From 0cfda2eeafe9a029a8556b2d8de6da8e5ec58c90 Mon Sep 17 00:00:00 2001 From: am11 <3840695+am11@users.noreply.github.com> Date: Wed, 4 Nov 2026 17:46:48 +0200 Subject: [PATCH 01/10] Port SPMI tools to C# (PublishAot) superpmi, mcs and the collector, counter and simple shims are now C#, published with NativeAOT under the same names, command lines, outputs and locations, so they are drop-in replacements; the native sources are deleted. - SuperPmi.Shared has the method context format and the recording, replay and dumping of the JIT-EE calls. superpmi and the shims reuse crossgen2's JIT interface (CorInfoImpl_generated.cs and its native JitInterfaceWrapper). - The shims call the EE through native forwarders generated by the ThunkGenerator, which capture the EE's exceptions and rethrow them at the boundaries. The native glue is linked in statically. - The output matches native on Linux and Windows x64: replay, mcs, collections and call counts. The win-x86 and linux-arm64 cross builds were checked too. Co-authored-by: Cursor --- .github/skills/add-new-jit-ee-api/SKILL.md | 177 +- docs/project/updating-jitinterface.md | 7 +- eng/Subsets.props | 5 + .../CommandLineHelpers.TargetArchitecture.cs | 50 + .../tools/Common/CommandLineHelpers.cs | 37 - .../JitInterface/CorInfoInstructionSet.cs | 2102 ----- .../CorInfoInstructionSetParser.cs | 2115 +++++ .../tools/Common/JitInterface/CorInfoTypes.cs | 8 +- .../ThunkGenerator/InstructionSetGenerator.cs | 43 +- .../JitInterface/ThunkGenerator/Program.cs | 185 +- .../JitInterface/ThunkGenerator/gen.bat | 4 +- .../Common/JitInterface/ThunkGenerator/gen.sh | 4 +- src/coreclr/tools/ILVerify/ILVerify.csproj | 1 + .../ILCompiler.Compiler.csproj | 3 + .../ILCompiler.ReadyToRun.csproj | 3 + .../ILCompiler.TypeSystem.Tests.csproj | 1 + .../tools/aot/ILCompiler/ILCompiler.props | 1 + .../tools/aot/crossgen2/crossgen2.props | 1 + .../tools/dotnet-pgo/dotnet-pgo.csproj | 1 + src/coreclr/tools/r2rdump/R2RDump.csproj | 1 + src/coreclr/tools/r2rtest/R2RTest.csproj | 1 + src/coreclr/tools/superpmi/CMakeLists.txt | 10 +- src/coreclr/tools/superpmi/config.h.in | 9 - src/coreclr/tools/superpmi/configure.cmake | 7 - .../superpmi/jitinterface/CMakeLists.txt | 57 + .../icorjitinfo_forwarders_generated.h | 1362 +++ .../superpmi/jitinterface/jitinterface.cpp | 223 + .../tools/superpmi/jitinterface/shim.cpp | 373 + .../superpmi/jitinterface/threadtime.cpp | 28 + .../superpmi/managed/Directory.Build.props | 15 + .../superpmi/managed/Directory.Build.targets | 14 + .../managed/SuperPmi.Shared/Agnostic.cs | 986 ++ .../managed/SuperPmi.Shared/ByteBuilder.cs | 45 + .../managed/SuperPmi.Shared/CFormat.cs | 306 + .../managed/SuperPmi.Shared/CallUtils.cs | 129 + .../SuperPmi.Shared/CompileResult.Dump.cs | 168 + .../SuperPmi.Shared/CompileResult.Maps.cs | 87 + .../SuperPmi.Shared/CompileResult.Replay.cs | 793 ++ .../managed/SuperPmi.Shared/CompileResult.cs | 33 + .../managed/SuperPmi.Shared/ErrorHandling.cs | 69 + .../superpmi/managed/SuperPmi.Shared/Hash.cs | 84 + .../managed/SuperPmi.Shared/JitEEVersion.cs | 30 + .../managed/SuperPmi.Shared/JitFlagNames.cs | 29 + .../managed/SuperPmi.Shared/JitMetrics.cs | 108 + .../managed/SuperPmi.Shared/LightWeightMap.cs | 539 ++ .../managed/SuperPmi.Shared/Logger.cs | 207 + .../managed/SuperPmi.Shared/MCList.cs | 191 + .../SuperPmi.Shared/MethodContext.Dump.cs | 1004 +++ .../SuperPmi.Shared/MethodContext.Identity.cs | 171 + .../SuperPmi.Shared/MethodContext.Maps.cs | 507 ++ .../SuperPmi.Shared/MethodContext.Record.cs | 2441 +++++ .../SuperPmi.Shared/MethodContext.Replay.cs | 1780 ++++ .../managed/SuperPmi.Shared/MethodContext.cs | 225 + .../SuperPmi.Shared/MethodContextIterator.cs | 117 + .../SuperPmi.Shared/MethodContextReader.cs | 376 + .../managed/SuperPmi.Shared/PacketId.cs | 200 + .../managed/SuperPmi.Shared/PinnedArena.cs | 47 + .../managed/SuperPmi.Shared/SpmiDumpHelper.cs | 357 + .../SuperPmi.Shared/SpmiRecordsHelper.cs | 373 + .../managed/SuperPmi.Shared/SpmiUtil.cs | 196 + .../SuperPmi.Shared/SuperPmi.Shared.csproj | 16 + .../managed/SuperPmi.Shared/TocFile.cs | 121 + .../tools/superpmi/managed/mcs/ILDumper.cs | 361 + .../superpmi/managed/mcs/McsRootCommand.cs | 257 + .../tools/superpmi/managed/mcs/Program.cs | 15 + .../tools/superpmi/managed/mcs/VerbDump.cs | 75 + .../tools/superpmi/managed/mcs/VerbDumpMap.cs | 224 + .../tools/superpmi/managed/mcs/VerbILDump.cs | 60 + .../tools/superpmi/managed/mcs/VerbMerge.cs | 288 + .../tools/superpmi/managed/mcs/Verbs.cs | 382 + .../tools/superpmi/managed/mcs/mcs.csproj | 19 + .../shim/CorInfoImpl_forwarding_generated.cs | 1114 +++ .../managed/shim/ForwardingCorInfoImpl.cs | 32 + .../superpmi/managed/shim/ForwardingShim.cs | 146 + .../managed/shim/OriginalJitInfo_generated.cs | 2015 +++++ .../tools/superpmi/managed/shim/Shim.props | 27 + .../superpmi/managed/shim/ShimEnvironment.cs | 119 + .../superpmi/managed/shim/ShimInterop.cs | 131 + .../superpmi-shim-collector/Collector.cs | 362 + .../CorInfoImpl.Collector.cs | 1635 ++++ .../superpmi-shim-collector.csproj | 7 + .../CorInfoImpl.Counter.cs | 11 + .../managed/superpmi-shim-counter/Counter.cs | 68 + .../superpmi-shim-counter.csproj | 13 + .../managed/superpmi-shim-simple/Simple.cs | 18 + .../superpmi-shim-simple.csproj | 13 + .../superpmi/managed/superpmi-tools.proj | 14 + .../superpmi/managed/superpmi/CommandLine.cs | 650 ++ .../managed/superpmi/CorInfoImpl.SuperPmi.cs | 1323 +++ .../superpmi/managed/superpmi/JitInstance.cs | 539 ++ .../superpmi/managed/superpmi/NearDiffer.cs | 609 ++ .../tools/superpmi/managed/superpmi/Output.cs | 111 + .../managed/superpmi/ParallelReplay.cs | 420 + .../superpmi/managed/superpmi/Program.cs | 44 + .../tools/superpmi/managed/superpmi/Replay.cs | 451 + .../managed/superpmi/SpmiJitInterface.cs | 77 + .../managed/superpmi/StreamingReplay.cs | 188 + .../superpmi/managed/superpmi/superpmi.csproj | 35 + src/coreclr/tools/superpmi/mcs/CMakeLists.txt | 74 - .../tools/superpmi/mcs/commandline.cpp | 642 -- src/coreclr/tools/superpmi/mcs/commandline.h | 79 - src/coreclr/tools/superpmi/mcs/mcs.cpp | 111 - src/coreclr/tools/superpmi/mcs/mcs.h | 7 - src/coreclr/tools/superpmi/mcs/removedup.cpp | 169 - src/coreclr/tools/superpmi/mcs/removedup.h | 61 - .../tools/superpmi/mcs/verbasmdump.cpp | 67 - src/coreclr/tools/superpmi/mcs/verbasmdump.h | 15 - src/coreclr/tools/superpmi/mcs/verbconcat.cpp | 102 - src/coreclr/tools/superpmi/mcs/verbconcat.h | 15 - src/coreclr/tools/superpmi/mcs/verbdump.cpp | 34 - src/coreclr/tools/superpmi/mcs/verbdump.h | 15 - .../tools/superpmi/mcs/verbdumpmap.cpp | 160 - src/coreclr/tools/superpmi/mcs/verbdumpmap.h | 15 - .../tools/superpmi/mcs/verbdumptoc.cpp | 30 - src/coreclr/tools/superpmi/mcs/verbdumptoc.h | 15 - .../tools/superpmi/mcs/verbfracture.cpp | 75 - src/coreclr/tools/superpmi/mcs/verbfracture.h | 16 - src/coreclr/tools/superpmi/mcs/verbildump.cpp | 995 --- src/coreclr/tools/superpmi/mcs/verbildump.h | 22 - src/coreclr/tools/superpmi/mcs/verbinteg.cpp | 35 - src/coreclr/tools/superpmi/mcs/verbinteg.h | 15 - .../tools/superpmi/mcs/verbjitflags.cpp | 130 - src/coreclr/tools/superpmi/mcs/verbjitflags.h | 16 - src/coreclr/tools/superpmi/mcs/verbmerge.cpp | 740 -- src/coreclr/tools/superpmi/mcs/verbmerge.h | 99 - .../superpmi/mcs/verbprintjiteeversion.cpp | 32 - .../superpmi/mcs/verbprintjiteeversion.h | 16 - .../tools/superpmi/mcs/verbremovedup.cpp | 35 - .../tools/superpmi/mcs/verbremovedup.h | 15 - src/coreclr/tools/superpmi/mcs/verbstat.cpp | 73 - src/coreclr/tools/superpmi/mcs/verbstat.h | 15 - src/coreclr/tools/superpmi/mcs/verbstrip.cpp | 148 - src/coreclr/tools/superpmi/mcs/verbstrip.h | 22 - src/coreclr/tools/superpmi/mcs/verbtoc.cpp | 107 - src/coreclr/tools/superpmi/mcs/verbtoc.h | 15 - src/coreclr/tools/superpmi/readme.md | 19 +- .../tools/superpmi/superpmi-shared/agnostic.h | 897 -- .../superpmi/superpmi-shared/asmdumper.cpp | 109 - .../superpmi/superpmi-shared/asmdumper.h | 17 - .../superpmi/superpmi-shared/callutils.cpp | 348 - .../superpmi/superpmi-shared/callutils.h | 35 - .../superpmi-shared/compileresult.cpp | 1358 --- .../superpmi/superpmi-shared/compileresult.h | 244 - .../superpmi/superpmi-shared/crlwmlist.h | 43 - .../superpmi-shared/errorhandling.cpp | 248 - .../superpmi/superpmi-shared/errorhandling.h | 178 - .../tools/superpmi/superpmi-shared/hash.cpp | 161 - .../tools/superpmi/superpmi-shared/hash.h | 22 - .../superpmi-shared/icorjitcompilerimpl.h | 51 - .../superpmi-shared/icorjithostimpl.h | 43 - .../superpmi-shared/icorjitinfoimpl.h | 10 - .../superpmi-shared/jitmetadatalist.h | 1 - .../superpmi/superpmi-shared/lightweightmap.h | 759 -- .../superpmi/superpmi-shared/logging.cpp | 357 - .../tools/superpmi/superpmi-shared/logging.h | 123 - .../tools/superpmi/superpmi-shared/lwmlist.h | 183 - .../tools/superpmi/superpmi-shared/mclist.cpp | 257 - .../tools/superpmi/superpmi-shared/mclist.h | 33 - .../superpmi-shared/methodcontext.cpp | 7916 ----------------- .../superpmi/superpmi-shared/methodcontext.h | 1257 --- .../superpmi-shared/methodcontextiterator.cpp | 126 - .../superpmi-shared/methodcontextiterator.h | 103 - .../superpmi-shared/methodcontextreader.cpp | 648 -- .../superpmi-shared/methodcontextreader.h | 159 - .../superpmi/superpmi-shared/runtimedetails.h | 19 - .../superpmi/superpmi-shared/simpletimer.cpp | 39 - .../superpmi/superpmi-shared/simpletimer.h | 25 - .../superpmi-shared/spmidumphelper.cpp | 285 - .../superpmi/superpmi-shared/spmidumphelper.h | 175 - .../superpmi-shared/spmirecordhelper.h | 579 -- .../superpmi/superpmi-shared/spmiutil.cpp | 595 -- .../tools/superpmi/superpmi-shared/spmiutil.h | 125 - .../superpmi/superpmi-shared/standardpch.h | 125 - .../superpmi/superpmi-shared/tocfile.cpp | 76 - .../tools/superpmi/superpmi-shared/tocfile.h | 69 - .../superpmi/superpmi-shared/typeutils.cpp | 161 - .../superpmi/superpmi-shared/typeutils.h | 23 - .../superpmi-shim-collector/CMakeLists.txt | 88 - .../icorjitcompiler.cpp | 160 - .../superpmi-shim-collector/icorjitcompiler.h | 25 - .../superpmi-shim-collector/icorjitinfo.cpp | 2091 ----- .../superpmi-shim-collector/icorjitinfo.h | 35 - .../superpmi-shim-collector/jithost.cpp | 159 - .../superpmi-shim-collector/jithost.h | 21 - .../superpmi-shim-collector.PAL.exports | 2 - .../superpmi-shim-collector.cpp | 226 - .../superpmi-shim-collector.def | 4 - .../superpmi-shim-collector.h | 16 - .../superpmi-shim-counter/CMakeLists.txt | 69 - .../superpmi-shim-counter/icorjitcompiler.cpp | 42 - .../superpmi-shim-counter/icorjitcompiler.h | 21 - .../superpmi-shim-counter/icorjitinfo.h | 22 - .../icorjitinfo_generated.cpp | 1502 ---- .../superpmi-shim-counter/jithost.cpp | 47 - .../superpmi/superpmi-shim-counter/jithost.h | 23 - .../methodcallsummarizer.cpp | 44 - .../methodcallsummarizer.h | 24 - .../superpmi-shim-counter.cpp | 178 - .../superpmi-shim-counter.def | 4 - .../superpmi-shim-counter.h | 10 - .../superpmi-shim-simple/CMakeLists.txt | 68 - .../superpmi-shim-simple/icorjitcompiler.cpp | 37 - .../superpmi-shim-simple/icorjitcompiler.h | 19 - .../superpmi-shim-simple/icorjitinfo.h | 20 - .../icorjitinfo_generated.cpp | 1319 --- .../superpmi/superpmi-shim-simple/jithost.cpp | 38 - .../superpmi/superpmi-shim-simple/jithost.h | 20 - .../superpmi-shim-simple.cpp | 152 - .../superpmi-shim-simple.def | 4 - .../superpmi-shim-simple.h | 10 - .../tools/superpmi/superpmi/CMakeLists.txt | 80 - .../tools/superpmi/superpmi/commandline.cpp | 952 -- .../tools/superpmi/superpmi/commandline.h | 67 - .../tools/superpmi/superpmi/cycletimer.cpp | 58 - .../tools/superpmi/superpmi/cycletimer.h | 26 - .../tools/superpmi/superpmi/fileio.cpp | 206 - src/coreclr/tools/superpmi/superpmi/fileio.h | 165 - .../tools/superpmi/superpmi/icorjitinfo.cpp | 1915 ---- .../tools/superpmi/superpmi/icorjitinfo.h | 28 - .../tools/superpmi/superpmi/jitdebugger.cpp | 441 - .../tools/superpmi/superpmi/jitdebugger.h | 32 - .../tools/superpmi/superpmi/jithost.cpp | 242 - src/coreclr/tools/superpmi/superpmi/jithost.h | 20 - .../tools/superpmi/superpmi/jitinstance.cpp | 596 -- .../tools/superpmi/superpmi/jitinstance.h | 91 - .../superpmi/superpmi/methodstatsemitter.cpp | 127 - .../superpmi/superpmi/methodstatsemitter.h | 28 - .../tools/superpmi/superpmi/neardiffer.cpp | 1508 ---- .../tools/superpmi/superpmi/neardiffer.h | 97 - .../superpmi/superpmi/parallelsuperpmi.cpp | 1137 --- .../superpmi/superpmi/streamingsuperpmi.cpp | 317 - .../tools/superpmi/superpmi/superpmi.cpp | 844 -- .../tools/superpmi/superpmi/superpmi.h | 27 - src/tests/Common/CoreRootArtifacts.targets | 1 - 234 files changed, 28140 insertions(+), 40034 deletions(-) create mode 100644 src/coreclr/tools/Common/CommandLineHelpers.TargetArchitecture.cs create mode 100644 src/coreclr/tools/Common/JitInterface/CorInfoInstructionSetParser.cs delete mode 100644 src/coreclr/tools/superpmi/config.h.in delete mode 100644 src/coreclr/tools/superpmi/configure.cmake create mode 100644 src/coreclr/tools/superpmi/jitinterface/CMakeLists.txt create mode 100644 src/coreclr/tools/superpmi/jitinterface/icorjitinfo_forwarders_generated.h create mode 100644 src/coreclr/tools/superpmi/jitinterface/jitinterface.cpp create mode 100644 src/coreclr/tools/superpmi/jitinterface/shim.cpp create mode 100644 src/coreclr/tools/superpmi/jitinterface/threadtime.cpp create mode 100644 src/coreclr/tools/superpmi/managed/Directory.Build.props create mode 100644 src/coreclr/tools/superpmi/managed/Directory.Build.targets create mode 100644 src/coreclr/tools/superpmi/managed/SuperPmi.Shared/Agnostic.cs create mode 100644 src/coreclr/tools/superpmi/managed/SuperPmi.Shared/ByteBuilder.cs create mode 100644 src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CFormat.cs create mode 100644 src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CallUtils.cs create mode 100644 src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CompileResult.Dump.cs create mode 100644 src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CompileResult.Maps.cs create mode 100644 src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CompileResult.Replay.cs create mode 100644 src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CompileResult.cs create mode 100644 src/coreclr/tools/superpmi/managed/SuperPmi.Shared/ErrorHandling.cs create mode 100644 src/coreclr/tools/superpmi/managed/SuperPmi.Shared/Hash.cs create mode 100644 src/coreclr/tools/superpmi/managed/SuperPmi.Shared/JitEEVersion.cs create mode 100644 src/coreclr/tools/superpmi/managed/SuperPmi.Shared/JitFlagNames.cs create mode 100644 src/coreclr/tools/superpmi/managed/SuperPmi.Shared/JitMetrics.cs create mode 100644 src/coreclr/tools/superpmi/managed/SuperPmi.Shared/LightWeightMap.cs create mode 100644 src/coreclr/tools/superpmi/managed/SuperPmi.Shared/Logger.cs create mode 100644 src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MCList.cs create mode 100644 src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Dump.cs create mode 100644 src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Identity.cs create mode 100644 src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Maps.cs create mode 100644 src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Record.cs create mode 100644 src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Replay.cs create mode 100644 src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.cs create mode 100644 src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContextIterator.cs create mode 100644 src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContextReader.cs create mode 100644 src/coreclr/tools/superpmi/managed/SuperPmi.Shared/PacketId.cs create mode 100644 src/coreclr/tools/superpmi/managed/SuperPmi.Shared/PinnedArena.cs create mode 100644 src/coreclr/tools/superpmi/managed/SuperPmi.Shared/SpmiDumpHelper.cs create mode 100644 src/coreclr/tools/superpmi/managed/SuperPmi.Shared/SpmiRecordsHelper.cs create mode 100644 src/coreclr/tools/superpmi/managed/SuperPmi.Shared/SpmiUtil.cs create mode 100644 src/coreclr/tools/superpmi/managed/SuperPmi.Shared/SuperPmi.Shared.csproj create mode 100644 src/coreclr/tools/superpmi/managed/SuperPmi.Shared/TocFile.cs create mode 100644 src/coreclr/tools/superpmi/managed/mcs/ILDumper.cs create mode 100644 src/coreclr/tools/superpmi/managed/mcs/McsRootCommand.cs create mode 100644 src/coreclr/tools/superpmi/managed/mcs/Program.cs create mode 100644 src/coreclr/tools/superpmi/managed/mcs/VerbDump.cs create mode 100644 src/coreclr/tools/superpmi/managed/mcs/VerbDumpMap.cs create mode 100644 src/coreclr/tools/superpmi/managed/mcs/VerbILDump.cs create mode 100644 src/coreclr/tools/superpmi/managed/mcs/VerbMerge.cs create mode 100644 src/coreclr/tools/superpmi/managed/mcs/Verbs.cs create mode 100644 src/coreclr/tools/superpmi/managed/mcs/mcs.csproj create mode 100644 src/coreclr/tools/superpmi/managed/shim/CorInfoImpl_forwarding_generated.cs create mode 100644 src/coreclr/tools/superpmi/managed/shim/ForwardingCorInfoImpl.cs create mode 100644 src/coreclr/tools/superpmi/managed/shim/ForwardingShim.cs create mode 100644 src/coreclr/tools/superpmi/managed/shim/OriginalJitInfo_generated.cs create mode 100644 src/coreclr/tools/superpmi/managed/shim/Shim.props create mode 100644 src/coreclr/tools/superpmi/managed/shim/ShimEnvironment.cs create mode 100644 src/coreclr/tools/superpmi/managed/shim/ShimInterop.cs create mode 100644 src/coreclr/tools/superpmi/managed/superpmi-shim-collector/Collector.cs create mode 100644 src/coreclr/tools/superpmi/managed/superpmi-shim-collector/CorInfoImpl.Collector.cs create mode 100644 src/coreclr/tools/superpmi/managed/superpmi-shim-collector/superpmi-shim-collector.csproj create mode 100644 src/coreclr/tools/superpmi/managed/superpmi-shim-counter/CorInfoImpl.Counter.cs create mode 100644 src/coreclr/tools/superpmi/managed/superpmi-shim-counter/Counter.cs create mode 100644 src/coreclr/tools/superpmi/managed/superpmi-shim-counter/superpmi-shim-counter.csproj create mode 100644 src/coreclr/tools/superpmi/managed/superpmi-shim-simple/Simple.cs create mode 100644 src/coreclr/tools/superpmi/managed/superpmi-shim-simple/superpmi-shim-simple.csproj create mode 100644 src/coreclr/tools/superpmi/managed/superpmi-tools.proj create mode 100644 src/coreclr/tools/superpmi/managed/superpmi/CommandLine.cs create mode 100644 src/coreclr/tools/superpmi/managed/superpmi/CorInfoImpl.SuperPmi.cs create mode 100644 src/coreclr/tools/superpmi/managed/superpmi/JitInstance.cs create mode 100644 src/coreclr/tools/superpmi/managed/superpmi/NearDiffer.cs create mode 100644 src/coreclr/tools/superpmi/managed/superpmi/Output.cs create mode 100644 src/coreclr/tools/superpmi/managed/superpmi/ParallelReplay.cs create mode 100644 src/coreclr/tools/superpmi/managed/superpmi/Program.cs create mode 100644 src/coreclr/tools/superpmi/managed/superpmi/Replay.cs create mode 100644 src/coreclr/tools/superpmi/managed/superpmi/SpmiJitInterface.cs create mode 100644 src/coreclr/tools/superpmi/managed/superpmi/StreamingReplay.cs create mode 100644 src/coreclr/tools/superpmi/managed/superpmi/superpmi.csproj delete mode 100644 src/coreclr/tools/superpmi/mcs/CMakeLists.txt delete mode 100644 src/coreclr/tools/superpmi/mcs/commandline.cpp delete mode 100644 src/coreclr/tools/superpmi/mcs/commandline.h delete mode 100644 src/coreclr/tools/superpmi/mcs/mcs.cpp delete mode 100644 src/coreclr/tools/superpmi/mcs/mcs.h delete mode 100644 src/coreclr/tools/superpmi/mcs/removedup.cpp delete mode 100644 src/coreclr/tools/superpmi/mcs/removedup.h delete mode 100644 src/coreclr/tools/superpmi/mcs/verbasmdump.cpp delete mode 100644 src/coreclr/tools/superpmi/mcs/verbasmdump.h delete mode 100644 src/coreclr/tools/superpmi/mcs/verbconcat.cpp delete mode 100644 src/coreclr/tools/superpmi/mcs/verbconcat.h delete mode 100644 src/coreclr/tools/superpmi/mcs/verbdump.cpp delete mode 100644 src/coreclr/tools/superpmi/mcs/verbdump.h delete mode 100644 src/coreclr/tools/superpmi/mcs/verbdumpmap.cpp delete mode 100644 src/coreclr/tools/superpmi/mcs/verbdumpmap.h delete mode 100644 src/coreclr/tools/superpmi/mcs/verbdumptoc.cpp delete mode 100644 src/coreclr/tools/superpmi/mcs/verbdumptoc.h delete mode 100644 src/coreclr/tools/superpmi/mcs/verbfracture.cpp delete mode 100644 src/coreclr/tools/superpmi/mcs/verbfracture.h delete mode 100644 src/coreclr/tools/superpmi/mcs/verbildump.cpp delete mode 100644 src/coreclr/tools/superpmi/mcs/verbildump.h delete mode 100644 src/coreclr/tools/superpmi/mcs/verbinteg.cpp delete mode 100644 src/coreclr/tools/superpmi/mcs/verbinteg.h delete mode 100644 src/coreclr/tools/superpmi/mcs/verbjitflags.cpp delete mode 100644 src/coreclr/tools/superpmi/mcs/verbjitflags.h delete mode 100644 src/coreclr/tools/superpmi/mcs/verbmerge.cpp delete mode 100644 src/coreclr/tools/superpmi/mcs/verbmerge.h delete mode 100644 src/coreclr/tools/superpmi/mcs/verbprintjiteeversion.cpp delete mode 100644 src/coreclr/tools/superpmi/mcs/verbprintjiteeversion.h delete mode 100644 src/coreclr/tools/superpmi/mcs/verbremovedup.cpp delete mode 100644 src/coreclr/tools/superpmi/mcs/verbremovedup.h delete mode 100644 src/coreclr/tools/superpmi/mcs/verbstat.cpp delete mode 100644 src/coreclr/tools/superpmi/mcs/verbstat.h delete mode 100644 src/coreclr/tools/superpmi/mcs/verbstrip.cpp delete mode 100644 src/coreclr/tools/superpmi/mcs/verbstrip.h delete mode 100644 src/coreclr/tools/superpmi/mcs/verbtoc.cpp delete mode 100644 src/coreclr/tools/superpmi/mcs/verbtoc.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/agnostic.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/asmdumper.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/asmdumper.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/callutils.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/callutils.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/compileresult.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/crlwmlist.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/errorhandling.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/errorhandling.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/hash.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/hash.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/icorjitcompilerimpl.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/icorjithostimpl.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/icorjitinfoimpl.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/jitmetadatalist.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/lightweightmap.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/logging.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/logging.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/mclist.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/mclist.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/methodcontextiterator.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/methodcontextiterator.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/methodcontextreader.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/methodcontextreader.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/runtimedetails.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/simpletimer.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/simpletimer.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/spmidumphelper.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/spmidumphelper.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/spmirecordhelper.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/spmiutil.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/spmiutil.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/standardpch.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/tocfile.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/tocfile.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/typeutils.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi-shared/typeutils.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shim-collector/CMakeLists.txt delete mode 100644 src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitcompiler.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitcompiler.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shim-collector/jithost.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi-shim-collector/jithost.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shim-collector/superpmi-shim-collector.PAL.exports delete mode 100644 src/coreclr/tools/superpmi/superpmi-shim-collector/superpmi-shim-collector.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi-shim-collector/superpmi-shim-collector.def delete mode 100644 src/coreclr/tools/superpmi/superpmi-shim-collector/superpmi-shim-collector.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shim-counter/CMakeLists.txt delete mode 100644 src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitcompiler.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitcompiler.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi-shim-counter/jithost.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi-shim-counter/jithost.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shim-counter/methodcallsummarizer.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi-shim-counter/methodcallsummarizer.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shim-counter/superpmi-shim-counter.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi-shim-counter/superpmi-shim-counter.def delete mode 100644 src/coreclr/tools/superpmi/superpmi-shim-counter/superpmi-shim-counter.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shim-simple/CMakeLists.txt delete mode 100644 src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitcompiler.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitcompiler.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi-shim-simple/jithost.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi-shim-simple/jithost.h delete mode 100644 src/coreclr/tools/superpmi/superpmi-shim-simple/superpmi-shim-simple.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi-shim-simple/superpmi-shim-simple.def delete mode 100644 src/coreclr/tools/superpmi/superpmi-shim-simple/superpmi-shim-simple.h delete mode 100644 src/coreclr/tools/superpmi/superpmi/CMakeLists.txt delete mode 100644 src/coreclr/tools/superpmi/superpmi/commandline.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi/commandline.h delete mode 100644 src/coreclr/tools/superpmi/superpmi/cycletimer.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi/cycletimer.h delete mode 100644 src/coreclr/tools/superpmi/superpmi/fileio.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi/fileio.h delete mode 100644 src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi/icorjitinfo.h delete mode 100644 src/coreclr/tools/superpmi/superpmi/jitdebugger.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi/jitdebugger.h delete mode 100644 src/coreclr/tools/superpmi/superpmi/jithost.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi/jithost.h delete mode 100644 src/coreclr/tools/superpmi/superpmi/jitinstance.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi/jitinstance.h delete mode 100644 src/coreclr/tools/superpmi/superpmi/methodstatsemitter.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi/methodstatsemitter.h delete mode 100644 src/coreclr/tools/superpmi/superpmi/neardiffer.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi/neardiffer.h delete mode 100644 src/coreclr/tools/superpmi/superpmi/parallelsuperpmi.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi/streamingsuperpmi.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi/superpmi.cpp delete mode 100644 src/coreclr/tools/superpmi/superpmi/superpmi.h diff --git a/.github/skills/add-new-jit-ee-api/SKILL.md b/.github/skills/add-new-jit-ee-api/SKILL.md index 54fa01995b19a6..ddb07e357fe9cf 100644 --- a/.github/skills/add-new-jit-ee-api/SKILL.md +++ b/.github/skills/add-new-jit-ee-api/SKILL.md @@ -86,129 +86,116 @@ Implement the API if asked, leave the UNREACHABLE() otherwise. 6. Now implement the most complex part - SuperPMI. SuperPMI acts as a (de)serializer for JIT-VM queries in order to then replay them without the actual VM to speed up jit-diffs and other scenarios. All parameters and return -values recorded/restored using special primitve types and helpers. We need to update the following files: +values recorded/restored using special primitve types and helpers. It is written in C#; we need to update the following +files in `/src/coreclr/tools/superpmi/managed/SuperPmi.Shared`: -* `/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h`: -* `/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h`: -* `/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h`: -* `/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp`: +* `Agnostic.cs` +* `PacketId.cs` +* `MethodContext.Maps.cs` +* `MethodContext.Record.cs` +* `MethodContext.Dump.cs` +* `MethodContext.Replay.cs` Go through each of them one by one. -* `/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h`: +* `Agnostic.cs`: Define two `Agnostic_*` types for input arguments and another one for output parameters (return value, output arguments). - Do not create them if one of the generics ones can be re-used such as `DLD`, `DD`, `DLDL`, etc. Use `DWORD*` - like types for integers. Inspect the whole file to see how other APIs are defined. + Do not create them if one of the generics ones can be re-used such as `DLD`, `DD`, `DLDL`, etc. Use `uint`/`ulong` + for integers and handles. Inspect the whole file to see how other APIs are defined. -* `/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h`: -Add a new entry to the `LWM` list. Example: +* `PacketId.cs`: +Add a new packet ID at the end of `enum PacketId`. Example: ```diff -+LWM(GetUnboxedEntry, DWORDLONG, DLD); ++ GetUnboxedEntry = , ``` -NOTE: Use upper-case for the first letter of the API name here. -Add the new record after the very last LWM one. - -* `/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h`: -Define 3 methods in this header file inside `class MethodContext` class (at the end of its definition). +* `MethodContext.Maps.cs`: +Add the new map at the end of `s_maps`, with the next index, and a property and a dump for it at the end of the other ones. Example: -The methods are prefixed with `rec*` (record), `dmp*` (dump to console) and `rep*` (replay). Example +```diff ++ new MapInfo(, "GetUnboxedEntry", PacketId.GetUnboxedEntry, static () => new LightWeightMap()), +``` ```diff -+ void recGetUnboxedEntry(CORINFO_METHOD_HANDLE ftn, bool* requiresInstMethodTableArg, CORINFO_METHOD_HANDLE result); -+ void dmpGetUnboxedEntry(DWORDLONG key, DLD value); -+ CORINFO_METHOD_HANDLE repGetUnboxedEntry(CORINFO_METHOD_HANDLE ftn, bool* requiresInstMethodTableArg); ++ public LightWeightMap GetUnboxedEntry { get => (LightWeightMap)_maps[]; set => _maps[] = value; } ``` -Now add a new element to `enum mcPackets` enum in the same file. Example: ```diff -+ Packet_GetUnboxedEntry = , ++ MapDumper.Dump(nameof(GetUnboxedEntry), GetUnboxedEntry, (k, v) => dmpGetUnboxedEntry(k, v)); ``` -* `/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp`: -Add the implementation of the 3 methods to `methodcontext.cpp` at the end of it. -Consider other similar methods in the file for reference. Do not change implementations of other methods in the file. Example: +NOTE: Use upper-case for the first letter of the API name here. + +* `MethodContext.Record.cs`, `MethodContext.Dump.cs` and `MethodContext.Replay.cs`: +Add 3 methods, prefixed with `rec*` (record), `dmp*` (dump to console) and `rep*` (replay), one to each file at its end. +Consider other similar methods in the files for reference. Do not change implementations of other methods. Example: ```diff -+void MethodContext::recGetUnboxedEntry(CORINFO_METHOD_HANDLE ftn, -+ bool* requiresInstMethodTableArg, -+ CORINFO_METHOD_HANDLE result) -+{ -+ // Initialize the "input - output" map if it is not already initialized -+ if (GetUnboxedEntry == nullptr) ++ public void recGetUnboxedEntry(CORINFO_METHOD_STRUCT_* ftn, bool* requiresInstMethodTableArg, CORINFO_METHOD_STRUCT_* result) + { -+ GetUnboxedEntry = new LightWeightMap(); -+ } ++ // Initialize the "input - output" map if it is not already initialized ++ GetUnboxedEntry ??= new(); + -+ // Create a key out of the input arguments -+ DWORDLONG key = CastHandle(ftn); -+ DLD value; -+ value.A = CastHandle(result); ++ // Create a key out of the input arguments ++ ulong key = CastHandle(ftn); + -+ // Create a value out of the return value and out parameters -+ if (requiresInstMethodTableArg != nullptr) -+ { -+ value.B = (DWORD)*requiresInstMethodTableArg ? 1 : 0; ++ // Create a value out of the return value and out parameters ++ DLD value = default; ++ value.A = CastHandle(result); ++ value.B = requiresInstMethodTableArg != null && *requiresInstMethodTableArg ? 1u : 0u; ++ ++ // Save it to the map ++ GetUnboxedEntry.Add(key, value); + } -+ else +``` + +```diff ++ public void dmpGetUnboxedEntry(ulong key, DLD value) ++ => CFormat.Printf(Out, "GetUnboxedEntry ftn-%016llX, result-%016llX, requires-inst-%u", key, value.A, value.B); +``` + +```diff ++ public CORINFO_METHOD_STRUCT_* repGetUnboxedEntry(CORINFO_METHOD_STRUCT_* ftn, bool* requiresInstMethodTableArg) + { -+ value.B = 0; -+ } -+ -+ // Save it to the map -+ GetUnboxedEntry->Add(key, value); -+ DEBUG_REC(dmpGetUnboxedEntry(key, value)); -+} -+void MethodContext::dmpGetUnboxedEntry(DWORDLONG key, DLD value) -+{ -+ // Dump key and value to the console for debug purposes. -+ printf("GetUnboxedEntry ftn-%016" PRIX64 ", result-%016" PRIX64 ", requires-inst-%u", key, value.A, value.B); -+} -+CORINFO_METHOD_HANDLE MethodContext::repGetUnboxedEntry(CORINFO_METHOD_HANDLE ftn, bool* requiresInstMethodTableArg) -+{ -+ // Create a key out of the input arguments -+ DWORDLONG key = CastHandle(ftn); ++ // Create a key out of the input arguments ++ ulong key = CastHandle(ftn); + -+ // Perform the lookup to obtain the value (output arguments and return value) -+ DLD value = LookupByKeyOrMiss(GetUnboxedEntry, key, ": key %016" PRIX64 "", key); -+ DEBUG_REP(dmpGetUnboxedEntry(key, value)); ++ // Perform the lookup to obtain the value (output arguments and return value) ++ DLD value = LookupByKeyOrMiss(GetUnboxedEntry, key, ": key %016llX", key); + -+ // propagate result to output arguments and return value (if exists) -+ if (requiresInstMethodTableArg != nullptr) -+ { -+ *requiresInstMethodTableArg = (value.B == 1); -+ } -+ return (CORINFO_METHOD_HANDLE)(value.A); -+} ++ // propagate result to output arguments and return value (if exists) ++ if (requiresInstMethodTableArg != null) ++ *requiresInstMethodTableArg = value.B == 1; ++ return (CORINFO_METHOD_STRUCT_*)value.A; ++ } ``` -7. Add a new function to `/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp` that calls the `rep*` method. Example: +7. Add a new method to `/src/coreclr/tools/superpmi/managed/superpmi/CorInfoImpl.SuperPmi.cs` that calls the `rep*` method. +It has the signature of the API in `CorInfoImpl_generated.cs`. Example: ```diff -+CORINFO_METHOD_HANDLE MyICJI::getUnboxedEntry(CORINFO_METHOD_HANDLE ftn, bool* requiresInstMethodTableArg) -+{ -+ jitInstance->mc->cr->AddCall("getUnboxedEntry"); -+ CORINFO_METHOD_HANDLE result = jitInstance->mc->repGetUnboxedEntry(ftn, requiresInstMethodTableArg); -+ return result; -+} ++ private CORINFO_METHOD_STRUCT_* getUnboxedEntry(CORINFO_METHOD_STRUCT_* ftn, ref bool requiresInstMethodTableArg) ++ { ++ AddCall("getUnboxedEntry"); ++ return mc.repGetUnboxedEntry(ftn, P(ref requiresInstMethodTableArg)); ++ } ``` -8. Add a new function to `/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp` that calls the `rec*` method. Example: +8. Add a new method to `/src/coreclr/tools/superpmi/managed/superpmi-shim-collector/CorInfoImpl.Collector.cs` that calls the +VM (`_original`) and the `rec*` method. Example: ```diff -+CORINFO_METHOD_HANDLE interceptor_ICJI::getUnboxedEntry(CORINFO_METHOD_HANDLE ftn, bool* requiresInstMethodTableArg) -+{ -+ mc->cr->AddCall("getUnboxedEntry"); -+ bool localRequiresInstMethodTableArg = false; -+ CORINFO_METHOD_HANDLE result = original_ICorJitInfo->getUnboxedEntry(ftn, &localRequiresInstMethodTableArg); -+ mc->recGetUnboxedEntry(ftn, &localRequiresInstMethodTableArg, result); -+ if (requiresInstMethodTableArg != nullptr) -+ { -+ *requiresInstMethodTableArg = localRequiresInstMethodTableArg; -+ } -+ return result; -+} ++ private CORINFO_METHOD_STRUCT_* getUnboxedEntry(CORINFO_METHOD_STRUCT_* ftn, ref bool requiresInstMethodTableArg) ++ { ++ AddCall("getUnboxedEntry"); ++ bool localRequiresInstMethodTableArg = false; ++ CORINFO_METHOD_STRUCT_* result = _original.getUnboxedEntry(ftn, ref localRequiresInstMethodTableArg); ++ mc.recGetUnboxedEntry(ftn, &localRequiresInstMethodTableArg, result); ++ if (!Unsafe.IsNullRef(ref requiresInstMethodTableArg)) ++ requiresInstMethodTableArg = localRequiresInstMethodTableArg; ++ return result; ++ } ``` #### 4 — Definition of Done (self-check list) @@ -219,10 +206,12 @@ Consider other similar methods in the file for reference. Do not change implemen * `/src/coreclr/inc/corinfo.h` * `/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs` * `/src/coreclr/vm/jitinterface.cpp` - * `/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h` [optional - only if new types are needed] - * `/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h` - * `/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h` - * `/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp` - * `/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp` - * `/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp` + * `/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/Agnostic.cs` [optional - only if new types are needed] + * `/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/PacketId.cs` + * `/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Maps.cs` + * `/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Record.cs` + * `/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Dump.cs` + * `/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Replay.cs` + * `/src/coreclr/tools/superpmi/managed/superpmi/CorInfoImpl.SuperPmi.cs` + * `/src/coreclr/tools/superpmi/managed/superpmi-shim-collector/CorInfoImpl.Collector.cs` * [ ] All TODO/UNREACHABLE markers remain for future functional implementation. diff --git a/docs/project/updating-jitinterface.md b/docs/project/updating-jitinterface.md index 571edab9a0ab07..e10d55b98d020f 100644 --- a/docs/project/updating-jitinterface.md +++ b/docs/project/updating-jitinterface.md @@ -19,10 +19,9 @@ It's a good idea to choose an existing API that is similar to the one you want t 3) Open `src/coreclr/inc/corinfo.h` and add the new API in `ICorStaticInfo` 4) Open `src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs` and add the new API in `CorInfoImpl` class. If the implementation is not shared for NativeAOT and R2R, use `CorInfoImpl.RyuJit.cs` and `CorInfoImpl.ReadyToRun.cs` to implement the API. 5) Open `src/coreclr/vm/jitinterface.cpp` and add the CoreCLR-specific implementation -6) Open `lwmlist.h` and add a definition of "input-args" - "output-args" map. Either use the generic `DLD`-like structs or create new ones in `agnostic.h` -7) Open `src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h` and add the necessary recording, dumping, and replaying methods for the new API and then implement them in `methodcontext.cpp` -8) Update `enum mcPackets` in `src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h` to include an entry for the new API and bump the max value of the enum -9) Use the `rec*` and `rep*` methods in `src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp` and `src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp` accordingly +6) Open `src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Maps.cs` and add a map of "input-args" to "output-args" for the new API (its entry in `s_maps`, its property, and its dump), with a new packet ID in `PacketId.cs`. Either use the generic `DLD`-like records or create new ones in `Agnostic.cs` +7) Add the recording, dumping, and replaying methods for the new API to `MethodContext.Record.cs`, `MethodContext.Dump.cs`, and `MethodContext.Replay.cs` in the same directory +8) Use the `rec*` and `rep*` methods in `src/coreclr/tools/superpmi/managed/superpmi-shim-collector/CorInfoImpl.Collector.cs` and `src/coreclr/tools/superpmi/managed/superpmi/CorInfoImpl.SuperPmi.cs` accordingly ## Adding a new JIT-VM API through an agent diff --git a/eng/Subsets.props b/eng/Subsets.props index e61c5d40cf7a4a..097407e7fa6db7 100644 --- a/eng/Subsets.props +++ b/eng/Subsets.props @@ -383,6 +383,11 @@ Category="clr" /> + + + + + + true + + false + + diff --git a/src/coreclr/tools/superpmi/managed/Directory.Build.targets b/src/coreclr/tools/superpmi/managed/Directory.Build.targets new file mode 100644 index 00000000000000..78778798a937f9 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/Directory.Build.targets @@ -0,0 +1,14 @@ + + + + + + + + PDB\%(Filename)%(Extension) + + + + diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/Agnostic.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/Agnostic.cs new file mode 100644 index 00000000000000..fbe80a4ff45803 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/Agnostic.cs @@ -0,0 +1,986 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// The records that the method contexts store for the JIT-EE interface calls: platform agnostic, in the layout of +// the .mc format. + +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SuperPmi; + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_CORINFO_SIG_INFO +{ + public uint callConv; + public ulong retTypeClass; + public ulong retTypeSigClass; + public uint retType; + public uint flags; + public uint numArgs; + public uint sigInst_classInstCount; + public uint sigInst_classInst_Index; + public uint sigInst_methInstCount; + public uint sigInst_methInst_Index; + public ulong args; + public uint pSig_Index; + public uint cbSig; + public ulong methodSignature; + public ulong scope; + public uint token; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_CORINFO_CONST_LOOKUP +{ + public uint accessType; + public ulong handle; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_CORINFO_LOOKUP_KIND +{ + public uint needsRuntimeLookup; + public uint runtimeLookupKind; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_CORINFO_RUNTIME_LOOKUP +{ + public ulong signature; + public uint helper; + public uint indirections; + public uint testForNull; + public ushort sizeOffset; + public UlongArray4 offsets; + public uint indirectFirstOffset; + public uint indirectSecondOffset; + public Agnostic_CORINFO_CONST_LOOKUP helperEntryPoint; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_CORINFO_LOOKUP +{ + public Agnostic_CORINFO_LOOKUP_KIND lookupKind; + public Agnostic_CORINFO_RUNTIME_LOOKUP runtimeLookup; + public Agnostic_CORINFO_CONST_LOOKUP constLookup; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_CORINFO_METHOD_INFO +{ + public ulong ftn; + public ulong scope; + public uint ILCode_offset; + public uint ILCodeSize; + public uint maxStack; + public uint EHcount; + public uint options; + public uint regionKind; + public Agnostic_CORINFO_SIG_INFO args; + public Agnostic_CORINFO_SIG_INFO locals; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_CompileMethod +{ + public Agnostic_CORINFO_METHOD_INFO info; + public uint flags; + public uint os; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_InitClass +{ + public ulong field; + public ulong method; + public ulong context; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct DLDL +{ + public ulong A; + public ulong B; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_CanInline +{ + public uint result; + public uint exceptionCode; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_GetClassGClayout +{ + public uint gcPtrs_Index; + public uint len; + public uint valCount; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct DLD +{ + public ulong A; + public uint B; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct DLDD +{ + public ulong A; + public uint B; + public uint C; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct DLDDD +{ + public ulong A; + public uint B; + public uint C; + public uint D; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_CORINFO_METHODNAME_TOKENin +{ + public ulong ftn; + public uint className; + public uint namespaceName; + public uint maxEnclosingClassNames; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_CORINFO_METHODNAME_TOKENout +{ + public uint methodName; + public uint className; + public uint namespaceName; + public uint enclosingClassNames; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_CORINFO_RESOLVED_TOKENin +{ + public ulong tokenContext; + public ulong tokenScope; + public uint token; + public uint tokenType; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_CORINFO_RESOLVED_TOKENout +{ + public ulong hClass; + public ulong hMethod; + public ulong hField; + public uint pTypeSpec_Index; + public uint cbTypeSpec; + public uint pMethodSpec_Index; + public uint cbMethodSpec; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_GetArgType_Key +{ + public uint flags; + public uint numArgs; + public uint sigInst_classInstCount; + public uint sigInst_classInst_Index; + public uint sigInst_methInstCount; + public uint sigInst_methInst_Index; + public ulong methodSignature; + public ulong scope; + public ulong args; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_GetArgClass_Key +{ + public uint sigInst_classInstCount; + public uint sigInst_classInst_Index; + public uint sigInst_methInstCount; + public uint sigInst_methInst_Index; + public ulong methodSignature; + public ulong scope; + public ulong args; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_GetBoundaries +{ + public uint cILOffsets; + public uint pILOffset_offset; + public uint implicitBoundaries; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_InlinedCallFrameInfo +{ + public uint size; + public uint sizeWithSecretStubArg; + public uint offsetOfFrameLink; + public uint offsetOfCallSiteSP; + public uint offsetOfCalleeSavedFP; + public uint offsetOfCallTarget; + public uint offsetOfReturnAddress; + public uint offsetOfSecretStubArg; + public uint offsetOfSPAfterProlog; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_CORINFO_EE_INFO +{ + public Agnostic_InlinedCallFrameInfo inlinedCallFrameInfo; + public uint offsetOfThreadFrame; + public uint offsetOfGCState; + public uint offsetOfDelegateInstance; + public uint offsetOfDelegateFirstTarget; + public uint sizeOfReversePInvokeFrame; + public uint osPageSize; + public uint maxUncheckedOffsetForNullObject; + public uint targetAbi; + public uint osType; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_CORINFO_ASYNC_INFO +{ + public ulong continuationClsHnd; + public ulong continuationNextFldHnd; + public ulong continuationResumeInfoFldHnd; + public ulong continuationStateFldHnd; + public ulong continuationFlagsFldHnd; + public ulong captureExecutionContextMethHnd; + public ulong captureContinuationContextMethHnd; + public ulong captureContextsMethHnd; + public ulong restoreContextsMethHnd; + public ulong restoreContextsOnSuspensionMethHnd; + public ulong restoreInlinedFrameContextsMethHnd; + public ulong captureInlinedFrameTransitionWithContinuationContextMethHnd; + public ulong captureInlinedFrameTransitionNoContinuationContextMethHnd; + public ulong captureInlinedFrameTransitionContinueOnThreadPoolMethHnd; + public ulong finishSuspensionNoContinuationContextMethHnd; + public ulong finishSuspensionWithContinuationContextMethHnd; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_CORINFO_WASM_WELLKNOWN_GLOBALS +{ + public ulong stackPointer; + public ulong imageBase; + public ulong tableBase; + public ulong asyncContinuation; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_GetAwaitReturnCallResult +{ + public ulong methodHnd; + public ulong contextHandle; + public Agnostic_CORINFO_LOOKUP instArg; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_GetOSRInfo +{ + public uint index; + public uint ilOffset; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_GetStaticFieldCurrentClass +{ + public ulong classHandle; + public byte isSpeculative; // bool +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_CORINFO_TYPE_LAYOUT_NODE +{ + public ulong simdTypeHnd; + public ulong diagFieldHnd; + public uint parent; + public uint offset; + public uint size; + public uint numFields; + public byte type; + public byte hasSignificantPadding; // bool +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_GetTypeLayoutResult +{ + public uint result; + public uint nodesBuffer; + public uint numNodes; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_CORINFO_RESOLVED_TOKEN +{ + public Agnostic_CORINFO_RESOLVED_TOKENin inValue; + public Agnostic_CORINFO_RESOLVED_TOKENout outValue; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_GetAwaitAwaiterInContinuationCall +{ + public ulong callerHnd; + public Agnostic_CORINFO_RESOLVED_TOKEN ResolvedToken; + public uint isUnsafe; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_GetFieldInfo +{ + public Agnostic_CORINFO_RESOLVED_TOKEN ResolvedToken; + public ulong callerHandle; + public uint flags; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_CORINFO_HELPER_ARG +{ + public ulong constant; + public uint argType; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_CORINFO_HELPER_DESC +{ + public uint helperNum; + public uint numArgs; + public Agnostic_CORINFO_HELPER_ARGArray4 args; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_GetHelperFtn +{ + public Agnostic_CORINFO_CONST_LOOKUP helperLookup; + public ulong helperMethod; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_CORINFO_FIELD_INFO +{ + public uint fieldAccessor; + public uint fieldFlags; + public uint helper; + public uint offset; + public uint fieldType; + public ulong structType; + public uint accessAllowed; + public Agnostic_CORINFO_HELPER_DESC accessCalloutHelper; + public Agnostic_CORINFO_CONST_LOOKUP fieldLookup; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct DD +{ + public uint A; + public uint B; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct DDD +{ + public uint A; + public uint B; + public uint C; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_CanTailCall +{ + public ulong callerHnd; + public ulong declaredCalleeHnd; + public ulong exactCalleeHnd; + public ushort fIsTailPrefix; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_Environment +{ + public uint name_index; + public uint val_index; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_GetCallInfo +{ + public Agnostic_CORINFO_RESOLVED_TOKEN ResolvedToken; + public Agnostic_CORINFO_RESOLVED_TOKEN ConstrainedResolvedToken; + public ulong callerHandle; + public uint flags; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_CORINFO_CALL_INFO +{ + public ulong hMethod; + public uint methodFlags; + public uint classFlags; + public Agnostic_CORINFO_SIG_INFO sig; + public uint accessAllowed; + public Agnostic_CORINFO_HELPER_DESC callsiteCalloutHelper; + public uint thisTransform; + public uint kind; + public uint nullInstanceCheck; + public ulong contextHandle; + public uint exactContextNeedsRuntimeLookup; + public Agnostic_CORINFO_LOOKUP stubLookup; + public Agnostic_CORINFO_CONST_LOOKUP instParamLookup; + public uint exceptionCode; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_GetMethodInfo +{ + public Agnostic_CORINFO_METHOD_INFO info; + public byte result; // bool + public uint exceptionCode; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_FindSig +{ + public ulong module; + public uint sigTOK; + public ulong context; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct MethodOrSigInfoValue +{ + public ulong method; + public uint pSig_Index; + public uint cbSig; + public ulong scope; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_CORINFO_EH_CLAUSE +{ + public uint Flags; + public uint TryOffset; + public uint TryLength; + public uint HandlerOffset; + public uint HandlerLength; + public uint ClassToken; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_GetVars +{ + public uint cVars; + public uint vars_offset; + public uint extendOthers; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_CanAccessClassIn +{ + public Agnostic_CORINFO_RESOLVED_TOKEN ResolvedToken; + public ulong callerHandle; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_CanAccessClassOut +{ + public Agnostic_CORINFO_HELPER_DESC AccessHelper; + public uint result; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_AppendClassNameIn +{ + public uint nBufLenIsZero; + public ulong classHandle; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_AppendClassNameOut +{ + public uint nLen; + public uint name_index; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_CheckMethodModifier +{ + public ulong hMethod; + public uint modifier; + public uint fOptional; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_EmbedGenericHandle +{ + public Agnostic_CORINFO_RESOLVED_TOKEN ResolvedToken; + public ulong hCallerHandle; + public uint fEmbedParent; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_ExpandRawHandleIntrinsic +{ + public Agnostic_CORINFO_RESOLVED_TOKENin ResolvedToken; + public ulong hCallerHandle; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_CORINFO_GENERICHANDLE_RESULT +{ + public Agnostic_CORINFO_LOOKUP lookup; + public ulong compileTimeHandle; + public uint handleType; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_GetDelegateCtorIn +{ + public ulong methHnd; + public ulong clsHnd; + public ulong targetMethodHnd; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_DelegateCtorArgs +{ + public ulong pMethod; + public ulong pArg3; + public ulong pArg4; + public ulong pArg5; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_GetDelegateCtorOut +{ + public Agnostic_DelegateCtorArgs CtorData; + public ulong result; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_FindCallSiteSig +{ + public ulong module; + public uint methTok; + public ulong context; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_GetCastingHelper +{ + public ulong hClass; + public uint fThrowing; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_GetClassModuleIdForStatics +{ + public ulong Module; + public ulong pIndirection; + public ulong result; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_GetIsClassInitedFlagAddress +{ + public Agnostic_CORINFO_CONST_LOOKUP addr; + public uint offset; + public uint result; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_GetStaticBaseAddress +{ + public Agnostic_CORINFO_CONST_LOOKUP addr; + public uint result; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_PgoInstrumentationSchema +{ + public ulong Offset; + public uint InstrumentationKind; + public uint ILOffset; + public uint Count; + public uint Other; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_AllocPgoInstrumentationBySchema +{ + public ulong instrumentationDataAddress; + public uint schema_index; + public uint countSchemaItems; + public uint result; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_GetPgoInstrumentationResults +{ + public uint countSchemaItems; + public uint schema_index; + public uint data_index; + public uint dataByteCount; + public uint result; + public uint pgoSource; + public uint dynamicPgo; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_GetProfilingHandle +{ + public uint bHookFunction; + public ulong ProfilerHandle; + public uint bIndirectedHandles; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_GetThreadLocalStaticBlocksInfo +{ + public Agnostic_CORINFO_CONST_LOOKUP tlsIndex; + public ulong tlsGetAddrFtnPtr; + public ulong tlsIndexObject; + public ulong threadVarsSection; + public uint offsetOfThreadLocalStoragePointer; + public uint offsetOfMaxThreadStaticBlocks; + public uint offsetOfThreadStaticBlocks; + public uint offsetOfBaseOfThreadLocalData; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_GetThreadStaticInfo_NativeAOT +{ + public uint offsetOfThreadLocalStoragePointer; + public Agnostic_CORINFO_CONST_LOOKUP tlsRootObject; + public Agnostic_CORINFO_CONST_LOOKUP tlsIndexObject; + public Agnostic_CORINFO_CONST_LOOKUP threadStaticBaseSlow; + public Agnostic_CORINFO_CONST_LOOKUP tlsGetAddrFtnPtr; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_GetClassCtorInitializationInfo +{ + public Agnostic_CORINFO_CONST_LOOKUP addr; + public Agnostic_CORINFO_CONST_LOOKUP targetAddr; + public int size; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_GetThreadLocalFieldInfo +{ + public uint staticBlockIndex; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_GetTailCallHelpers +{ + public Agnostic_CORINFO_RESOLVED_TOKEN callToken; + public Agnostic_CORINFO_SIG_INFO sig; + public uint flags; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_CORINFO_TAILCALL_HELPERS +{ + public byte result; // bool + public uint flags; + public ulong hStoreArgs; + public ulong hCallTarget; + public ulong hDispatcher; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_GetArgClass_Value +{ + public ulong result; + public uint exceptionCode; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_GetArgType_Value +{ + public ulong vcTypeRet; + public uint result; + public uint exceptionCode; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_GetExactClassesResult +{ + public int numClasses; + public uint classes; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_ConfigIntInfo +{ + public uint nameIndex; + public uint defaultValue; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_GetSystemVAmd64PassStructInRegisterDescriptor +{ + public uint passedInRegisters; + public uint eightByteCount; + public UintArray2 eightByteClassifications; + public UintArray2 eightByteSizes; + public UintArray2 eightByteOffsets; + public uint result; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_GetSwiftLowering +{ + public uint byReference; + public UintArray4 loweredElements; + public UintArray4 offsets; + public uint numLoweredElements; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_GetFpStructLowering +{ + public uint byIntegerCallConv; + public UintArray2 loweredElements; + public UintArray2 offsets; + public uint numLoweredElements; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_GetContinuationTypeIn +{ + public ulong dataSize; + public uint objRefs; + public uint objRefsSize; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_GetWasmTypeSymbol +{ + public uint types; + public uint typesSize; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_ResolveVirtualMethodKey +{ + public ulong virtualMethod; + public ulong objClass; + public ulong context; + public uint pResolvedTokenVirtualMethodNonNull; + public Agnostic_CORINFO_RESOLVED_TOKEN pResolvedTokenVirtualMethod; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_ResolveVirtualMethodResult +{ + public byte returnValue; // bool + public ulong devirtualizedMethod; + public ulong tokenLookupContext; + public uint detail; + public Agnostic_CORINFO_RESOLVED_TOKEN resolvedTokenDevirtualizedMethod; + public Agnostic_CORINFO_RESOLVED_TOKEN resolvedTokenDevirtualizedUnboxedMethod; + public Agnostic_CORINFO_LOOKUP instParamLookup; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct ResolveTokenValue +{ + public Agnostic_CORINFO_RESOLVED_TOKENout tokenOut; + public uint exceptionCode; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct GetTokenTypeAsHandleValue +{ + public ulong hMethod; + public ulong hField; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct GetVarArgsHandleValue +{ + public uint cbSig; + public uint pSig_Index; + public ulong scope; + public uint token; + public ulong methHnd; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct GetCookieForInterpreterCalliSigValue +{ + public uint cbSig; + public uint pSig_Index; + public ulong scope; + public uint token; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct GetReadyToRunHelper_TOKENin +{ + public Agnostic_CORINFO_RESOLVED_TOKEN ResolvedToken; + public uint id; + public ulong callerHandle; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct GetReadyToRunHelper_TOKENout +{ + public Agnostic_CORINFO_CONST_LOOKUP Lookup; + public byte result; // bool +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct GetReadyToRunDelegateCtorHelper_TOKENIn +{ + public Agnostic_CORINFO_RESOLVED_TOKEN TargetMethod; + public uint targetConstraint; + public ulong delegateType; + public ulong callerHandle; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_RecordRelocation +{ + public ulong location; + public ulong target; + public uint fRelocType; + public uint addlDelta; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_AllocGCInfo +{ + public ulong size; + public uint retval_offset; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_AllocMemDetails +{ + public uint hotCodeSize; + public uint coldCodeSize; + public uint roDataSize; + public uint xcptnsCount; + public uint hotCodeBlock_offset; + public uint coldCodeBlock_offset; + public uint roDataBlock_offset; + public ulong hotCodeBlock; + public ulong coldCodeBlock; + public ulong roDataBlock; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_AllocUnwindInfo +{ + public ulong pHotCode; + public ulong pColdCode; + public uint startOffset; + public uint endOffset; + public uint unwindSize; + public uint pUnwindBlock_index; + public uint funcKind; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_CompileMethodResults +{ + public ulong nativeEntry; + public uint nativeSizeOfCode; + public uint CorJitResult; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_ReportInliningDecision +{ + public ulong inlinerHnd; + public ulong inlineeHnd; + public uint inlineResult; + public uint reason_offset; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_ReportTailCallDecision +{ + public ulong callerHnd; + public ulong calleeHnd; + public uint fIsTailPrefix; + public uint tailCallResult; + public uint reason_index; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_ReserveUnwindInfo +{ + public uint isFunclet; + public uint isColdCode; + public uint unwindSize; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_SetBoundaries +{ + public ulong ftn; + public uint cMap; + public uint pMap_offset; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_SetVars +{ + public ulong ftn; + public uint cVars; + public uint vars_offset; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_SetPatchpointInfo +{ + public uint index; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_RecordCallSite +{ + public Agnostic_CORINFO_SIG_INFO callSig; + public ulong methodHandle; +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct Agnostic_PrintResult +{ + public uint requiredBufferSize; + public uint stringBuffer; + public uint stringBufferSize; +} +[InlineArray(4)] +public struct Agnostic_CORINFO_HELPER_ARGArray4 +{ + private Agnostic_CORINFO_HELPER_ARG _element0; +} + +[InlineArray(2)] +public struct UintArray2 +{ + private uint _element0; +} + +[InlineArray(4)] +public struct UintArray4 +{ + private uint _element0; +} + +[InlineArray(4)] +public struct UlongArray4 +{ + private ulong _element0; +} diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/ByteBuilder.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/ByteBuilder.cs new file mode 100644 index 00000000000000..dd011661ad8460 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/ByteBuilder.cs @@ -0,0 +1,45 @@ +// 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.Text; + +namespace SuperPmi; + +// Builds byte strings. Recorded names are kept as their raw bytes, so that their hashes don't depend on decoding them. +public sealed class ByteBuilder +{ + private byte[] _buffer = new byte[256]; + + public int Length { get; private set; } + + public ReadOnlySpan AsSpan() => _buffer.AsSpan(0, Length); + + public byte[] ToArray() => AsSpan().ToArray(); + + public override string ToString() => Encoding.UTF8.GetString(AsSpan()); + + public ByteBuilder Append(ReadOnlySpan bytes) + { + EnsureCapacity(Length + bytes.Length); + bytes.CopyTo(_buffer.AsSpan(Length)); + Length += bytes.Length; + return this; + } + + public ByteBuilder Append(string text) + { + int max = Encoding.UTF8.GetMaxByteCount(text.Length); + EnsureCapacity(Length + max); + Length += Encoding.UTF8.GetBytes(text, _buffer.AsSpan(Length)); + return this; + } + + public void Truncate(int length) => Length = Math.Min(Length, length); + + private void EnsureCapacity(int capacity) + { + if (capacity > _buffer.Length) + Array.Resize(ref _buffer, Math.Max(capacity, _buffer.Length * 2)); + } +} diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CFormat.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CFormat.cs new file mode 100644 index 00000000000000..dbc7fb8e79d819 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CFormat.cs @@ -0,0 +1,306 @@ +// 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.Globalization; +using System.IO; +using System.Text; + +namespace SuperPmi; + +// C printf-style formatting, in which the output formats of the tools are defined. +// Integer arguments are converted to the width given by the length modifier, as a C variadic call would. +public static class CFormat +{ + public static void Printf(TextWriter writer, string format, params object[] args) => writer.Write(Sprintf(format, args)); + + public static string Sprintf(string format, params object[] args) + { + var sb = new StringBuilder(format.Length + 16); + int argIndex = 0; + int i = 0; + while (i < format.Length) + { + char c = format[i++]; + if (c != '%') + { + sb.Append(c); + continue; + } + + if (i < format.Length && format[i] == '%') + { + sb.Append('%'); + i++; + continue; + } + + bool leftAlign = false, zeroPad = false, plus = false, space = false, alternate = false; + for (; i < format.Length; i++) + { + switch (format[i]) + { + case '-': leftAlign = true; continue; + case '0': zeroPad = true; continue; + case '+': plus = true; continue; + case ' ': space = true; continue; + case '#': alternate = true; continue; + } + break; + } + + int width = -1; + if (i < format.Length && format[i] == '*') + { + width = Convert.ToInt32(args[argIndex++], CultureInfo.InvariantCulture); + if (width < 0) + { + leftAlign = true; + width = -width; + } + i++; + } + else + { + width = ParseNumber(format, ref i, -1); + } + + int precision = -1; + if (i < format.Length && format[i] == '.') + { + i++; + if (i < format.Length && format[i] == '*') + { + precision = Convert.ToInt32(args[argIndex++], CultureInfo.InvariantCulture); + i++; + } + else + { + precision = ParseNumber(format, ref i, 0); + } + } + + int bits = 32; + if (Match(format, ref i, "hh")) bits = 8; + else if (Match(format, ref i, "h")) bits = 16; + else if (Match(format, ref i, "ll") || Match(format, ref i, "I64") || Match(format, ref i, "l") || + Match(format, ref i, "j") || Match(format, ref i, "z") || Match(format, ref i, "t") || Match(format, ref i, "q")) bits = 64; + else if (Match(format, ref i, "I32")) bits = 32; + else if (Match(format, ref i, "L")) bits = 64; + + char conversion = format[i++]; + object arg = conversion == 'n' ? null : args[argIndex++]; + + string body; + string prefix = ""; + bool numeric = true; + switch (conversion) + { + case 'd': + case 'i': + { + long value = ToSigned(arg, bits); + body = FormatDigits((ulong)Math.Abs((decimal)value), 10, false, precision); + prefix = value < 0 ? "-" : plus ? "+" : space ? " " : ""; + break; + } + case 'u': + body = FormatDigits(ToUnsigned(arg, bits), 10, false, precision); + break; + case 'x': + case 'X': + { + ulong value = ToUnsigned(arg, bits); + body = FormatDigits(value, 16, conversion == 'X', precision); + if (alternate && value != 0) + prefix = conversion == 'X' ? "0X" : "0x"; + break; + } + case 'o': + { + ulong value = ToUnsigned(arg, bits); + body = FormatDigits(value, 8, false, precision); + if (alternate && !body.StartsWith('0')) + body = "0" + body; + break; + } + case 'c': + body = ((char)(byte)ToUnsigned(arg, 8)).ToString(); + numeric = false; + break; + case 's': + body = arg switch + { + null => "(null)", + byte[] bytes => Encoding.UTF8.GetString(bytes), + _ => arg.ToString(), + }; + if (precision >= 0 && body.Length > precision) + body = body.Substring(0, precision); + numeric = false; + break; + case 'p': + body = "0x" + ToUnsigned(arg, 64).ToString("x", CultureInfo.InvariantCulture); + numeric = false; + break; + case 'f': + case 'F': + case 'e': + case 'E': + case 'g': + case 'G': + { + double value = Convert.ToDouble(arg, CultureInfo.InvariantCulture); + body = FormatDouble(Math.Abs(value), conversion, precision < 0 ? 6 : precision, alternate); + prefix = (value < 0 || (value == 0 && double.IsNegative(value))) ? "-" : plus ? "+" : space ? " " : ""; + if (double.IsNaN(value) || double.IsInfinity(value)) + zeroPad = false; + break; + } + default: + throw new FormatException($"Unsupported printf conversion '%{conversion}' in \"{format}\""); + } + + // With a precision, '0' padding doesn't apply to integers. + if (precision >= 0 && conversion is 'd' or 'i' or 'u' or 'x' or 'X' or 'o') + zeroPad = false; + + int length = prefix.Length + body.Length; + if (width <= length) + { + sb.Append(prefix).Append(body); + } + else if (leftAlign) + { + sb.Append(prefix).Append(body).Append(' ', width - length); + } + else if (zeroPad && numeric) + { + sb.Append(prefix).Append('0', width - length).Append(body); + } + else + { + sb.Append(' ', width - length).Append(prefix).Append(body); + } + } + + return sb.ToString(); + } + + private static int ParseNumber(string format, ref int i, int defaultValue) + { + int start = i; + int value = 0; + while (i < format.Length && char.IsAsciiDigit(format[i])) + value = value * 10 + (format[i++] - '0'); + return i == start ? defaultValue : value; + } + + private static bool Match(string format, ref int i, string text) + { + if (string.CompareOrdinal(format, i, text, 0, text.Length) != 0) + return false; + i += text.Length; + return true; + } + + private static ulong RawBits(object arg) => arg switch + { + sbyte v => (ulong)(long)v, + short v => (ulong)(long)v, + int v => (ulong)(long)v, + long v => (ulong)v, + nint v => (ulong)(long)v, + byte v => v, + ushort v => v, + char v => v, + uint v => v, + ulong v => v, + nuint v => (ulong)v, + bool v => v ? 1UL : 0UL, + Enum e => RawBits(Convert.ChangeType(e, Enum.GetUnderlyingType(e.GetType()), CultureInfo.InvariantCulture)), + _ => throw new FormatException($"Unsupported printf integer argument type {arg?.GetType()}"), + }; + + private static ulong ToUnsigned(object arg, int bits) + { + ulong raw = RawBits(arg); + return bits == 64 ? raw : raw & ((1UL << bits) - 1); + } + + private static long ToSigned(object arg, int bits) + { + ulong raw = RawBits(arg); + return bits switch + { + 8 => (sbyte)raw, + 16 => (short)raw, + 32 => (int)raw, + _ => (long)raw, + }; + } + + private static string FormatDigits(ulong value, int radix, bool upper, int precision) + { + string digits = radix switch + { + 10 => value.ToString(CultureInfo.InvariantCulture), + 16 => value.ToString(upper ? "X" : "x", CultureInfo.InvariantCulture), + _ => Convert.ToString((long)value, 8), + }; + if (precision == 0 && value == 0) + return ""; + return precision > digits.Length ? new string('0', precision - digits.Length) + digits : digits; + } + + private static string FormatDouble(double value, char conversion, int precision, bool alternate) + { + bool upper = char.IsUpper(conversion); + if (double.IsNaN(value)) + return upper ? "NAN" : "nan"; + if (double.IsInfinity(value)) + return upper ? "INF" : "inf"; + + switch (char.ToLowerInvariant(conversion)) + { + case 'f': + return value.ToString("F" + precision, CultureInfo.InvariantCulture); + case 'e': + return FormatExponent(value, precision, upper); + default: + { + // %g: %e if the exponent is < -4 or >= the precision, else %f; trailing zeros removed. + int p = precision == 0 ? 1 : precision; + int exponent = value == 0 ? 0 : (int)Math.Floor(Math.Log10(value)); + string rounded = value.ToString("E" + (p - 1), CultureInfo.InvariantCulture); + exponent = int.Parse(rounded.Substring(rounded.IndexOf('E') + 1), CultureInfo.InvariantCulture); + string result = (exponent < -4 || exponent >= p) + ? FormatExponent(value, p - 1, upper) + : value.ToString("F" + (p - 1 - exponent), CultureInfo.InvariantCulture); + if (!alternate) + result = StripTrailingZeros(result); + return result; + } + } + } + + // C uses at least two exponent digits; .NET uses three. + private static string FormatExponent(double value, int precision, bool upper) + { + string s = value.ToString((upper ? "E" : "e") + precision, CultureInfo.InvariantCulture); + int e = s.IndexOfAny(['e', 'E']); + string mantissa = s.Substring(0, e); + int exponent = int.Parse(s.Substring(e + 1), CultureInfo.InvariantCulture); + return $"{mantissa}{s[e]}{(exponent < 0 ? '-' : '+')}{Math.Abs(exponent):00}"; + } + + private static string StripTrailingZeros(string s) + { + int e = s.IndexOfAny(['e', 'E']); + string mantissa = e >= 0 ? s.Substring(0, e) : s; + string exponent = e >= 0 ? s.Substring(e) : ""; + if (mantissa.Contains('.')) + mantissa = mantissa.TrimEnd('0').TrimEnd('.'); + return mantissa + exponent; + } +} diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CallUtils.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CallUtils.cs new file mode 100644 index 00000000000000..e7af6979b4b92e --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CallUtils.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.InteropServices; +using System.Text; +using Internal.JitInterface; + +using static SuperPmi.SpmiRecordsHelper; + +namespace SuperPmi; + +public static class TypeUtils +{ + // Naming follows JITtype2varType in src/coreclr/jit/ee_il_dll.hpp. + public static string GetCorInfoTypeName(CorInfoType type) => type switch + { + CorInfoType.CORINFO_TYPE_VOID => "void", + CorInfoType.CORINFO_TYPE_BOOL => "bool", + CorInfoType.CORINFO_TYPE_CHAR => "char", + CorInfoType.CORINFO_TYPE_BYTE => "byte", + CorInfoType.CORINFO_TYPE_UBYTE => "ubyte", + CorInfoType.CORINFO_TYPE_SHORT => "short", + CorInfoType.CORINFO_TYPE_USHORT => "ushort", + CorInfoType.CORINFO_TYPE_INT => "int", + CorInfoType.CORINFO_TYPE_UINT => "uint", + CorInfoType.CORINFO_TYPE_LONG => "long", + CorInfoType.CORINFO_TYPE_ULONG => "ulong", + CorInfoType.CORINFO_TYPE_FLOAT => "float", + CorInfoType.CORINFO_TYPE_DOUBLE => "double", + CorInfoType.CORINFO_TYPE_BYREF => "byref", + CorInfoType.CORINFO_TYPE_VALUECLASS => "struct", + CorInfoType.CORINFO_TYPE_CLASS => "ref", + // Emulates the JIT's TYP_I_IMPL. + CorInfoType.CORINFO_TYPE_NATIVEINT or CorInfoType.CORINFO_TYPE_NATIVEUINT => SpmiUtil.IsSpmiTarget64Bit() ? "long" : "int", + // Pointer-sized, without regard to GC-ness. + CorInfoType.CORINFO_TYPE_PTR => "ptr", + _ => UnknownType(type), + }; + + private static string UnknownType(CorInfoType type) + { + ErrorHandling.LogException(ExceptionCodes.TYPEUTILS, $"Unknown type passed into GetCorInfoTypeName (0x{(int)type:x})"); + return "UNKNOWN"; + } + + public static CorInfoType strip(CorInfoTypeWithMod val) => (CorInfoType)(val & CorInfoTypeWithMod.CORINFO_TYPE_MASK); +} + +public static unsafe class CallUtils +{ + public const uint CORINFO_HELP_UNDEF = 0; + + // Helpers are marked by odd handle values. + public static uint GetHelperNum(CORINFO_METHOD_STRUCT_* method) + => (CastHandle(method) & 1) == 0 ? CORINFO_HELP_UNDEF : (uint)(CastHandle(method) >> 2); + + public static string GetHelperName(uint helperNum) + => helperNum < (uint)CorInfoHelpFunc.CORINFO_HELP_COUNT ? Enum.GetName((CorInfoHelpFunc)helperNum) : $"CORINFO_HELP_{helperNum}"; + + // Formats "Class:Method(argtypes):rettype[:this]", as in src/coreclr/jit/eeinterface.cpp. With + // 'ignoreMethodName', the class and method names are placeholders that are the same for all methods. + public static byte[] GetMethodFullName(MethodContext mc, CORINFO_METHOD_STRUCT_* hnd, CORINFO_SIG_INFO sig, bool ignoreMethodName = false) + { + uint helperNum = GetHelperNum(hnd); + if (helperNum != CORINFO_HELP_UNDEF) + return Encoding.ASCII.GetBytes(GetHelperName(helperNum)); + + var name = new ByteBuilder(); + if (ignoreMethodName) + { + name.Append("CLASS:METHOD"); + } + else + { + name.Append(getClassName(mc, mc.repGetMethodClass(hnd))); + name.Append(":"u8); + name.Append(getMethodName(mc, hnd)); + } + + name.Append("("u8); + CORINFO_ARG_LIST_STRUCT_* argList = sig.args; + for (uint i = 0; i < sig.numArgs; i++) + { + CORINFO_CLASS_STRUCT_* dummyCls; + CorInfoType type = TypeUtils.strip(mc.repGetArgType(&sig, argList, &dummyCls, out _)); + name.Append(TypeUtils.GetCorInfoTypeName(type)); + + argList = mc.repGetArgNext(argList); + if (i + 1 < sig.numArgs) + name.Append(","u8); + } + name.Append(")"u8); + + if (sig.retType != CorInfoType.CORINFO_TYPE_VOID) + name.Append(":"u8).Append(TypeUtils.GetCorInfoTypeName(sig.retType)); + + // Explicit 'this' is already the first element of the argument list. + if ((sig.callConv & (CorInfoCallConv.CORINFO_CALLCONV_HASTHIS | CorInfoCallConv.CORINFO_CALLCONV_EXPLICITTHIS)) == CorInfoCallConv.CORINFO_CALLCONV_HASTHIS) + name.Append(":this"u8); + + return name.ToArray(); + } + + public static byte[] getMethodName(MethodContext mc, CORINFO_METHOD_STRUCT_* methHnd) + => GetFromPrinter((buffer, size, required) => mc.repPrintMethodName(methHnd, buffer, size, required)); + + public static byte[] getClassName(MethodContext mc, CORINFO_CLASS_STRUCT_* clsHnd) + => GetFromPrinter((buffer, size, required) => mc.repPrintClassName(clsHnd, buffer, size, required)); + + private delegate nuint Printer(byte* buffer, nuint bufferSize, nuint* pRequiredBufferSize); + + // Prints into a 256-byte buffer first, and asks for the required size only if that wasn't enough. + private static byte[] GetFromPrinter(Printer print) + { + byte* buffer = stackalloc byte[256]; + nuint requiredBufferSize; + print(buffer, 256, &requiredBufferSize); + if (requiredBufferSize <= 256) + return MemoryMarshal.CreateReadOnlySpanFromNullTerminated(buffer).ToArray(); + + byte[] large = new byte[requiredBufferSize]; + fixed (byte* p = large) + { + print(p, requiredBufferSize, null); + return MemoryMarshal.CreateReadOnlySpanFromNullTerminated(p).ToArray(); + } + } +} diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CompileResult.Dump.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CompileResult.Dump.cs new file mode 100644 index 00000000000000..72ee1d75412720 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CompileResult.Dump.cs @@ -0,0 +1,168 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Buffers.Binary; +using System.IO; +using System.Runtime.InteropServices; +using static SuperPmi.DumpStrings; + +namespace SuperPmi; + +// Dumps each kind of recorded data, as mcs -dump prints it. +public sealed partial class CompileResult +{ + private static TextWriter Out => Logger.Out; + + private static uint U32(ReadOnlySpan data, int offset) => BinaryPrimitives.ReadUInt32LittleEndian(data.Slice(offset)); + + public void dmpAssertLog(uint key, uint value) + { + CFormat.Printf(Out, "AssertLog key %u, value '%s'", key, AssertLog.GetString(value)); + AssertLog.Unlock(); + } + + public void dmpCallLog(uint key, uint value) + { + CFormat.Printf(Out, "CallLog %u '%s'", key, CallLog.GetString(value)); + CallLog.Unlock(); + } + + public void dmpSetBoundaries(uint key, in Agnostic_SetBoundaries value) + { + const int OffsetMappingSize = 12; // ICorDebugInfo::OffsetMapping: nativeOffset, ilOffset, source + ReadOnlySpan om = SetBoundaries.GetBuffer(value.pMap_offset); + CFormat.Printf(Out, "SetBoundaries key 0, value ftn-%016llX cMap-%u %u{", value.ftn, value.cMap, value.pMap_offset); + for (uint i = 0; i < value.cMap; i++) + { + if (i != 0) + Out.Write(", "); + int at = (int)i * OffsetMappingSize; + CFormat.Printf(Out, "%u %u %u", U32(om, at + 4), U32(om, at), U32(om, at + 8)); + } + Out.Write("}"); + SetBoundaries.Unlock(); + } + + public void dmpSetVars(uint key, in Agnostic_SetVars value) + { + // ICorDebugInfo::NativeVarInfo: startOffset, endOffset, callReturnValueILOffset, varNumber, then a 16-byte VarLoc. + const int NativeVarInfoSize = 32; + ReadOnlySpan om = SetVars.GetBuffer(value.vars_offset); + CFormat.Printf(Out, "SetVars key %u, value ftn-%016llX cVars-%u %u{", key, value.ftn, value.cVars, value.vars_offset); + for (uint i = 0; i < value.cVars; i++) + { + if (i != 0) + Out.Write(", "); + int at = (int)i * NativeVarInfoSize; + CFormat.Printf(Out, "so-%u eo-%u var-%u", U32(om, at), U32(om, at + 4), U32(om, at + 12)); + } + Out.Write("}"); + SetVars.Unlock(); + } + + public void dmpSetPatchpointInfo(uint key, in Agnostic_SetPatchpointInfo value) + { + SetPatchpointInfo.GetBuffer(value.index); + CFormat.Printf(Out, "SetPatchpointInfo key %u, index %u{", key, value.index); + Out.Write("}"); + SetPatchpointInfo.Unlock(); + } + + // The buffer's offset is printed in place of its address, which changes from run to run. + public void dmpAllocGCInfo(uint key, in Agnostic_AllocGCInfo value) + { + ReadOnlySpan buff = AllocGCInfo.GetBuffer(value.retval_offset); + Out.Write("AllocGCInfo key 0, "); + CFormat.Printf(Out, "sz-%llu %s{ ", value.size, value.retval_offset == uint.MaxValue ? "(nil)" : CFormat.Sprintf("0x%x", value.retval_offset)); + for (ulong i = 0; i < value.size; i++) + CFormat.Printf(Out, "%02X ", buff[(int)i]); + Out.Write("}"); + AllocGCInfo.Unlock(); + } + + public void dmpReportInliningDecision(uint key, in Agnostic_ReportInliningDecision value) + { + CFormat.Printf(Out, "ReportInliningDecision key %u, value inliner-%016llX inlinee-%016llX res-%u reason-'%s'", key, + value.inlinerHnd, value.inlineeHnd, value.inlineResult, ReportInliningDecision.GetString(value.reason_offset)); + ReportInliningDecision.Unlock(); + } + + public void dmpReportTailCallDecision(uint key, in Agnostic_ReportTailCallDecision value) + { + CFormat.Printf(Out, "ReportTailCallDecision key-%u, value cr-%016llX ce-%016llX tail-%u call-%u -%s", key, value.callerHnd, + value.calleeHnd, value.tailCallResult, value.tailCallResult, ReportTailCallDecision.GetString(value.reason_index)); + ReportTailCallDecision.Unlock(); + } + + public void dmpProcessName(uint key, uint value) + { + CFormat.Printf(Out, "ProcessName key %u, value '%s'", key, ProcessName.GetString(value)); + ProcessName.Unlock(); + } + + public void dmpAllocMem(uint key, in Agnostic_AllocMemDetails value) + => CFormat.Printf(Out, "AllocMem key 0, value hotCodeSize-%u coldCodeSize-%u roDataSize-%u xcptnsCount-%u hotCodeBlock_offset-%u coldCodeBlock_offset-%u roDataBlock_offset-%u hotCodeBlock-%016llX coldCodeBlock-%016llX roDataBlock-%016llX", + value.hotCodeSize, value.coldCodeSize, value.roDataSize, value.xcptnsCount, + value.hotCodeBlock_offset, value.coldCodeBlock_offset, value.roDataBlock_offset, value.hotCodeBlock, + value.coldCodeBlock, value.roDataBlock); + + public void dmpCompileMethod(uint key, in Agnostic_CompileMethodResults value) + => CFormat.Printf(Out, "CompileMethod key %u, value nativeEntry-%016llX nativeSizeOfCode-%u CorJitResult-%u", key, + value.nativeEntry, value.nativeSizeOfCode, value.CorJitResult); + + public void dmpMessageLog(uint key, uint value) + => CFormat.Printf(Out, "MessageLog NYI"); + + public void dmpSetEHcount(uint key, uint value) + => CFormat.Printf(Out, "SetEHcount key %u, value %u", key, value); + + public void dmpSetEHinfo(uint key, in Agnostic_CORINFO_EH_CLAUSE value) + { + CFormat.Printf(Out, "SetEHinfo key %u, value flg-%u to-%u tl-%u ho-%u hl-%u", key, value.Flags, value.TryOffset, value.TryLength, + value.HandlerOffset, value.HandlerLength); + if (value.Flags == CORINFO_EH_CLAUSE_FILTER) + { + CFormat.Printf(Out, " fo-%u", value.ClassToken); // FilterOffset + } + else if (value.Flags == CORINFO_EH_CLAUSE_NONE) + { + CFormat.Printf(Out, " cls-%08X", value.ClassToken); + } + // else, no need to print for finally/fault handlers + } + + public void dmpSetMethodAttribs(ulong key, uint value) + { + CFormat.Printf(Out, "SetMethodAttribs key ftn-%016llX, value attr-%08X", key, value); + } + + public void dmpReportFatalError(uint key, uint value) + => CFormat.Printf(Out, "ReportFatalError key Count-%u, value result-%08X", key, value); + + public void dmpRecordRelocation(uint key, in Agnostic_RecordRelocation value) + => CFormat.Printf(Out, "RecordRelocation key %u, value loc-%016llX tgt-%016llX fRelocType-%u(%s) addlDelta:%d", key, + value.location, value.target, value.fRelocType, relocationTypeToString(value.fRelocType), + (int)value.addlDelta); + + public void dmpReserveUnwindInfo(uint key, in Agnostic_ReserveUnwindInfo value) + => CFormat.Printf(Out, "ReserveUnwindInfo key %u, value isFun-%u isCold-%u usz-%u", key, value.isFunclet, value.isColdCode, + value.unwindSize); + + public void dmpAllocUnwindInfo(uint key, in Agnostic_AllocUnwindInfo value) + => CFormat.Printf(Out, "AllocUnwindInfo key %u, value pHot-%016llX pCold-%016llX startOff-%u endOff-%u unwindSz-%u blki-%u funcKind-%u", + key, value.pHotCode, value.pColdCode, value.startOffset, value.endOffset, value.unwindSize, + value.pUnwindBlock_index, value.funcKind); + + public void dmpRecordCallSiteWithSignature(uint key, in Agnostic_RecordCallSite value) + => CFormat.Printf(Out, "RecordCallSite key %u, callSig-%s ftn-%016llX", + key, + SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INFO(value.callSig, RecordCallSiteWithSignature, CrSigInstHandleMap), + value.methodHandle); + + public void dmpRecordCallSiteWithoutSignature(uint key, ulong methodHandle) + => CFormat.Printf(Out, "RecordCallSite without call signature key %u, ftn-%016llX", key, methodHandle); + + public void dmpCrSigInstHandleMap(uint key, ulong value) + => CFormat.Printf(Out, "CrSigInstHandleMap key %u, value %016llX", key, value); +} diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CompileResult.Maps.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CompileResult.Maps.cs new file mode 100644 index 00000000000000..5b518fe273157d --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CompileResult.Maps.cs @@ -0,0 +1,87 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// The maps of a compile result: what the JIT reported; each is a packet of the .mc format. + +namespace SuperPmi; + +public partial class CompileResult +{ + // The maps are serialized in this order. + internal static readonly MapInfo[] s_maps = + [ + new MapInfo(0, "AllocGCInfo", PacketId.CR_AllocGCInfo, static () => new LightWeightMap()), + new MapInfo(1, "AllocMem", PacketId.CR_AllocMem, static () => new LightWeightMap()), + new MapInfo(2, "AllocUnwindInfo", PacketId.CR_AllocUnwindInfo, static () => new DenseLightWeightMap()), + new MapInfo(3, "AssertLog", PacketId.CR_AssertLog, static () => new DenseLightWeightMap()), + new MapInfo(4, "CallLog", PacketId.CR_CallLog, static () => new DenseLightWeightMap()), + new MapInfo(5, "CompileMethod", PacketId.CR_CompileMethod, static () => new LightWeightMap()), + new MapInfo(6, "MessageLog", PacketId.CR_MessageLog, static () => new DenseLightWeightMap()), + new MapInfo(7, "ProcessName", PacketId.CR_ProcessName, static () => new DenseLightWeightMap()), + new MapInfo(8, "RecordCallSiteWithSignature", PacketId.CR_RecordCallSiteWithSignature, static () => new LightWeightMap()), + new MapInfo(9, "RecordCallSiteWithoutSignature", PacketId.CR_RecordCallSiteWithoutSignature, static () => new LightWeightMap()), + new MapInfo(10, "RecordRelocation", PacketId.CR_RecordRelocation, static () => new DenseLightWeightMap()), + new MapInfo(11, "ReportFatalError", PacketId.CR_ReportFatalError, static () => new DenseLightWeightMap()), + new MapInfo(12, "ReportInliningDecision", PacketId.CR_ReportInliningDecision, static () => new DenseLightWeightMap()), + new MapInfo(13, "ReportTailCallDecision", PacketId.CR_ReportTailCallDecision, static () => new DenseLightWeightMap()), + new MapInfo(14, "ReserveUnwindInfo", PacketId.CR_ReserveUnwindInfo, static () => new DenseLightWeightMap()), + new MapInfo(15, "SetBoundaries", PacketId.CR_SetBoundaries, static () => new LightWeightMap()), + new MapInfo(16, "SetEHcount", PacketId.CR_SetEHcount, static () => new LightWeightMap()), + new MapInfo(17, "SetEHinfo", PacketId.CR_SetEHinfo, static () => new LightWeightMap()), + new MapInfo(18, "SetMethodAttribs", PacketId.CR_SetMethodAttribs, static () => new LightWeightMap()), + new MapInfo(19, "SetVars", PacketId.CR_SetVars, static () => new LightWeightMap()), + new MapInfo(20, "SetPatchpointInfo", PacketId.CR_SetPatchpointInfo, static () => new LightWeightMap()), + new MapInfo(21, "CrSigInstHandleMap", PacketId.CR_CrSigInstHandleMap, static () => new DenseLightWeightMap()), + ]; + + private readonly LightWeightMapBuffer[] _maps = new LightWeightMapBuffer[s_maps.Length]; + + public LightWeightMap AllocGCInfo { get => (LightWeightMap)_maps[0]; set => _maps[0] = value; } + public LightWeightMap AllocMem { get => (LightWeightMap)_maps[1]; set => _maps[1] = value; } + public DenseLightWeightMap AllocUnwindInfo { get => (DenseLightWeightMap)_maps[2]; set => _maps[2] = value; } + public DenseLightWeightMap AssertLog { get => (DenseLightWeightMap)_maps[3]; set => _maps[3] = value; } + public DenseLightWeightMap CallLog { get => (DenseLightWeightMap)_maps[4]; set => _maps[4] = value; } + public LightWeightMap CompileMethod { get => (LightWeightMap)_maps[5]; set => _maps[5] = value; } + public DenseLightWeightMap MessageLog { get => (DenseLightWeightMap)_maps[6]; set => _maps[6] = value; } + public DenseLightWeightMap ProcessName { get => (DenseLightWeightMap)_maps[7]; set => _maps[7] = value; } + public LightWeightMap RecordCallSiteWithSignature { get => (LightWeightMap)_maps[8]; set => _maps[8] = value; } + public LightWeightMap RecordCallSiteWithoutSignature { get => (LightWeightMap)_maps[9]; set => _maps[9] = value; } + public DenseLightWeightMap RecordRelocation { get => (DenseLightWeightMap)_maps[10]; set => _maps[10] = value; } + public DenseLightWeightMap ReportFatalError { get => (DenseLightWeightMap)_maps[11]; set => _maps[11] = value; } + public DenseLightWeightMap ReportInliningDecision { get => (DenseLightWeightMap)_maps[12]; set => _maps[12] = value; } + public DenseLightWeightMap ReportTailCallDecision { get => (DenseLightWeightMap)_maps[13]; set => _maps[13] = value; } + public DenseLightWeightMap ReserveUnwindInfo { get => (DenseLightWeightMap)_maps[14]; set => _maps[14] = value; } + public LightWeightMap SetBoundaries { get => (LightWeightMap)_maps[15]; set => _maps[15] = value; } + public LightWeightMap SetEHcount { get => (LightWeightMap)_maps[16]; set => _maps[16] = value; } + public LightWeightMap SetEHinfo { get => (LightWeightMap)_maps[17]; set => _maps[17] = value; } + public LightWeightMap SetMethodAttribs { get => (LightWeightMap)_maps[18]; set => _maps[18] = value; } + public LightWeightMap SetVars { get => (LightWeightMap)_maps[19]; set => _maps[19] = value; } + public LightWeightMap SetPatchpointInfo { get => (LightWeightMap)_maps[20]; set => _maps[20] = value; } + public DenseLightWeightMap CrSigInstHandleMap { get => (DenseLightWeightMap)_maps[21]; set => _maps[21] = value; } + + internal void dumpMaps() + { + MapDumper.Dump(nameof(AllocGCInfo), AllocGCInfo, (k, v) => dmpAllocGCInfo(k, v)); + MapDumper.Dump(nameof(AllocMem), AllocMem, (k, v) => dmpAllocMem(k, v)); + MapDumper.Dump(nameof(AllocUnwindInfo), AllocUnwindInfo, (k, v) => dmpAllocUnwindInfo(k, v)); + MapDumper.Dump(nameof(AssertLog), AssertLog, (k, v) => dmpAssertLog(k, v)); + MapDumper.Dump(nameof(CallLog), CallLog, (k, v) => dmpCallLog(k, v)); + MapDumper.Dump(nameof(CompileMethod), CompileMethod, (k, v) => dmpCompileMethod(k, v)); + MapDumper.Dump(nameof(MessageLog), MessageLog, (k, v) => dmpMessageLog(k, v)); + MapDumper.Dump(nameof(ProcessName), ProcessName, (k, v) => dmpProcessName(k, v)); + MapDumper.Dump(nameof(RecordCallSiteWithSignature), RecordCallSiteWithSignature, (k, v) => dmpRecordCallSiteWithSignature(k, v)); + MapDumper.Dump(nameof(RecordCallSiteWithoutSignature), RecordCallSiteWithoutSignature, (k, v) => dmpRecordCallSiteWithoutSignature(k, v)); + MapDumper.Dump(nameof(RecordRelocation), RecordRelocation, (k, v) => dmpRecordRelocation(k, v)); + MapDumper.Dump(nameof(ReportFatalError), ReportFatalError, (k, v) => dmpReportFatalError(k, v)); + MapDumper.Dump(nameof(ReportInliningDecision), ReportInliningDecision, (k, v) => dmpReportInliningDecision(k, v)); + MapDumper.Dump(nameof(ReportTailCallDecision), ReportTailCallDecision, (k, v) => dmpReportTailCallDecision(k, v)); + MapDumper.Dump(nameof(ReserveUnwindInfo), ReserveUnwindInfo, (k, v) => dmpReserveUnwindInfo(k, v)); + MapDumper.Dump(nameof(SetBoundaries), SetBoundaries, (k, v) => dmpSetBoundaries(k, v)); + MapDumper.Dump(nameof(SetEHcount), SetEHcount, (k, v) => dmpSetEHcount(k, v)); + MapDumper.Dump(nameof(SetEHinfo), SetEHinfo, (k, v) => dmpSetEHinfo(k, v)); + MapDumper.Dump(nameof(SetMethodAttribs), SetMethodAttribs, (k, v) => dmpSetMethodAttribs(k, v)); + MapDumper.Dump(nameof(SetVars), SetVars, (k, v) => dmpSetVars(k, v)); + MapDumper.Dump(nameof(SetPatchpointInfo), SetPatchpointInfo, (k, v) => dmpSetPatchpointInfo(k, v)); + MapDumper.Dump(nameof(CrSigInstHandleMap), CrSigInstHandleMap, (k, v) => dmpCrSigInstHandleMap(k, v)); + } +} diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CompileResult.Replay.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CompileResult.Replay.cs new file mode 100644 index 00000000000000..b7072c43e9f9f1 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CompileResult.Replay.cs @@ -0,0 +1,793 @@ +// 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 Internal.JitInterface; +using Internal.TypeSystem; + +using static SuperPmi.SpmiRecordsHelper; +using static SuperPmi.SpmiUtil; + +namespace SuperPmi; + +// The data needed to process relocations. +public struct RelocContext +{ + public MethodContext mc; + public nuint hotCodeAddress; + public nuint hotCodeSize; + public nuint coldCodeAddress; + public nuint coldCodeSize; + public nuint roDataAddress; + public nuint roDataSize1; + public nuint roDataSize2; + public nuint originalHotCodeAddress; + public nuint originalColdCodeAddress; + public nuint originalRoDataAddress1; + public nuint originalRoDataAddress2; +} + +public sealed unsafe partial class CompileResult +{ + // Set it to true to use CallUtils.GetRecordedCallSiteInfo. + private static readonly bool recordCallSitesWithoutSig = false; + + public double secondsToCompile; + public ulong clockCyclesToCompile; + + // The method full name reported by the JIT (not available with a release JIT), and the compilation tier. + public string MethodFullName; + public string TieringName; + public readonly JitMetrics Metrics = new(); + + // Not persisted. + public readonly LightWeightMap CallTargetTypes = new(); + + private PinnedArena memoryTracker; + + private nuint allocMemHotCodeSize, allocMemColdCodeSize, allocMemRoDataSize; + private uint allocMemXcptnsCount; + private void* allocMemHotCodeBlock, allocMemColdCodeBlock, allocMemRoDataBlock; + + private nuint allocGCInfoSize; + private void* allocGCInfoRetval; + + // Memory that lives as long as the compile result. + public PinnedArena MemoryTracker => memoryTracker ??= new PinnedArena(); + + public void* allocateMemory(nuint sizeInBytes, nuint alignment = 16) => MemoryTracker.Allocate(sizeInBytes, alignment); + + public void recAssert(string assertText) + { + AssertLog ??= new DenseLightWeightMap(); + AssertLog.Append(AssertLog.AddBuffer(CStringBytes(assertText))); + } + + public string repAssert() => AssertLog == null || AssertLog.GetCount() == 0 ? null : AssertLog.GetString(AssertLog.Get(0)); + + // Calls aren't logged anymore, but the (empty) log still marks the compile result as non-empty. + public void AddCall(string name) => CallLog ??= new DenseLightWeightMap(); + + public void dumpToConsole() + { + Logger.Out.Write("***************************************** CompileResult\n"); + dumpMaps(); + Logger.Out.Write("-----------------------------------------\n"); + } + + // The EE allocates these blocks (and the exception blocks) in a single linear region, with an + // 8-byte aligned RO block. + public void recAllocMem(nuint hotCodeSize, nuint coldCodeSize, nuint roDataSize, uint xcptnsCount, void* hotCodeBlock, void* coldCodeBlock, void* roDataBlock) + { + // Grab the values, to scrape the real answers in the capture method. + allocMemHotCodeSize = hotCodeSize; + allocMemColdCodeSize = coldCodeSize; + allocMemRoDataSize = roDataSize; + allocMemXcptnsCount = xcptnsCount; + allocMemHotCodeBlock = hotCodeBlock; + allocMemColdCodeBlock = coldCodeBlock; + allocMemRoDataBlock = roDataBlock; + } + + public void recAllocMemCapture() + { + AllocMem ??= new LightWeightMap(); + AllocMem.Add(0, new Agnostic_AllocMemDetails + { + hotCodeSize = (uint)allocMemHotCodeSize, + coldCodeSize = (uint)allocMemColdCodeSize, + roDataSize = (uint)allocMemRoDataSize, + xcptnsCount = allocMemXcptnsCount, + hotCodeBlock_offset = AllocMem.AddBuffer(Bytes(allocMemHotCodeBlock, allocMemHotCodeSize)), + coldCodeBlock_offset = AllocMem.AddBuffer(Bytes(allocMemColdCodeBlock, allocMemColdCodeSize)), + roDataBlock_offset = AllocMem.AddBuffer(Bytes(allocMemRoDataBlock, allocMemRoDataSize)), + hotCodeBlock = CastHandle(allocMemHotCodeBlock), + coldCodeBlock = CastHandle(allocMemColdCodeBlock), + roDataBlock = CastHandle(allocMemRoDataBlock), + }); + } + + // Code can't be placed at the addresses used during recording, so the blocks point into the AllocMem + // map, and the original addresses are returned separately. + public Agnostic_AllocMemDetails repAllocMem(out byte* hotCodeBlock, out byte* coldCodeBlock, out byte* roDataBlock) + { + Agnostic_AllocMemDetails value = AllocMem.Get(0); + hotCodeBlock = value.hotCodeSize > 0 ? AllocMem.GetBufferPointer(value.hotCodeBlock_offset) : null; + coldCodeBlock = value.coldCodeSize > 0 ? AllocMem.GetBufferPointer(value.coldCodeBlock_offset) : null; + roDataBlock = value.roDataSize > 0 ? AllocMem.GetBufferPointer(value.roDataBlock_offset) : null; + return value; + } + + public void recSetBoundaries(CORINFO_METHOD_STRUCT_* ftn, uint cMap, OffsetMapping* pMap) + { + SetBoundaries ??= new LightWeightMap(); + SetBoundaries.Add(0, new Agnostic_SetBoundaries + { + ftn = CastHandle(ftn), + cMap = cMap, + pMap_offset = SetBoundaries.AddBuffer(Bytes(pMap, (nuint)sizeof(OffsetMapping) * cMap)), + }); + } + + public bool repSetBoundaries(out CORINFO_METHOD_STRUCT_* ftn, out uint cMap, out OffsetMapping* pMap) + { + if (SetBoundaries == null || SetBoundaries.GetCount() == 0) + { + ftn = (CORINFO_METHOD_STRUCT_*)-1; + cMap = uint.MaxValue; + pMap = null; + return false; + } + + Agnostic_SetBoundaries value = SetBoundaries.Get(0); + ftn = (CORINFO_METHOD_STRUCT_*)value.ftn; + cMap = value.cMap; + pMap = (OffsetMapping*)SetBoundaries.GetBufferPointer(value.pMap_offset); + return true; + } + + public void recSetVars(CORINFO_METHOD_STRUCT_* ftn, uint cVars, NativeVarInfo* vars) + { + SetVars ??= new LightWeightMap(); + SetVars.Add(0, new Agnostic_SetVars + { + ftn = CastHandle(ftn), + cVars = cVars, + vars_offset = SetVars.AddBuffer(Bytes(vars, (nuint)sizeof(NativeVarInfo) * cVars)), // not deep enough: vlt memory is pointer sized + }); + } + + public bool repSetVars(out CORINFO_METHOD_STRUCT_* ftn, out uint cVars, out NativeVarInfo* vars) + { + if (SetVars == null || SetVars.GetCount() == 0) + { + ftn = (CORINFO_METHOD_STRUCT_*)-1; + cVars = uint.MaxValue; + vars = null; + return false; + } + + Agnostic_SetVars value = SetVars.Get(0); + ftn = (CORINFO_METHOD_STRUCT_*)value.ftn; + cVars = value.cVars; + vars = (NativeVarInfo*)SetVars.GetBufferPointer(value.vars_offset); + return true; + } + + public void recSetPatchpointInfo(PatchpointInfo* patchpointInfo) + { + SetPatchpointInfo ??= new LightWeightMap(); + SetPatchpointInfo.Add(0, new Agnostic_SetPatchpointInfo + { + index = SetPatchpointInfo.AddBuffer(Bytes(patchpointInfo, PatchpointInfoSize(patchpointInfo))), + }); + } + + public bool repSetPatchpointInfo(out PatchpointInfo* patchpointInfo) + { + if (SetPatchpointInfo == null || SetPatchpointInfo.GetCount() == 0) + { + patchpointInfo = null; + return false; + } + + patchpointInfo = (PatchpointInfo*)SetPatchpointInfo.GetBufferPointer(SetPatchpointInfo.Get(0).index); + return true; + } + + public void recAllocGCInfo(nuint size, void* retval) + { + allocGCInfoSize = size; + allocGCInfoRetval = retval; + } + + public void recAllocGCInfoCapture() + { + AllocGCInfo ??= new LightWeightMap(); + AllocGCInfo.Add(0, new Agnostic_AllocGCInfo + { + size = allocGCInfoSize, + retval_offset = AllocGCInfo.AddBuffer(Bytes(allocGCInfoRetval, (uint)allocGCInfoSize)), + }); + } + + public void repAllocGCInfo(out nuint size, out void* retval) + { + Agnostic_AllocGCInfo value = AllocGCInfo.Get(0); + size = (nuint)value.size; + retval = size > 0 ? AllocGCInfo.GetBufferPointer(value.retval_offset) : null; + } + + public void recCompileMethod(byte* nativeEntry, uint nativeSizeOfCode, CorJitResult result) + { + CompileMethod ??= new LightWeightMap(); + CompileMethod.Add(0, new Agnostic_CompileMethodResults + { + nativeEntry = CastHandle(nativeEntry), + nativeSizeOfCode = nativeSizeOfCode, + CorJitResult = (uint)result, + }); + } + + public void repCompileMethod(out byte* nativeEntry, out uint nativeSizeOfCode, out CorJitResult result) + { + Agnostic_CompileMethodResults value = CompileMethod.Get(0); + nativeEntry = (byte*)value.nativeEntry; + nativeSizeOfCode = value.nativeSizeOfCode; + result = (CorJitResult)value.CorJitResult; + } + + // Message logging is disabled. + public void recMessageLog(string message) + { + } + + public void recReportInliningDecision(CORINFO_METHOD_STRUCT_* inlinerHnd, CORINFO_METHOD_STRUCT_* inlineeHnd, CorInfoInline inlineResult, byte* reason) + { + ReportInliningDecision ??= new DenseLightWeightMap(); + ReportInliningDecision.Append(new Agnostic_ReportInliningDecision + { + inlinerHnd = CastHandle(inlinerHnd), + inlineeHnd = CastHandle(inlineeHnd), + inlineResult = (uint)inlineResult, + reason_offset = reason != null ? ReportInliningDecision.AddBuffer(CString(reason)) : uint.MaxValue, + }); + } + + public CorInfoInline repReportInliningDecision(CORINFO_METHOD_STRUCT_* inlinerHnd, CORINFO_METHOD_STRUCT_* inlineeHnd) + { + CorInfoInline result = CorInfoInline.INLINE_FAIL; + if (ReportInliningDecision != null) + { + foreach (Agnostic_ReportInliningDecision item in ReportInliningDecision.GetRawItems()) + { + if (item.inlinerHnd == CastHandle(inlinerHnd) && item.inlineeHnd == CastHandle(inlineeHnd) && item.inlineResult == (uint)CorInfoInline.INLINE_PASS) + result = CorInfoInline.INLINE_PASS; + } + } + return result; + } + + public void recSetEHcount(uint cEH) + { + SetEHcount ??= new LightWeightMap(); + SetEHcount.Add(0, cEH); + } + + public uint repSetEHcount() + { + SetEHcount ??= new LightWeightMap(); + int index = SetEHcount.GetIndex(0); + return index < 0 ? 0 : SetEHcount.GetItem(index); + } + + public void recSetEHinfo(uint EHnumber, CORINFO_EH_CLAUSE* clause) + { + SetEHinfo ??= new LightWeightMap(); + SetEHinfo.Add(EHnumber, new Agnostic_CORINFO_EH_CLAUSE + { + Flags = (uint)clause->Flags, + TryOffset = clause->TryOffset, + TryLength = clause->TryLength, + HandlerOffset = clause->HandlerOffset, + HandlerLength = clause->HandlerLength, + ClassToken = clause->ClassTokenOrOffset, + }); + } + + public Agnostic_CORINFO_EH_CLAUSE repSetEHinfo(uint EHnumber) => SetEHinfo.Get(EHnumber); + + public void recSetMethodAttribs(CORINFO_METHOD_STRUCT_* ftn, CorInfoMethodRuntimeFlags attribs) + { + SetMethodAttribs ??= new LightWeightMap(); + int index = SetMethodAttribs.GetIndex(CastHandle(ftn)); + if (index == -1) + SetMethodAttribs.Add(CastHandle(ftn), (uint)attribs); + else + SetMethodAttribs.Update(index, SetMethodAttribs.GetItem(index) | (uint)attribs); + } + + public CorInfoMethodRuntimeFlags repSetMethodAttribs(CORINFO_METHOD_STRUCT_* ftn) + { + int index = SetMethodAttribs?.GetIndex(CastHandle(ftn)) ?? -1; + return index == -1 ? 0 : (CorInfoMethodRuntimeFlags)SetMethodAttribs.GetItem(index); + } + + public void recReportTailCallDecision(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* calleeHnd, bool fIsTailPrefix, + CorInfoTailCall tailCallResult, byte* reason) + { + ReportTailCallDecision ??= new DenseLightWeightMap(); + ReportTailCallDecision.Append(new Agnostic_ReportTailCallDecision + { + callerHnd = CastHandle(callerHnd), + calleeHnd = CastHandle(calleeHnd), + fIsTailPrefix = fIsTailPrefix ? 1u : 0u, + tailCallResult = (uint)tailCallResult, + reason_index = reason != null ? ReportTailCallDecision.AddBuffer(CString(reason)) : uint.MaxValue, + }); + } + + public void recReportFatalError(CorJitResult result) + { + ReportFatalError ??= new DenseLightWeightMap(); + ReportFatalError.Append((uint)result); + } + + public void recRecordRelocation(void* location, void* target, CorInfoReloc fRelocType, int addlDelta) + => repRecordRelocation(location, target, fRelocType, addlDelta); + + public void repRecordRelocation(void* location, void* target, CorInfoReloc fRelocType, int addlDelta) + { + RecordRelocation ??= new DenseLightWeightMap(); + RecordRelocation.Append(new Agnostic_RecordRelocation + { + location = CastHandle(location), + target = CastHandle(target), + fRelocType = (uint)fRelocType, + addlDelta = (uint)addlDelta, + }); + } + + // A replay replaces the recorded CompileResult. Usually the collection has also been "thinned" (by + // "mcs -removeDup -thin"), which removes the CompileResult, so the original addresses are lost. + // + // The generated code may still depend on the original relative addresses. For example, a relocation + // based on the result of GetFunctionEntryPoint may have fit in a rel32 delta, or, if it didn't fit, + // the VM may have returned a jump stub in the JIT code section that does fit. + // + // Ideally, the original addresses and relocations would be kept even if the CompileResult is deleted; + // then a new relocation with the same target as an original one could reuse the original delta. + // + // For now, a rel32 relocation that doesn't fit gets an address immediately after the current section + // (using originalAddr), assuming a jump stub was needed. Multiple calls to potentially different + // functions can share the address, since even if they had used different ones, no textual diffs would + // appear: most of the textual call names are "hackishMethodName". + public void applyRelocs(ref RelocContext rc, byte* block1, uint blocksize1, void* originalAddr) + { + if (RecordRelocation == null || blocksize1 == 0) + return; + + // For wasm32, the JIT writes padded ULEB128/SLEB128 placeholders (PADDED_RELOC_SIZE bytes of + // `80 80 ... 80 00` that decode to zero) in place of the real handle at every reloc site. Both + // baseline and diff JITs write the same placeholder bytes, so the byte-by-byte comparison succeeds + // at reloc sites without any patching here. The near differ validates reloc-target equivalence via + // compareOffsetsWasm when the surrounding immediate bytes happen to differ. + if (GetSpmiTargetArchitecture() == TargetArchitecture.Wasm32) + return; + + nuint section_begin = (nuint)block1; + nuint section_end = (nuint)block1 + blocksize1; // address is exclusive + + Logger.LogDebug(CFormat.Sprintf("applyRelocs block [%p,%p) block size %u, orig addr %p", (ulong)block1, (ulong)(block1 + blocksize1), blocksize1, CastHandle(originalAddr))); + + ReadOnlySpan relocations = RecordRelocation.GetRawItems(); + for (int i = 0; i < relocations.Length; i++) + { + Agnostic_RecordRelocation tmp = relocations[i]; + + if (Logger.IsEnabled(LogLevel.Debug)) + { + Logger.Out.Write(" "); + dmpRecordRelocation((uint)i, tmp); + Logger.Out.Write("\n"); + } + + TargetArchitecture targetArch = GetSpmiTargetArchitecture(); + var relocType = (CorInfoReloc)tmp.fRelocType; + bool wasRelocHandled = false; + ulong fixupLocation = tmp.location; + nuint address = section_begin + (nuint)fixupLocation - (nuint)originalAddr; + bool inSection = section_begin <= address && address < section_end; // A reloc for our section? + + // Do platform specific relocations first. + + if (targetArch is TargetArchitecture.X86 or TargetArchitecture.ARM && relocType == CorInfoReloc.DIRECT) + { + if (inSection) + { + Logger.LogDebug(CFormat.Sprintf(" fixupLoc-%016llX (@%p) : %08X => %08X", fixupLocation, (ulong)address, *(uint*)address, (uint)tmp.target)); + *(uint*)address = (uint)tmp.target; + } + wasRelocHandled = true; + } + + if (targetArch == TargetArchitecture.ARM) + { + switch (relocType) + { + case CorInfoReloc.ARM32_THUMB_MOV32: + case CorInfoReloc.ARM32_THUMB_MOV32_PCREL: + if (inSection) + PutThumb2Mov32((ushort*)address, (uint)(int)(tmp.target - fixupLocation)); + wasRelocHandled = true; + break; + + case CorInfoReloc.ARM32_THUMB_BRANCH24: + if (inSection) + { + // Like the arm64 ARM64_BRANCH26 and x64 RELATIVE32 handling, hardcode the bottom bits + // of the target into the instruction, so the encoding doesn't depend on where SuperPMI + // allocated the code buffer. Otherwise a BL whose target is out of the +-16MB range for + // one of the two compared blocks would get a buffer-dependent placeholder, producing + // spurious asm diffs. + ulong target = tmp.target + (ulong)(long)(int)tmp.addlDelta; + PutThumb2BlRel24((ushort*)address, (int)(target & 0x00FFFFFE)); + } + wasRelocHandled = true; + break; + } + } + + if (targetArch == TargetArchitecture.ARM64) + { + ulong target = tmp.target + (ulong)(long)(int)tmp.addlDelta; + if (relocType is CorInfoReloc.ARM64_PAGEBASE_REL21 or CorInfoReloc.ARM64_LIN_TLSDESC_ADR_PAGE21 or + CorInfoReloc.ARM64_PAGEOFFSET_12A or CorInfoReloc.ARM64_PAGEOFFSET_12L) + { + // Is the target in the RO data section? + if (rc.originalRoDataAddress2 <= (nuint)target && (nuint)target < rc.originalRoDataAddress2 + rc.roDataSize2) + { + nuint ro_section_offset = (nuint)target - rc.originalRoDataAddress2; + if (rc.originalHotCodeAddress <= (nuint)fixupLocation && (nuint)fixupLocation < rc.originalHotCodeAddress + rc.hotCodeSize) + { + // The fixup location is in the hot section. + target = rc.originalHotCodeAddress + rc.hotCodeSize + ro_section_offset - fixupLocation; + } + else if (rc.originalColdCodeAddress <= (nuint)fixupLocation && (nuint)fixupLocation < rc.originalColdCodeAddress + rc.coldCodeSize) + { + // The fixup location is in the cold section. + target = rc.originalColdCodeAddress + rc.coldCodeSize + ro_section_offset - fixupLocation; + } + } + } + + switch (relocType) + { + case CorInfoReloc.ARM64_BRANCH26: // 26 bit offset << 2 & sign ext, for B and BL + // Like x64's IMAGE_REL_BASED_REL32 handling, hardcode the bottom bits of the target + // into the instruction. + if (inSection) + PutArm64Rel28((uint*)address, (int)target); + wasRelocHandled = true; + break; + + case CorInfoReloc.ARM64_PAGEBASE_REL21: // ADRP 21 bit PC-relative page address + case CorInfoReloc.ARM64_LIN_TLSDESC_ADR_PAGE21: // ADRP 21 bit for TLSDesc + if (inSection) + { + // The page delta is deliberately (target page - target page): the ADRP immediates of the two + // compilations being diffed then don't differ. + long targetPage = (long)target & unchecked((long)0xFFFFFFFFFFFFF000); + long pageDelta = targetPage - targetPage; + PutArm64Rel21((uint*)address, (int)(pageDelta >> 12) & 0x1FFFFF); + } + wasRelocHandled = true; + break; + + case CorInfoReloc.ARM64_PAGEOFFSET_12A: // ADD 12 bit page offset + if (inSection) + PutArm64Rel12((uint*)address, (int)(nuint)target & 0xFFF); + wasRelocHandled = true; + break; + + case CorInfoReloc.ARM64_PAGEOFFSET_12L: // LDR 12 bit page offset + if (inSection) + PutArm64Rel12Ldr((uint*)address, (int)(nuint)target & 0xFFF); + wasRelocHandled = true; + break; + + case CorInfoReloc.ARM64_WIN_TLS_SECREL_HIGH12A: // TLSDESC ADD for High-12 Add + case CorInfoReloc.ARM64_WIN_TLS_SECREL_LOW12A: // TLSDESC ADD for Low-12 Add + case CorInfoReloc.ARM64_LIN_TLSDESC_LD64_LO12: + case CorInfoReloc.ARM64_LIN_TLSDESC_ADD_LO12: // TLSDESC ADD for corresponding ADRP + case CorInfoReloc.ARM64_LIN_TLSDESC_CALL: + // These are patched later by the linker during actual execution, and don't need relocation. + wasRelocHandled = true; + break; + } + } + + if (targetArch == TargetArchitecture.RiscV64 && + relocType is CorInfoReloc.RISCV64_CALL_PLT or CorInfoReloc.RISCV64_PCREL_I or CorInfoReloc.RISCV64_PCREL_S) + { + if (inSection) + { + // Like x64's IMAGE_REL_BASED_REL32 handling, hardcode the bottom bits of the target into the + // instruction. + long offset = (long)tmp.target; + int lo12 = (int)((offset << (64 - 12)) >> (64 - 12)); + int hi20 = (int)(offset - lo12); + PutRiscV64AuipcCombo((uint*)address, (long)lo12 + hi20, relocType == CorInfoReloc.RISCV64_PCREL_S); + } + wasRelocHandled = true; + } + + if (IsSpmiTarget64Bit()) + { + if (!wasRelocHandled && relocType == CorInfoReloc.DIRECT) + { + // Write 64 bits into the location. + if (inSection) + { + Logger.LogDebug(CFormat.Sprintf(" fixupLoc-%016llX (@%p) %016llX => %016llX", fixupLocation, (ulong)address, *(ulong*)address, tmp.target)); + *(ulong*)address = tmp.target; + } + wasRelocHandled = true; + } + else if (relocType == CorInfoReloc.AMD64_LIN_TLSGD) + { + // These are patched later by the linker during actual execution, and don't need relocation. + wasRelocHandled = true; + } + } + + if (wasRelocHandled) + continue; + + // Now do all-platform relocations. + if (relocType is CorInfoReloc.RELATIVE32 or CorInfoReloc.AMD64_WIN_SECREL) + { + if (inSection) + ApplyRelative32(ref rc, tmp, address, fixupLocation, blocksize1, originalAddr); + wasRelocHandled = true; + } + + if (!wasRelocHandled) + Logger.LogError($"Unknown reloc type {tmp.fRelocType}"); + } + } + + private static void ApplyRelative32(ref RelocContext rc, in Agnostic_RecordRelocation tmp, nuint address, ulong fixupLocation, uint blocksize1, void* originalAddr) + { + ulong target = tmp.target + (ulong)(long)(int)tmp.addlDelta; + ulong baseAddr = fixupLocation + sizeof(int); + long delta = (long)(target - baseAddr); + bool deltaIsFinal = false; + MethodContext mc = rc.mc; + + if (IsSpmiTarget64Bit()) + { + if (GetSpmiTargetArchitecture() == TargetArchitecture.X64 && mc.GetRelocTypeHint != null) + { + // For just AMD64: the VM tries to allocate the JIT code buffer near the CLR assemblies, so that + // 32-bit offsets (and RELATIVE32 relocations) can be used in the code. If a RELATIVE32 + // relocation doesn't fit, the VM throws away the JIT result, disables RELATIVE32 relocations, + // and restarts the compilation. SuperPMI doesn't know where the original compilation was + // allocated (though maybe that should be added to the MC, not just the CompileResult), and + // doesn't control where the JIT buffer is allocated. So if getRelocTypeHint() was called on + // the target address and returned IMAGE_REL_BASED_REL32, use the low-order 32 bits of the + // target address. That's unique enough for assembly diffs: the delta compares identically and + // doesn't depend on where SuperPMI allocated the JIT memory. + int index = mc.GetRelocTypeHint.GetIndex(tmp.target); + if (index != -1 && (CorInfoReloc)mc.GetRelocTypeHint.GetItem(index) == CorInfoReloc.RELATIVE32) + { + Logger.LogDebug(CFormat.Sprintf(" RELATIVE32 target used as argument to getRelocTypeHint: setting delta=%d (0x%X)", (ulong)(long)(int)tmp.target, (uint)tmp.target)); + delta = (int)tmp.target; + deltaIsFinal = true; + } + } + + // If the target is the result of getHelperFtn(), the VM would create a jump stub if the RELATIVE32 + // address doesn't fit. Don't fail with a RELATIVE32 overflow if the actual target address doesn't + // fit: use its low-order 32 bits. The whole table is searched, since the helper id isn't known. + if (!deltaIsFinal && mc.GetHelperFtn != null) + { + foreach (Agnostic_GetHelperFtn value in mc.GetHelperFtn.GetRawItems()) + { + if (value.helperLookup.handle == tmp.target) + { + Logger.LogDebug(CFormat.Sprintf(" RELATIVE32 target is result of getHelperFtn(): setting delta=%d (0x%X)", (ulong)(long)(int)tmp.target, (uint)tmp.target)); + delta = (int)tmp.target; + deltaIsFinal = true; + break; + } + } + } + + // Likewise for results of GetFunctionEntryPoint(). + if (!deltaIsFinal && mc.GetFunctionEntryPoint != null) + { + foreach (DLD value in mc.GetFunctionEntryPoint.GetRawItems()) + { + if (value.A == tmp.target) + { + Logger.LogDebug(CFormat.Sprintf(" RELATIVE32 target is result of getFunctionEntryPoint(): setting delta=%d (0x%X)", (ulong)(long)(int)tmp.target, (uint)tmp.target)); + delta = (int)tmp.target; + deltaIsFinal = true; + break; + } + } + } + + // A relocation to the RO data section must fit in 32 bits for both the baseline and diff + // compilations, so pretend the RO data section immediately follows the current code section. + if (!deltaIsFinal && rc.originalRoDataAddress1 <= (nuint)target && (nuint)target < rc.originalRoDataAddress1 + rc.roDataSize1) + { + nuint ro_section_offset = (nuint)target - rc.originalRoDataAddress1; + if (rc.originalHotCodeAddress <= (nuint)fixupLocation && (nuint)fixupLocation < rc.originalHotCodeAddress + rc.hotCodeSize) + { + delta = (long)(rc.originalHotCodeAddress + rc.hotCodeSize + ro_section_offset - baseAddr); + deltaIsFinal = true; + Logger.LogDebug(CFormat.Sprintf(" RELATIVE32 hot code target is in RO data section: setting delta=%d (0x%X)", (ulong)delta, (ulong)delta)); + } + else if (rc.originalColdCodeAddress <= (nuint)fixupLocation && (nuint)fixupLocation < rc.originalColdCodeAddress + rc.coldCodeSize) + { + delta = (long)(rc.originalColdCodeAddress + rc.coldCodeSize + ro_section_offset - baseAddr); + deltaIsFinal = true; + Logger.LogDebug(CFormat.Sprintf(" RELATIVE32 cold code target is in RO data section: setting delta=%d (0x%X)", (ulong)delta, (ulong)delta)); + } + } + + if (delta != (int)delta) + { + // This won't fit in a signed 32-bit offset. Use something that fits, assuming the original + // compilation fit fine. This is only an issue for 32-bit offsets on 64-bit targets. + target = CastHandle(originalAddr) + blocksize1; + long newdelta = (long)(target - baseAddr); + Logger.LogDebug(CFormat.Sprintf(" RELATIVE32 overflow. Mapping target to %016llX. Mapping delta: %016llX => %016llX", target, (ulong)delta, (ulong)newdelta)); + delta = newdelta; + } + } + + if (IsSpmiTarget32Bit()) + { + // Only 32 bits matter, regardless of sign. Note that SuperPMI sometimes returns arbitrary values, + // such as 0xCAFE0003 from MethodContext::repGetHelperFtn(). + delta &= 0xFFFFFFFF; + } + else if (delta != (int)delta) + { + Logger.LogError(CFormat.Sprintf("RELATIVE32 relocation overflows field! delta=0x%016llX", (ulong)delta)); + } + + if (GetSpmiTargetArchitecture() == TargetArchitecture.X64 && !deltaIsFinal) + { + // During an actual compile, recordRelocation() is called before the compile is finished, and it + // writes the relative offset into the fixup location. Then emitEndCodeGen() patches forward jumps + // by subtracting any adjustment due to overestimated instruction sizes. Since the relocs are + // applied after the compile has finished, reverse that: add in the (negative) adjustment that's + // now in the fixup location. + delta += *(int*)address; + } + + // Write 32 bits into the location. + Logger.LogDebug(CFormat.Sprintf(" fixupLoc-%016llX (@%p) : %08X => %08X", fixupLocation, (ulong)address, *(uint*)address, (ulong)delta)); + *(uint*)address = (uint)delta; + } + + // Finds the recorded relocation (if any) whose location is in [originalBufferStart + originalBufferOffset, + // + windowSize). The wasm32 near differ uses this to map a coredistools opcode-byte block offset to a + // JIT-recorded reloc on the immediate-payload byte. + public bool findRelocationInRange(nuint originalBufferStart, nuint originalBufferOffset, nuint windowSize, out Agnostic_RecordRelocation relocation) + { + relocation = default; + if (RecordRelocation == null || windowSize == 0) + return false; + + nuint rangeLo = originalBufferStart + originalBufferOffset; + nuint rangeHi = rangeLo + windowSize; + + // Guard against wraparound (rangeLo near SIZE_MAX), rather than scanning an inverted range that could + // match unrelated relocs. + if (rangeHi < rangeLo) + return false; + + foreach (Agnostic_RecordRelocation item in RecordRelocation.GetRawItems()) + { + if (rangeLo <= (nuint)item.location && (nuint)item.location < rangeHi) + { + relocation = item; + return true; + } + } + return false; + } + + public void recProcessName(string name) + { + ProcessName ??= new DenseLightWeightMap(); + ProcessName.Append(name != null ? ProcessName.AddBuffer(CStringBytes(name)) : uint.MaxValue); + } + + public void recReserveUnwindInfo(bool isFunclet, bool isColdCode, uint unwindSize) + { + ReserveUnwindInfo ??= new DenseLightWeightMap(); + ReserveUnwindInfo.Append(new Agnostic_ReserveUnwindInfo { isFunclet = isFunclet ? 1u : 0u, isColdCode = isColdCode ? 1u : 0u, unwindSize = unwindSize }); + } + + public void recAllocUnwindInfo(byte* pHotCode, byte* pColdCode, uint startOffset, uint endOffset, uint unwindSize, byte* pUnwindBlock, CorJitFuncKind funcKind) + { + AllocUnwindInfo ??= new DenseLightWeightMap(); + AllocUnwindInfo.Append(new Agnostic_AllocUnwindInfo + { + pHotCode = CastHandle(pHotCode), + pColdCode = CastHandle(pColdCode), + startOffset = startOffset, + endOffset = endOffset, + unwindSize = unwindSize, + pUnwindBlock_index = AllocUnwindInfo.AddBuffer(Bytes(pUnwindBlock, unwindSize)), + funcKind = (uint)funcKind, + }); + } + + public void recRecordCallSite(uint instrOffset, CORINFO_SIG_INFO* callSig, CORINFO_METHOD_STRUCT_* methodHandle) + => repRecordCallSite(instrOffset, callSig, methodHandle); + + public void repRecordCallSite(uint instrOffset, CORINFO_SIG_INFO* callSig, CORINFO_METHOD_STRUCT_* methodHandle) + { + if (RecordCallSiteWithSignature == null) + { + // Most call site records only have methodHandle, so two separate maps give better performance and + // smaller memory use. These maps aren't read during a normal replay. + RecordCallSiteWithSignature = new LightWeightMap(); + if (recordCallSitesWithoutSig) + RecordCallSiteWithoutSignature = new LightWeightMap(); + } + + if (callSig != null) + { + DenseLightWeightMap handleMap = CrSigInstHandleMap; + Agnostic_CORINFO_SIG_INFO sig = StoreAgnostic_CORINFO_SIG_INFO(*callSig, RecordCallSiteWithSignature, ref handleMap); + CrSigInstHandleMap = handleMap; + RecordCallSiteWithSignature.Add(instrOffset, new Agnostic_RecordCallSite { callSig = sig, methodHandle = CastHandle(methodHandle) }); + } + else if (recordCallSitesWithoutSig) + { + RecordCallSiteWithoutSignature.Add(instrOffset, CastHandle(methodHandle)); + } + } + + public bool fndRecordCallSiteSigInfo(uint instrOffset, CORINFO_SIG_INFO* pCallSig) + { + if (RecordCallSiteWithSignature == null || RecordCallSiteWithSignature.GetIndex(instrOffset) == -1) + return false; + + Agnostic_RecordCallSite value = RecordCallSiteWithSignature.Get(instrOffset); + if (value.callSig.callConv == uint.MaxValue) + return false; + + *pCallSig = Restore_CORINFO_SIG_INFO(value.callSig, RecordCallSiteWithSignature, CrSigInstHandleMap, MemoryTracker); + return true; + } + + public bool fndRecordCallSiteMethodHandle(uint instrOffset, CORINFO_METHOD_STRUCT_** pMethodHandle) + { + if (RecordCallSiteWithSignature != null && RecordCallSiteWithSignature.GetIndex(instrOffset) != -1) + *pMethodHandle = (CORINFO_METHOD_STRUCT_*)RecordCallSiteWithSignature.Get(instrOffset).methodHandle; + else if (RecordCallSiteWithoutSignature != null && RecordCallSiteWithoutSignature.GetIndex(instrOffset) != -1) + *pMethodHandle = (CORINFO_METHOD_STRUCT_*)RecordCallSiteWithoutSignature.Get(instrOffset); + return false; + } + + private static ReadOnlySpan Bytes(void* data, nuint length) => data == null ? default : new ReadOnlySpan(data, (int)length); + + private static ReadOnlySpan CString(byte* s) => new(s, System.Runtime.InteropServices.MemoryMarshal.CreateReadOnlySpanFromNullTerminated(s).Length + 1); + + private static byte[] CStringBytes(string s) + { + byte[] bytes = new byte[System.Text.Encoding.UTF8.GetByteCount(s) + 1]; + System.Text.Encoding.UTF8.GetBytes(s, bytes); + return bytes; + } +} diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CompileResult.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CompileResult.cs new file mode 100644 index 00000000000000..f2b6e6f6a701c0 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CompileResult.cs @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace SuperPmi; + +// What a compilation produced: code, GC info, relocations, and so on. +public sealed partial class CompileResult +{ + internal static readonly MapInfo[] s_mapByPacket; + + static CompileResult() + { + s_mapByPacket = MethodContext.BuildPacketTable(s_maps); + } + + internal LightWeightMapBuffer[] Maps => _maps; + + internal void SetMap(int index, LightWeightMapBuffer map) => _maps[index] = map; + + public bool IsEmpty() => Array.TrueForAll(_maps, map => map == null); + + public string repProcessName() + { + if (ProcessName == null) + return "hackishProcessName"; + + if (ProcessName.GetCount() > 0) + return ProcessName.GetString(ProcessName.Get(0)); + return null; + } +} diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/ErrorHandling.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/ErrorHandling.cs new file mode 100644 index 00000000000000..28f3c06eb9b288 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/ErrorHandling.cs @@ -0,0 +1,69 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Diagnostics.CodeAnalysis; + +namespace SuperPmi; + +public static class ExceptionCodes +{ + // DebugBreakorAV is the base of a range; each call site adds a unique number. + public const uint DebugBreakorAV = 0xe0421000; + public const uint DebugBreakorAV_MAX = 0xe0422000; + + public const uint MC = 0xe0422000; + public const uint LWM = 0xe0423000; + public const uint CALLUTILS = 0xe0426000; + public const uint TYPEUTILS = 0xe0427000; + + // Rethrows an exception that the EE threw during recording. Not an SPMI exception, and + // not a replay failure. + public const uint RECORDED_EXCEPTION = 0xe0428000; + public const uint ASSERT = 0xe0440000; + + public static bool IsSuperPMIException(uint code) => code switch + { + MC or LWM or CALLUTILS or TYPEUTILS or ASSERT => true, + _ => code >= DebugBreakorAV && code < DebugBreakorAV_MAX, + }; +} + +public sealed class SpmiException : Exception +{ + public SpmiException(uint code, string message) + : base(message) + { + Code = code; + } + + public uint Code { get; } +} + +public static class ErrorHandling +{ + [DoesNotReturn] + public static void LogException(uint code, string message) + { + Logger.LogExceptionMessage(code, message); + throw new SpmiException(code, message); + } + + public static void AssertCodeMsg([DoesNotReturnIf(false)] bool condition, uint code, string expr, string message) + { + if (!condition) + LogException(code, $"SuperPMI assertion '{expr}' failed ({message})"); + } + + public static void AssertCode([DoesNotReturnIf(false)] bool condition, uint code, string expr) + { + if (!condition) + LogException(code, $"SuperPMI assertion '{expr}' failed"); + } + + public static void AssertMsg([DoesNotReturnIf(false)] bool condition, string expr, string message) + => AssertCodeMsg(condition, ExceptionCodes.ASSERT, expr, message); + + // The error code of a failed file operation, as GetLastError() (or errno, for the common errors) reports it. + public static uint LastError(Exception e) => (uint)e.HResult & 0xFFFF; +} diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/Hash.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/Hash.cs new file mode 100644 index 00000000000000..aa463e8019cfaf --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/Hash.cs @@ -0,0 +1,84 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Buffers.Binary; +using System.Numerics; + +namespace SuperPmi; + +// MurmurHash3 (x64, 128-bit, seed 0), written by Austin Appleby and placed in the public domain. +// https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp +public static class Hash +{ + public const int MM3_HASH_BYTE_SIZE = 16; + public const int MM3_HASH_BUFFER_SIZE = 33; // 32 hex characters plus a null terminator + + private static ulong FMix64(ulong k) + { + k ^= k >> 33; + k *= 0xff51afd7ed558ccdUL; + k ^= k >> 33; + k *= 0xc4ceb9fe1a85ec53UL; + k ^= k >> 33; + return k; + } + + public static void MurmurHash3_128(ReadOnlySpan data, uint seed, Span output) + { + const ulong c1 = 0x87c37b91114253d5UL; + const ulong c2 = 0x4cf5ad432745937fUL; + + int nblocks = data.Length / MM3_HASH_BYTE_SIZE; + ulong h1 = seed; + ulong h2 = seed; + + for (int i = 0; i < nblocks; i++) + { + ulong k1 = BinaryPrimitives.ReadUInt64LittleEndian(data.Slice(i * 16)); + ulong k2 = BinaryPrimitives.ReadUInt64LittleEndian(data.Slice(i * 16 + 8)); + + k1 *= c1; k1 = BitOperations.RotateLeft(k1, 31); k1 *= c2; h1 ^= k1; + h1 = BitOperations.RotateLeft(h1, 27); h1 += h2; h1 = h1 * 5 + 0x52dce729; + k2 *= c2; k2 = BitOperations.RotateLeft(k2, 33); k2 *= c1; h2 ^= k2; + h2 = BitOperations.RotateLeft(h2, 31); h2 += h1; h2 = h2 * 5 + 0x38495ab5; + } + + ReadOnlySpan tail = data.Slice(nblocks * MM3_HASH_BYTE_SIZE); + ulong t1 = 0; + ulong t2 = 0; + for (int i = tail.Length - 1; i >= 8; i--) + t2 ^= (ulong)tail[i] << ((i - 8) * 8); + for (int i = Math.Min(tail.Length, 8) - 1; i >= 0; i--) + t1 ^= (ulong)tail[i] << (i * 8); + + if (tail.Length > 8) + { + t2 *= c2; t2 = BitOperations.RotateLeft(t2, 33); t2 *= c1; h2 ^= t2; + } + if (tail.Length > 0) + { + t1 *= c1; t1 = BitOperations.RotateLeft(t1, 31); t1 *= c2; h1 ^= t1; + } + + h1 ^= (ulong)data.Length; + h2 ^= (ulong)data.Length; + h1 += h2; + h2 += h1; + h1 = FMix64(h1); + h2 = FMix64(h2); + h1 += h2; + h2 += h1; + + BinaryPrimitives.WriteUInt64LittleEndian(output, h1); + BinaryPrimitives.WriteUInt64LittleEndian(output.Slice(8), h2); + } + + // Hashes 'data' and returns the 32-character upper-case hexadecimal text of the hash. + public static string HashBuffer(ReadOnlySpan data) + { + Span hash = stackalloc byte[MM3_HASH_BYTE_SIZE]; + MurmurHash3_128(data, 0, hash); + return Convert.ToHexString(hash); + } +} diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/JitEEVersion.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/JitEEVersion.cs new file mode 100644 index 00000000000000..e20c0433618d25 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/JitEEVersion.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.IO; + +namespace SuperPmi; + +// The JIT-EE version of src/coreclr/inc/jiteeversionguid.h (embedded as a resource, so the version is always the +// one of the JIT interface the tools are built with). +public static class JitEEVersion +{ + public static readonly Guid Identifier = Load(); + + private static Guid Load() + { + using Stream stream = typeof(JitEEVersion).Assembly.GetManifestResourceStream("jiteeversionguid.h"); + using var reader = new StreamReader(stream); + + // The line that superpmi.py parses too: constexpr GUID JITEEVersionIdentifier = { /* */ + const string Prefix = "constexpr GUID JITEEVersionIdentifier = { /* "; + while (reader.ReadLine() is string line) + { + if (line.StartsWith(Prefix, StringComparison.Ordinal)) + return Guid.Parse(line.AsSpan(Prefix.Length, 36)); + } + + throw new InvalidDataException("JITEEVersionIdentifier is missing from jiteeversionguid.h"); + } +} diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/JitFlagNames.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/JitFlagNames.cs new file mode 100644 index 00000000000000..22312f1a6660c5 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/JitFlagNames.cs @@ -0,0 +1,29 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// The names that the dumps print for the JIT flags (CorJitFlag) and the instruction sets of the host architecture. + +using System; +using System.Runtime.InteropServices; +using Internal.JitInterface; + +namespace SuperPmi; + +public static class JitFlagNames +{ + public static string CorJitFlagToString(uint flag) => Enum.GetName((CorJitFlag)flag) ?? ""; + + public static string InstructionSetToString(uint instructionSet) + { + string name = RuntimeInformation.ProcessArchitecture switch + { + Architecture.X64 => Enum.GetName((InstructionSet_X64)instructionSet), + Architecture.X86 => Enum.GetName((InstructionSet_X86)instructionSet), + Architecture.Arm64 => Enum.GetName((InstructionSet_ARM64)instructionSet), + Architecture.RiscV64 => Enum.GetName((InstructionSet_RiscV64)instructionSet), + Architecture.Wasm => Enum.GetName((InstructionSet_Wasm32)instructionSet), + _ => null, + }; + return name is null or nameof(InstructionSet.ILLEGAL) or nameof(InstructionSet.NONE) ? "UnknownInstructionSet" : name; + } +} diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/JitMetrics.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/JitMetrics.cs new file mode 100644 index 00000000000000..3aa379dc2b0ec5 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/JitMetrics.cs @@ -0,0 +1,108 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Text; + +namespace SuperPmi; + +// The metrics that the JIT reports through reportMetadata, as listed by src/coreclr/jit/jitmetadatalist.h +// (embedded as a resource, so new metrics don't need changes here). +public sealed unsafe class JitMetrics +{ + public enum MetricType + { + Int, + Int64, + Double, + } + + public readonly record struct Metric(string Name, byte[] Utf8Name, MetricType Type); + + public static readonly Metric[] All = Load(); + + // Doubles are stored as their bits. + private readonly long[] _values = new long[All.Length]; + + private static Metric[] Load() + { + using Stream stream = typeof(JitMetrics).Assembly.GetManifestResourceStream("jitmetadatalist.h"); + using var reader = new StreamReader(stream); + + const string Prefix = "JITMETADATAMETRIC("; + var metrics = new List(); + while (reader.ReadLine() is string line) + { + if (!line.StartsWith(Prefix, StringComparison.Ordinal)) + continue; + + string[] parts = line.Substring(Prefix.Length).Split(','); + string name = parts[0].Trim(); + MetricType type = parts[1].Trim() switch + { + "int" => MetricType.Int, + "int64_t" => MetricType.Int64, + "double" => MetricType.Double, + string other => throw new InvalidDataException($"Unknown JIT metric type '{other}' for {name}"), + }; + metrics.Add(new Metric(name, Encoding.UTF8.GetBytes(name), type)); + } + return metrics.ToArray(); + } + + // The JIT reports metrics in the order they're listed, so the search resumes where the previous one + // matched; in practice this matches on the first comparison. + public static int FindIndex(ReadOnlySpan name, ref int searchStart) + { + int index = searchStart; + for (int i = 0; i < All.Length; i++) + { + int candidate = index; + index = index + 1 == All.Length ? 0 : index + 1; + if (name.SequenceEqual(All[candidate].Utf8Name)) + { + searchStart = index; + return candidate; + } + } + return -1; + } + + // Stores the value if it has the metric's size. + public void Store(int index, void* value, nuint length) + { + switch (All[index].Type) + { + case MetricType.Int when length == sizeof(int): + _values[index] = *(int*)value; + break; + case MetricType.Int64 when length == sizeof(long): + case MetricType.Double when length == sizeof(double): + _values[index] = *(long*)value; + break; + } + } + + public double GetDouble(int index) => BitConverter.Int64BitsToDouble(_values[index]); + + public long GetInteger(int index) => _values[index]; + + // Formats the value as printf's "%d", "%lld", or "%f", as the details CSV has it. + public string Format(int index) => All[index].Type switch + { + MetricType.Double => FormatDouble(GetDouble(index)), + _ => _values[index].ToString(CultureInfo.InvariantCulture), + }; + + public static string FormatDouble(double value) + { + if (double.IsNaN(value)) + return double.IsNegative(value) ? "-nan" : "nan"; + if (double.IsInfinity(value)) + return value < 0 ? "-inf" : "inf"; + return value.ToString("F6", CultureInfo.InvariantCulture); + } +} diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/LightWeightMap.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/LightWeightMap.cs new file mode 100644 index 00000000000000..758aaad9e7c2c1 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/LightWeightMap.cs @@ -0,0 +1,539 @@ +// 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.Buffers.Binary; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SuperPmi; + +// Describes one map of a MethodContext or CompileResult: its packet, and how to create it. +public sealed class MapInfo +{ + private readonly Func _factory; + + public MapInfo(int index, string name, PacketId packet, Func factory) + { + Index = index; + Name = name; + Packet = packet; + _factory = factory; + } + + public int Index { get; } + public string Name { get; } + public PacketId Packet { get; } + + public LightWeightMapBuffer Create() => _factory(); +} + +// Dumps a map as a "name - count" line followed by one "index-" line per entry. +internal static class MapDumper +{ + public static void Dump(string name, LightWeightMap map, Action dmp) + where TKey : unmanaged + where TItem : unmanaged + { + if (map == null) + return; + + Logger.Out.Write($"{name} - {map.GetCount()}\n"); + for (int i = 0; i < map.GetCount(); i++) + { + Logger.Out.Write($"{i}-"); + dmp(map.GetRawKeys()[i], map.GetRawItems()[i]); + Logger.Out.Write("\n"); + } + } + + public static void Dump(string name, DenseLightWeightMap map, Action dmp) + where TItem : unmanaged + { + if (map == null) + return; + + Logger.Out.Write($"{name} - {map.GetCount()}\n"); + for (int i = 0; i < map.GetCount(); i++) + { + Logger.Out.Write($"{i}-"); + dmp((uint)i, map.GetRawItems()[i]); + Logger.Out.Write("\n"); + } + } +} + +// The raw buffer shared by all the maps. Each entry is stored as a 4-byte length followed by the data; +// the "offset" of an entry is the position of its data. +public abstract class LightWeightMapBuffer +{ + private const int LengthPrefixSize = sizeof(uint); + + protected byte[] buffer = []; + protected uint bufferLength; + private byte[] pinnedBuffer; + private List retiredPinnedBuffers; + private bool locked; + + public abstract uint GetCount(); + + public abstract uint CalculateArraySize(); + + public abstract void ReadFromArray(ReadOnlySpan rawData); + + public abstract uint DumpToArray(Span bytes); + + public uint AddBuffer(ReadOnlySpan buff, bool forceUnique = false) + { + if (buff.Length == 0) + return uint.MaxValue; + + int index = Contains(buff); + if (index != -1 && !forceUnique) + return (uint)index; + + if (locked) + Logger.LogError("Added item that extended the buffer after it was locked by a call to GetBuffer()"); + + Span entry = Grow((uint)buff.Length, out uint newOffset); + buff.CopyTo(entry); + return newOffset; + } + + // Reserves a zero-filled entry of the given length and returns its offset. + public uint CreateBuffer(uint len) + { + if (len == 0) + return uint.MaxValue; + + if (locked) + Logger.LogError("Added item that extended the buffer after it was locked by a call to GetBuffer()"); + + Grow(len, out uint newOffset); + return newOffset; + } + + private Span Grow(uint len, out uint dataOffset) + { + uint newLength = bufferLength + LengthPrefixSize + len; + if (newLength > buffer.Length) + Array.Resize(ref buffer, (int)Math.Max(newLength, Math.Min((long)buffer.Length * 2, Array.MaxLength))); + + BinaryPrimitives.WriteUInt32LittleEndian(buffer.AsSpan((int)bufferLength), len); + dataOffset = bufferLength + LengthPrefixSize; + bufferLength = newLength; + return buffer.AsSpan((int)dataOffset, (int)len); + } + + // Returns the buffer contents starting at 'offset' (to the end of the buffer), or an empty span + // for the "no buffer" offset (uint.MaxValue). + public ReadOnlySpan GetBuffer(uint offset) + { + if (offset == uint.MaxValue) + return default; + + if (offset >= bufferLength) + { + ErrorHandling.AssertCodeMsg(false, ExceptionCodes.LWM, "offset < bufferLength", + $"Hit offset bigger than bufferLength {offset} >= {bufferLength}"); + } + locked = true; + return buffer.AsSpan((int)offset, (int)(bufferLength - offset)); + } + + // A stable pointer to the buffer contents at 'offset', or null for the "no buffer" offset. The + // buffer is copied to a pinned array on first use, so the pointer is valid for the map's lifetime. + public unsafe byte* GetBufferPointer(uint offset) + { + if (GetBuffer(offset).IsEmpty) + return null; + + if (pinnedBuffer == null || pinnedBuffer.Length < bufferLength) + { + // Entries added after pinning get a new copy; the old one stays alive for earlier pointers. + if (pinnedBuffer != null) + (retiredPinnedBuffers ??= []).Add(pinnedBuffer); + pinnedBuffer = GC.AllocateUninitializedArray((int)bufferLength, pinned: true); + buffer.AsSpan(0, (int)bufferLength).CopyTo(pinnedBuffer); + } + return (byte*)Unsafe.AsPointer(ref pinnedBuffer[offset]); + } + + // Mutable access to a buffer entry, as used by the recorder to fill a CreateBuffer() entry. + public Span GetBufferForWrite(uint offset, uint length) => buffer.AsSpan((int)offset, (int)length); + + // Returns exactly the stored entry at 'offset', using its length prefix. + public ReadOnlySpan GetBufferEntry(uint offset) + { + ReadOnlySpan data = GetBuffer(offset); + if (data.IsEmpty) + return data; + + uint len = BinaryPrimitives.ReadUInt32LittleEndian(buffer.AsSpan((int)offset - LengthPrefixSize)); + return data.Slice(0, (int)len); + } + + // Returns the null-terminated string stored at 'offset', or null for the "no buffer" offset. + public string GetString(uint offset) + { + if (offset == uint.MaxValue) + return null; + + ReadOnlySpan data = GetBuffer(offset); + int nul = data.IndexOf((byte)0); + return System.Text.Encoding.UTF8.GetString(nul >= 0 ? data.Slice(0, nul) : data); + } + + public int Contains(ReadOnlySpan buff) + { + if (buff.Length == 0 || bufferLength == 0) + return -1; + + uint offset = 0; + while (offset + LengthPrefixSize + (uint)buff.Length <= bufferLength) + { + uint chunkLen = BinaryPrimitives.ReadUInt32LittleEndian(buffer.AsSpan((int)offset)); + if (chunkLen == (uint)buff.Length && + buffer.AsSpan((int)(offset + LengthPrefixSize), buff.Length).SequenceEqual(buff)) + { + return (int)(offset + LengthPrefixSize); + } + offset += LengthPrefixSize + chunkLen; + } + return -1; + } + + public void Unlock() => locked = false; + + protected void ForgetPinnedBuffers() + { + pinnedBuffer = null; + retiredPinnedBuffers = null; + } + + protected void ReadBuffer(ReadOnlySpan rawData, ref int ptr) + { + buffer = Take(rawData, ref ptr, (int)bufferLength).ToArray(); + } + + protected int WriteBuffer(Span bytes, int ptr) + { + buffer.AsSpan(0, (int)bufferLength).CopyTo(bytes.Slice(ptr)); + return ptr + (int)bufferLength; + } + + protected static uint ReadUInt32(ReadOnlySpan rawData, ref int ptr) + => BinaryPrimitives.ReadUInt32LittleEndian(Take(rawData, ref ptr, sizeof(uint))); + + protected static ReadOnlySpan Take(ReadOnlySpan rawData, ref int ptr, int length) + { + if (length < 0 || (long)ptr + length > rawData.Length) + { + ErrorHandling.AssertCodeMsg(false, ExceptionCodes.LWM, "ptr + length <= size", + $"Ran past the end of the map data {ptr + (long)length:x} > {rawData.Length:x}"); + } + ReadOnlySpan result = rawData.Slice(ptr, length); + ptr += length; + return result; + } + + protected static void CheckSize(int ptr, int size) + { + if (ptr != size) + { + ErrorHandling.AssertCodeMsg(false, ExceptionCodes.LWM, "(unsigned int)(ptr - rawData) == size", + $"Unknown type - Ended with unexpected sizes {ptr:x} != {size:x}"); + } + } + + protected static int ByteSize(uint count) where T : unmanaged => checked((int)count * Unsafe.SizeOf()); +} + +public sealed class LightWeightMap : LightWeightMapBuffer + where TKey : unmanaged + where TItem : unmanaged +{ + private static ReadOnlySpan Tag => "LWM1"u8; + + private uint numItems; + private TKey[] pKeys = []; + private TItem[] pItems = []; + + public override uint GetCount() => numItems; + + public override void ReadFromArray(ReadOnlySpan rawData) + { + int ptr = 0; + + // The tag is optional, to roll forward previous formats which don't have + // the tag, but which also have the same format. + if (rawData.StartsWith(Tag)) + ptr += Tag.Length; + + numItems = ReadUInt32(rawData, ref ptr); + if (numItems > 0) + { + bufferLength = ReadUInt32(rawData, ref ptr); + pKeys = MemoryMarshal.Cast(Take(rawData, ref ptr, ByteSize(numItems))).ToArray(); + pItems = MemoryMarshal.Cast(Take(rawData, ref ptr, ByteSize(numItems))).ToArray(); + ReadBuffer(rawData, ref ptr); + } + + CheckSize(ptr, rawData.Length); + } + + public override uint CalculateArraySize() + { + uint size = 4 /* tag */ + sizeof(uint) /* numItems */; + if (numItems > 0) + { + size += sizeof(uint); // size of bufferLength + size += (uint)ByteSize(numItems); // size of keyset + size += (uint)ByteSize(numItems); // size of itemset + size += bufferLength; // bulk size of raw buffer + } + return size; + } + + public override uint DumpToArray(Span bytes) + { + int ptr = 0; + Tag.CopyTo(bytes); + ptr += Tag.Length; + BinaryPrimitives.WriteUInt32LittleEndian(bytes.Slice(ptr), numItems); + ptr += sizeof(uint); + + if (numItems > 0) + { + BinaryPrimitives.WriteUInt32LittleEndian(bytes.Slice(ptr), bufferLength); + ptr += sizeof(uint); + ReadOnlySpan keys = MemoryMarshal.AsBytes(pKeys.AsSpan(0, (int)numItems)); + keys.CopyTo(bytes.Slice(ptr)); + ptr += keys.Length; + ReadOnlySpan items = MemoryMarshal.AsBytes(pItems.AsSpan(0, (int)numItems)); + items.CopyTo(bytes.Slice(ptr)); + ptr += items.Length; + ptr = WriteBuffer(bytes, ptr); + } + + return (uint)ptr; + } + + // Keys are kept sorted by memcmp() order of their bytes, so on a little-endian machine the + // lowest bits of an integer key sort first. Returns false if the key already exists. + public bool Add(TKey key, TItem item) + { + if (numItems == pKeys.Length) + { + int newSize = (pKeys.Length * 2) + 4; + Array.Resize(ref pKeys, newSize); + Array.Resize(ref pItems, newSize); + } + + int first = 0; + int last = (int)numItems - 1; + while (first <= last) + { + int mid = (first + last) / 2; + int res = Compare(in pKeys[mid], in key); + if (res < 0) + { + first = mid + 1; + } + else if (res > 0) + { + last = mid - 1; + } + else + { + if (!AsBytes(in pItems[mid]).SequenceEqual(AsBytes(in item))) + Logger.LogDebug("Tried to add a new value for an existing key, the new value was ignored"); + return false; + } + } + + int insert = first; + int countToMove = (int)numItems - insert; + Array.Copy(pKeys, insert, pKeys, insert + 1, countToMove); + Array.Copy(pItems, insert, pItems, insert + 1, countToMove); + pKeys[insert] = key; + pItems[insert] = item; + numItems++; + return true; + } + + public void Update(int index, TItem item) => pItems[index] = item; + + public int GetIndex(TKey key) + { + int first = 0; + int last = (int)numItems - 1; + while (first <= last) + { + int mid = (first + last) / 2; + int res = Compare(in pKeys[mid], in key); + if (res < 0) + first = mid + 1; + else if (res > 0) + last = mid - 1; + else + return mid; + } + return -1; + } + + public TItem GetItem(int index) + { + ErrorHandling.AssertCodeMsg(index != -1, ExceptionCodes.LWM, "index != -1", "Didn't find Key"); + return pItems[index]; + } + + public TKey GetKey(int index) + { + ErrorHandling.AssertCodeMsg(index != -1, ExceptionCodes.LWM, "index != -1", "Didn't find Key (in GetKey)"); + return pKeys[index]; + } + + public TItem Get(TKey key) + { + int index = GetIndex(key); + ErrorHandling.AssertCodeMsg(index != -1, ExceptionCodes.MC, "index != -1", "Didn't find Item (in Get)"); + return GetItem(index); + } + + public ReadOnlySpan GetRawKeys() => pKeys.AsSpan(0, (int)numItems); + + public ReadOnlySpan GetRawItems() => pItems.AsSpan(0, (int)numItems); + + public LightWeightMap Clone() + { + var copy = (LightWeightMap)MemberwiseClone(); + copy.pKeys = (TKey[])pKeys.Clone(); + copy.pItems = (TItem[])pItems.Clone(); + copy.buffer = (byte[])buffer.Clone(); + copy.ForgetPinnedBuffers(); + copy.Unlock(); + return copy; + } + + private static int Compare(in TKey a, in TKey b) => AsBytes(in a).SequenceCompareTo(AsBytes(in b)); + + private static ReadOnlySpan AsBytes(in T value) where T : unmanaged + => MemoryMarshal.AsBytes(new ReadOnlySpan(in value)); +} + +// A map whose keys are the indices [0 .. count - 1]. Keys are not stored. +public sealed class DenseLightWeightMap : LightWeightMapBuffer + where TItem : unmanaged +{ + private static ReadOnlySpan Tag => "DWM1"u8; + + private uint numItems; + private TItem[] pItems = []; + + public override uint GetCount() => numItems; + + public override void ReadFromArray(ReadOnlySpan rawData) + { + // If this is a v1 LWM, convert it to a DenseLightWeightMap. + if (!rawData.StartsWith(Tag)) + { + ReadFromArrayAndConvertLWM1(rawData); + return; + } + + int ptr = Tag.Length; + numItems = ReadUInt32(rawData, ref ptr); + if (numItems > 0) + { + bufferLength = ReadUInt32(rawData, ref ptr); + pItems = MemoryMarshal.Cast(Take(rawData, ref ptr, ByteSize(numItems))).ToArray(); + ReadBuffer(rawData, ref ptr); + } + + CheckSize(ptr, rawData.Length); + } + + private void ReadFromArrayAndConvertLWM1(ReadOnlySpan rawData) + { + int ptr = 0; + numItems = ReadUInt32(rawData, ref ptr); + if (numItems > 0) + { + bufferLength = ReadUInt32(rawData, ref ptr); + ReadOnlySpan keys = MemoryMarshal.Cast(Take(rawData, ref ptr, ByteSize(numItems))); + ReadOnlySpan items = MemoryMarshal.Cast(Take(rawData, ref ptr, ByteSize(numItems))); + ReadBuffer(rawData, ref ptr); + + var seen = new bool[numItems]; + pItems = new TItem[numItems]; + for (int index = 0; index < numItems; index++) + { + uint key = keys[index]; + if (key >= numItems) + ErrorHandling.AssertCodeMsg(false, ExceptionCodes.LWM, "key < numItems", $"Illegal key {key}, numItems == {numItems}"); + if (seen[key]) + ErrorHandling.AssertCodeMsg(false, ExceptionCodes.LWM, "!tKeySeen[key]", $"Duplicate key {key}"); + seen[key] = true; + pItems[key] = items[index]; + } + } + + CheckSize(ptr, rawData.Length); + } + + public override uint CalculateArraySize() + { + uint size = 4 /* tag */ + sizeof(uint) /* numItems */; + if (numItems > 0) + { + size += sizeof(uint); // size of bufferLength + size += (uint)ByteSize(numItems); // size of itemset + size += bufferLength; // bulk size of raw buffer + } + return size; + } + + public override uint DumpToArray(Span bytes) + { + int ptr = 0; + Tag.CopyTo(bytes); + ptr += Tag.Length; + BinaryPrimitives.WriteUInt32LittleEndian(bytes.Slice(ptr), numItems); + ptr += sizeof(uint); + + if (numItems > 0) + { + BinaryPrimitives.WriteUInt32LittleEndian(bytes.Slice(ptr), bufferLength); + ptr += sizeof(uint); + ReadOnlySpan items = MemoryMarshal.AsBytes(pItems.AsSpan(0, (int)numItems)); + items.CopyTo(bytes.Slice(ptr)); + ptr += items.Length; + ptr = WriteBuffer(bytes, ptr); + } + + return (uint)ptr; + } + + public bool Append(TItem item) + { + if (numItems == pItems.Length) + Array.Resize(ref pItems, (pItems.Length * 2) + 4); + + pItems[numItems++] = item; + return true; + } + + public int GetIndex(uint key) => key >= numItems ? -1 : (int)key; + + public TItem GetItem(int index) + { + ErrorHandling.AssertCodeMsg(index != -1, ExceptionCodes.LWM, "index != -1", "Didn't find Key"); + return pItems[index]; + } + + public TItem Get(uint key) => GetItem(GetIndex(key)); + + public ReadOnlySpan GetRawItems() => pItems.AsSpan(0, (int)numItems); +} diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/Logger.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/Logger.cs new file mode 100644 index 00000000000000..10fb87a1faa09f --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/Logger.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. + +using System; +using System.IO; +using System.Runtime.CompilerServices; +using System.Text; + +namespace SuperPmi; + +[Flags] +public enum LogLevel : uint +{ + None = 0, + Error = 0x01, // Internal fatal errors that are non-recoverable + Warning = 0x02, // Internal conditions that are unusual, but not serious + Missing = 0x04, // Failures due to missing JIT-EE details + Issue = 0x08, // Issues found with the JIT, e.g. asm diffs, asserts + Info = 0x10, // Notifications/summaries, e.g. 'Loaded 5 Jitted 4 FailedCompile 1' + Verbose = 0x20, // Status messages, e.g. 'Jit startup took 151.12ms' + Debug = 0x40, // Detailed output that's only useful for SuperPMI debugging + PassThroughStdout = 0x80, + PassThroughStderr = 0x100, + + Default = Debug - 1, // Everything except debug + All = 0xffffffff, +} + +// Console and log file output. stdout is buffered; Shutdown() (or Flush()) must be called before exiting. +public static class Logger +{ + private static readonly object s_lock = new object(); + private static LogLevel s_logLevel = LogLevel.Default; + private static FileStream s_logFile; + private static string s_logFilePath; + + public static TextWriter Out { get; } = ConsoleWriter(new StreamWriter(Console.OpenStandardOutput(), new UTF8Encoding(false), 1 << 16) { AutoFlush = false }); + public static TextWriter Error { get; } = ConsoleWriter(new StreamWriter(Console.OpenStandardError(), new UTF8Encoding(false)) { AutoFlush = true }); + + // stdout and stderr are in text mode, which writes "\n" as "\r\n" on Windows. + private static TextWriter ConsoleWriter(StreamWriter writer) + => OperatingSystem.IsWindows() ? new TextModeWriter(writer) : writer; + + private sealed class TextModeWriter : TextWriter + { + private readonly TextWriter _inner; + + public TextModeWriter(TextWriter inner) => _inner = inner; + + public override Encoding Encoding => _inner.Encoding; + + public override void Write(char value) + { + if (value == '\n') + _inner.Write('\r'); + _inner.Write(value); + } + + public override void Write(string value) => _inner.Write(value?.Replace("\n", "\r\n")); + + public override void Write(char[] buffer, int index, int count) => Write(new string(buffer, index, count)); + + public override void Flush() => _inner.Flush(); + } + + public static LogLevel GetLogLevel() => s_logLevel; + + public static void SetLogLevel(LogLevel level) => s_logLevel = level; + + public static void Flush() => Out.Flush(); + + public static void Shutdown() + { + Out.Flush(); + CloseLogFile(); + } + + public static void OpenLogFile(string logFilePath) + { + if (s_logFile != null || logFilePath == null) + return; + + try + { + s_logFile = new FileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read | FileShare.Delete); + s_logFilePath = logFilePath; + } + catch (Exception e) when (e is IOException or UnauthorizedAccessException) + { + Error.WriteLine($"WARNING: [Logger::OpenLogFile] Failed to open log file '{logFilePath}'. GetLastError()={ErrorHandling.LastError(e)}"); + } + } + + public static void CloseLogFile() + { + if (s_logFile == null) + return; + + bool empty = s_logFile.Length == 0; + s_logFile.Dispose(); + s_logFile = null; + + // Avoid polluting the file system with empty log files. + if (empty) + { + try + { + File.Delete(s_logFilePath); + } + catch (Exception e) when (e is IOException or UnauthorizedAccessException) + { + Error.WriteLine($"WARNING: [Logger::CloseLogFile] remove failed. GetLastError()={ErrorHandling.LastError(e)}"); + } + } + s_logFilePath = null; + } + + // Each character enables a level; 'q' (quiet) overrides everything, then 'a' (all). + public static LogLevel ParseLogLevelString(string specifier) + { + if (specifier.Contains('q')) + return LogLevel.None; + if (specifier.Contains('a')) + return LogLevel.All; + + LogLevel mask = LogLevel.None; + if (specifier.Contains('e')) mask |= LogLevel.Error; + if (specifier.Contains('w')) mask |= LogLevel.Warning; + if (specifier.Contains('m')) mask |= LogLevel.Missing; + if (specifier.Contains('i')) mask |= LogLevel.Issue; + if (specifier.Contains('n')) mask |= LogLevel.Info; + if (specifier.Contains('v')) mask |= LogLevel.Verbose; + if (specifier.Contains('d')) mask |= LogLevel.Debug; + return mask; + } + + public static void LogError(string msg, [CallerMemberName] string function = "", [CallerFilePath] string file = "", [CallerLineNumber] int line = 0) + => Log(LogLevel.Error, msg, function, file, line); + + public static void LogWarning(string msg, [CallerMemberName] string function = "", [CallerFilePath] string file = "", [CallerLineNumber] int line = 0) + => Log(LogLevel.Warning, msg, function, file, line); + + public static void LogMissing(string msg, [CallerMemberName] string function = "", [CallerFilePath] string file = "", [CallerLineNumber] int line = 0) + => Log(LogLevel.Missing, msg, function, file, line); + + public static void LogIssue(string msg, [CallerMemberName] string function = "", [CallerFilePath] string file = "", [CallerLineNumber] int line = 0) + => Log(LogLevel.Issue, msg, function, file, line); + + public static void LogInfo(string msg, [CallerMemberName] string function = "", [CallerFilePath] string file = "", [CallerLineNumber] int line = 0) + => Log(LogLevel.Info, msg, function, file, line); + + public static void LogVerbose(string msg, [CallerMemberName] string function = "", [CallerFilePath] string file = "", [CallerLineNumber] int line = 0) + => Log(LogLevel.Verbose, msg, function, file, line); + + public static void LogDebug(string msg, [CallerMemberName] string function = "", [CallerFilePath] string file = "", [CallerLineNumber] int line = 0) + => Log(LogLevel.Debug, msg, function, file, line); + + public static void LogPassThroughStdout(string msg) => Log(LogLevel.PassThroughStdout, msg, "", "", 0); + + public static void LogPassThroughStderr(string msg) => Log(LogLevel.PassThroughStderr, msg, "", "", 0); + + public static void LogExceptionMessage(uint code, string msg, [CallerMemberName] string function = "", [CallerFilePath] string file = "", [CallerLineNumber] int line = 0) + => Log(LogLevel.Debug, "Exception thrown: " + msg, function, file, line); + + public static bool IsEnabled(LogLevel level) + => level is LogLevel.PassThroughStdout or LogLevel.PassThroughStderr || (level & s_logLevel) != 0; + + public static void Log(LogLevel level, string msg, string function, string file, int line) + { + if (!IsEnabled(level)) + return; + + (string levelStr, bool toStderr) = level switch + { + LogLevel.Error => ("ERROR", true), + LogLevel.Warning => ("WARNING", true), + LogLevel.Missing => ("MISSING", false), + LogLevel.Issue => ("ISSUE", false), + LogLevel.Info => ("INFO", false), + LogLevel.Verbose => ("VERBOSE", false), + LogLevel.Debug => ("DEBUG", false), + LogLevel.PassThroughStdout => ("STDOUT", false), + LogLevel.PassThroughStderr => ("STDERR", true), + _ => ("INVALID_LOGLEVEL", false), + }; + + lock (s_lock) + { + TextWriter dest = toStderr ? Error : Out; + if (toStderr) + Out.Flush(); + + if (level < LogLevel.Info) + dest.Write(levelStr + ": "); + dest.Write(msg); + dest.Write('\n'); + + if (s_logFile != null) + { + string timeStr = OperatingSystem.IsWindows() ? DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") : ""; + byte[] entry = Encoding.UTF8.GetBytes($"{timeStr} - {function} [{Path.GetFileName(file)}:{line}] - {levelStr} - {msg}\r\n"); + s_logFile.Write(entry); + s_logFile.Flush(); + } + } + } +} diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MCList.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MCList.cs new file mode 100644 index 00000000000000..36919c7aefec1d --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MCList.cs @@ -0,0 +1,191 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace SuperPmi; + +// Lists of method context numbers: either a range list like "1-5,9" or a .mcl file with one number per line. +public sealed class MCList +{ + private const long MAXMCLFILESIZE = 0xffffff; + + private FileStream hMCLFile; + + // True if 'input' should be treated as a list rather than as a file name. + public static bool LooksLikeList(string input) + { + if (input.EndsWith(".mcl", StringComparison.OrdinalIgnoreCase)) + return true; + + foreach (char c in input) + { + if (c != '-' && c != ',' && !char.IsAsciiDigit(c)) + return false; + } + return input.Length > 0; + } + + // Parses a range list or reads an .mcl file. The numbers must start at 1 and be increasing. + // Input that is neither fails without an error message. + public static bool TryParse(string input, out int[] list, out string error) + { + list = null; + error = null; + + if (input.AsSpan().ContainsAnyExcept("0123456789-,")) + { + if (!input.EndsWith(".mcl", StringComparison.OrdinalIgnoreCase) || !getLineData(input, out list, out error)) + return false; + } + else if (!TryParseRangeList(input, out list, out error)) + { + return false; + } + + if (list.Length > 0 && list[0] == 0) + { + error = "MCL list needs to start from 1!"; + return false; + } + for (int i = 1; i < list.Length; i++) + { + if (list[i - 1] >= list[i]) + { + error = $"MCL list must be increasing.. found {list[i - 1]} -> {list[i]}"; + return false; + } + } + return true; + } + + private static bool TryParseRangeList(string input, out int[] list, out string error) + { + list = null; + error = null; + + var result = new List(); + bool inRange = false; + uint rangeStart = 0; + for (int head = 0; head <= input.Length; head++) + { + uint scratch = 0; + bool foundDigit = false; + while (head < input.Length && char.IsAsciiDigit(input[head])) + { + scratch = (scratch * 10) + (uint)(input[head] - '0'); + foundDigit = true; + head++; + } + if (foundDigit) + { + if (inRange) + { + inRange = false; + if (rangeStart >= scratch) + { + error = $"Invalid range in '{input}'"; + return false; + } + for (uint i = rangeStart + 1; i <= scratch; i++) + result.Add((int)i); + } + else + { + rangeStart = scratch; + result.Add((int)scratch); + } + } + if (head < input.Length && input[head] == '-') + inRange = true; + } + + if (result.Count == 0) + { + error = "Didn't find a list!"; + return false; + } + if (inRange) + { + error = $"Found invalid external range in '{input}'"; + return false; + } + + list = result.ToArray(); + return true; + } + + // Reads one number per line. Lines without digits are skipped. + public static bool getLineData(string nameOfInput, out int[] indexes, out string error) + { + indexes = null; + error = null; + byte[] buff; + try + { + long size = new FileInfo(nameOfInput).Length; + if (size > MAXMCLFILESIZE) + { + error = $"Size {size} exceeds max size of {MAXMCLFILESIZE}"; + return false; + } + buff = File.ReadAllBytes(nameOfInput); + } + catch (Exception e) when (e is IOException or UnauthorizedAccessException) + { + error = $"Unable to open '{nameOfInput}'. GetLastError()={ErrorHandling.LastError(e)}"; + return false; + } + + var result = new List(); + int i = 0; + while (i < buff.Length) + { + while (i < buff.Length && !char.IsAsciiDigit((char)buff[i])) + i++; + if (i >= buff.Length) + break; + + long value = 0; + while (i < buff.Length && char.IsAsciiDigit((char)buff[i])) + { + value = Math.Min(value * 10 + (buff[i] - '0'), int.MaxValue); + i++; + } + result.Add((int)value); + + while (i < buff.Length && buff[i] != '\n') + i++; + i++; + } + + indexes = result.ToArray(); + return true; + } + + public void InitializeMCL(string filename) + { + try + { + hMCLFile = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.Write); + } + catch (Exception e) when (e is IOException or UnauthorizedAccessException) + { + Logger.LogError($"Failed to open output file '{filename}'. GetLastError()={ErrorHandling.LastError(e)}"); + } + } + + public void AddMethodToMCL(int methodIndex) + { + hMCLFile?.Write(Encoding.ASCII.GetBytes($"{methodIndex}\r\n")); + } + + public void CloseMCL() + { + hMCLFile?.Dispose(); + hMCLFile = null; + } +} diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Dump.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Dump.cs new file mode 100644 index 00000000000000..76d696c41451b1 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Dump.cs @@ -0,0 +1,1004 @@ +// 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.Buffers.Binary; +using System.IO; +using System.Runtime.InteropServices; +using Internal.Pgo; +using static SuperPmi.DumpStrings; + +namespace SuperPmi; + +// Dumps each kind of recorded data, as mcs -dump prints it. +public sealed partial class MethodContext +{ + private static TextWriter Out => Logger.Out; + + private static uint U32(ReadOnlySpan data, int offset) => BinaryPrimitives.ReadUInt32LittleEndian(data.Slice(offset)); + + private static ulong U64(ReadOnlySpan data, int offset) => BinaryPrimitives.ReadUInt64LittleEndian(data.Slice(offset)); + + public void dmpGetClassAssemblyName(ulong key, uint value) + { + string assemblyName = GetClassAssemblyName.GetString(value); + CFormat.Printf(Out, "GetClassAssemblyName cls-%016llX, value-%u '%s'", key, value, assemblyName); + GetClassAssemblyName.Unlock(); + } + + public void dmpGetVars(ulong key, in Agnostic_GetVars value) + { + const int ILVarInfoSize = 12; // ICorDebugInfo::ILVarInfo: startOffset, endOffset, varNumber + ReadOnlySpan vars = GetVars.GetBuffer(value.vars_offset); + CFormat.Printf(Out, "GetVars key ftn-%016llX, value cVars-%u extendOthers-%u (", key, value.cVars, value.extendOthers); + for (uint i = 0; i < value.cVars; i++) + { + int at = (int)i * ILVarInfoSize; + CFormat.Printf(Out, "(%u %u %u %u)", i, U32(vars, at), U32(vars, at + 4), U32(vars, at + 8)); + } + Out.Write(")"); + GetVars.Unlock(); + } + + public void dmpGetBoundaries(ulong key, in Agnostic_GetBoundaries value) + { + CFormat.Printf(Out, "GetBoundaries key ftn-%016llX, value cnt-%u imp-%u{", key, value.cILOffsets, value.implicitBoundaries); + ReadOnlySpan bnd = GetBoundaries.GetBuffer(value.pILOffset_offset); + for (uint i = 0; i < value.cILOffsets; i++) + { + CFormat.Printf(Out, "%u", U32(bnd, (int)i * 4)); + // Every element is followed by a comma. + Out.Write(","); + } + GetBoundaries.Unlock(); + Out.Write("}"); + } + + public void dmpGetMethodNameFromMetadata(Agnostic_CORINFO_METHODNAME_TOKENin key, Agnostic_CORINFO_METHODNAME_TOKENout value) + { + string methodName = GetMethodNameFromMetadata.GetString(value.methodName); + string className = GetMethodNameFromMetadata.GetString(value.className); + string namespaceName = GetMethodNameFromMetadata.GetString(value.namespaceName); + ReadOnlySpan enclosingClassNameIndices = GetMethodNameFromMetadata.GetBuffer(value.enclosingClassNames); + CFormat.Printf(Out, "GetMethodNameFromMetadata key - ftn-%016llX classNonNull-%u namespaceNonNull-%u maxEnclosingClassNames-%u, value meth-'%s', class-'%s', namespace-'%s'", + key.ftn, key.className, key.namespaceName, key.maxEnclosingClassNames, methodName, className, namespaceName); + + for (uint i = 0; i < key.maxEnclosingClassNames; i++) + { + string enclosingClassName = GetMethodNameFromMetadata.GetString(U32(enclosingClassNameIndices, (int)i * 4)); + if (enclosingClassName != null) + CFormat.Printf(Out, " enclosingClass%u-'%s'", i, enclosingClassName); + } + + GetMethodNameFromMetadata.Unlock(); + } + + public void dmpGetJitFlags(uint key, DD value) + { + ReadOnlySpan jitflags = GetJitFlags.GetBuffer(value.A); + ulong flags = U64(jitflags, 0); + CFormat.Printf(Out, "GetJitFlags key %u sizeInBytes-%u jitFlags-%016llX instructionSetFlags-", key, value.B, flags); + + var isaFlags = new ulong[InstructionFlagsFieldCount]; + for (int i = 0; i < isaFlags.Length; i++) + isaFlags[i] = U64(jitflags, 8 * (i + 1)); + for (int i = isaFlags.Length - 1; i >= 0; i--) + CFormat.Printf(Out, "%016llX", isaFlags[i]); + + Out.Write(" ("); + for (uint flag = 0; flag < 64; flag++) + { + if ((flags & (1UL << (int)flag)) != 0) + CFormat.Printf(Out, " %s", JitFlagNames.CorJitFlagToString(flag)); + } + for (uint isa = 0; isa < 64 * isaFlags.Length; isa++) + { + if ((isaFlags[isa / 64] & (1UL << (int)(isa % 64))) != 0) + CFormat.Printf(Out, " %s", JitFlagNames.InstructionSetToString(isa)); + } + Out.Write(" )"); + GetJitFlags.Unlock(); + } + + public void dmpGetFieldInfo(in Agnostic_GetFieldInfo key, in Agnostic_CORINFO_FIELD_INFO value) + { + CFormat.Printf(Out, "GetFieldInfo key ch-%016llX flg-%08X rt{%s}", key.callerHandle, key.flags, + SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.ResolvedToken)); + + CFormat.Printf(Out, ", value fa-%u fflg-%08X hlp-%u off-%u fT-%u(%s) sT-%016llX aa-%u hnum-%u na-%u {", value.fieldAccessor, + value.fieldFlags, value.helper, value.offset, value.fieldType, toString_CorInfoType(value.fieldType), + value.structType, value.accessAllowed, value.accessCalloutHelper.helperNum, value.accessCalloutHelper.numArgs); + + for (int i = 0; i < 4; i++) + { + Agnostic_CORINFO_HELPER_ARG arg = value.accessCalloutHelper.args[i]; + string format = arg.argType switch + { + 1 => "{%u: fld-%016llX}", + 2 => "{%u: mth-%016llX}", + 3 => "{%u: cls-%016llX}", + 4 => "{%u: mod-%016llX}", + 5 => "{%u: const-%016llX}", + _ => null, + }; + if (format == null) + CFormat.Printf(Out, "{%u: illegal}", i); + else + CFormat.Printf(Out, format, i, arg.constant); + } + CFormat.Printf(Out, " fl %s}", SpmiDumpHelper.DumpAgnostic_CORINFO_CONST_LOOKUP(value.fieldLookup)); + } + + public void dmpGetClassGClayout(ulong key, in Agnostic_GetClassGClayout value) + { + CFormat.Printf(Out, "GetClassGCLayout key %016llX, value len %u cnt %u {", key, value.len, value.valCount); + if (value.gcPtrs_Index != uint.MaxValue) + { + ReadOnlySpan ptr = GetClassGClayout.GetBuffer(value.gcPtrs_Index); + for (uint i = 0; i < value.len; i++) + { + CFormat.Printf(Out, "0x%02x", ptr[(int)i]); + if (i + 1 < value.len) + Out.Write(","); + } + GetClassGClayout.Unlock(); + } + Out.Write("}"); + } + + public void dmpCanAccessClass(in Agnostic_CanAccessClassIn key, in Agnostic_CanAccessClassOut value) + { + CFormat.Printf(Out, "CanAccessClass key rt{%s}, callerHandle %016llX\n", + SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.ResolvedToken), key.callerHandle); + CFormat.Printf(Out, ", value hnum-%u na-%u {", value.AccessHelper.helperNum, value.AccessHelper.numArgs); + for (int i = 0; i < 4; i++) + CFormat.Printf(Out, "{%016llX %u}", value.AccessHelper.args[i].constant, value.AccessHelper.args[i].argType); + CFormat.Printf(Out, "} res-%u", value.result); + } + + public void dmpGetTypeLayout(ulong key, in Agnostic_GetTypeLayoutResult value) + { + CFormat.Printf(Out, "GetTypeLayout key type-%016llX value result=%d numNodes=%d", key, value.result, value.numNodes); + if (value.numNodes > 0) + { + ReadOnlySpan nodes = + MemoryMarshal.Cast(GetTypeLayout.GetBuffer(value.nodesBuffer)); + ulong index = 0; + dmpTypeLayoutTree(nodes, value.numNodes, ref index, 1); + } + } + + // Nodes are printed one after another on the same line. For partial layouts the field + // counts can describe more nodes than were recorded, which aren't printed. + public void dmpTypeLayoutTree(ReadOnlySpan nodes, ulong maxNodes, ref ulong index, ulong indent) + { + if (index >= (ulong)nodes.Length) + return; + + for (ulong i = 0; i < indent; i++) + Out.Write(" "); + + Agnostic_CORINFO_TYPE_LAYOUT_NODE node = nodes[(int)index]; + CFormat.Printf(Out, "%zu: parent %u offset %u size %u type %s numFields %u hasSignificantPadding %s simdTypeHnd %016llX diagFieldHnd %016llX", + index, node.parent, node.offset, node.size, toString_CorInfoType(node.type), node.numFields, + node.hasSignificantPadding != 0 ? "yes" : "no", node.simdTypeHnd, node.diagFieldHnd); + + index++; + for (ulong i = 0; i < node.numFields; i++) + { + if (i >= maxNodes) + break; + dmpTypeLayoutTree(nodes, maxNodes, ref index, indent + 1); + } + } + + private const int PgoSchemaSize = 24; // Agnostic_PgoInstrumentationSchema + + private static Agnostic_PgoInstrumentationSchema PgoSchemaAt(ReadOnlySpan schema, uint i) + => MemoryMarshal.Read(schema.Slice((int)i * PgoSchemaSize)); + + public void dmpAllocPgoInstrumentationBySchema(ulong key, in Agnostic_AllocPgoInstrumentationBySchema value) + { + CFormat.Printf(Out, "AllocPgoInstrumentationBySchema key ftn-%016llX, value res-%08X addr-%016llX cnt-%u schema{\n", + key, value.result, value.instrumentationDataAddress, value.countSchemaItems); + + if (value.countSchemaItems > 0) + { + ReadOnlySpan pBuf = AllocPgoInstrumentationBySchema.GetBuffer(value.schema_index); + Out.Write("\n"); + for (uint i = 0; i < value.countSchemaItems; i++) + { + Agnostic_PgoInstrumentationSchema s = PgoSchemaAt(pBuf, i); + CFormat.Printf(Out, " %u-{Offset %016llX ILOffset %u Kind %u(0x%x) Count %u Other %u}\n", + i, s.Offset, s.ILOffset, s.InstrumentationKind, s.InstrumentationKind, s.Count, s.Other); + } + AllocPgoInstrumentationBySchema.Unlock(); + } + Out.Write("}"); + } + + public void dmpGetPgoInstrumentationResults(ulong key, in Agnostic_GetPgoInstrumentationResults value) + { + CFormat.Printf(Out, "GetPgoInstrumentationResults key ftn-%016llX, value res-%08X schemaCnt-%u profileBufSize-%u source-%u dynamic-%u schema{", + key, value.result, value.countSchemaItems, value.dataByteCount, value.pgoSource, value.dynamicPgo); + + if (value.countSchemaItems > 0) + { + ReadOnlySpan pBuf = GetPgoInstrumentationResults.GetBuffer(value.schema_index); + ReadOnlySpan data = GetPgoInstrumentationResults.GetBuffer(value.data_index); + + Out.Write("\n"); + for (uint i = 0; i < value.countSchemaItems; i++) + { + Agnostic_PgoInstrumentationSchema s = PgoSchemaAt(pBuf, i); + CFormat.Printf(Out, " %u-{Offset %016llX ILOffset %u Kind %u(0x%x) Count %u Other %u Data ", + i, s.Offset, s.ILOffset, s.InstrumentationKind, s.InstrumentationKind, s.Count, s.Other); + + int at = (int)s.Offset; + switch ((PgoInstrumentationKind)s.InstrumentationKind) + { + case PgoInstrumentationKind.BasicBlockIntCount: + CFormat.Printf(Out, "B %u", U32(data, at)); + break; + case PgoInstrumentationKind.BasicBlockLongCount: + CFormat.Printf(Out, "B %llu", U64(data, at)); + break; + case PgoInstrumentationKind.EdgeIntCount: + CFormat.Printf(Out, "E %u", U32(data, at)); + break; + case PgoInstrumentationKind.EdgeLongCount: + CFormat.Printf(Out, "E %llu", U64(data, at)); + break; + case PgoInstrumentationKind.HandleHistogramIntCount: + CFormat.Printf(Out, "T %u", U32(data, at)); + break; + case PgoInstrumentationKind.HandleHistogramLongCount: + CFormat.Printf(Out, "T %llu", U64(data, at)); + break; + case PgoInstrumentationKind.HandleHistogramTypes: + case PgoInstrumentationKind.HandleHistogramMethods: + for (uint j = 0; j < s.Count; j++) + CFormat.Printf(Out, "[%u] %016llX ", j, ReadPointer(data, at + (int)j * IntPtr.Size)); + break; + case PgoInstrumentationKind.ValueHistogramIntCount: + CFormat.Printf(Out, "V %u", U32(data, at)); + break; + case PgoInstrumentationKind.ValueHistogramLongCount: + CFormat.Printf(Out, "V %llu", U64(data, at)); + break; + case PgoInstrumentationKind.ValueHistogram: + for (uint j = 0; j < s.Count; j++) + CFormat.Printf(Out, "[%u] %08X ", j, U32(data, at + (int)j * sizeof(uint))); + break; + case PgoInstrumentationKind.GetLikelyClass: + case PgoInstrumentationKind.GetLikelyMethod: + // (N)umber, (L)ikelihood, (H)andle + CFormat.Printf(Out, "N %u L %u H %016llX", s.Other >> 8, s.Other & 0xFF, ReadPointer(data, at)); + break; + default: + Out.Write("?"); + break; + } + + Out.Write("}\n"); + } + GetPgoInstrumentationResults.Unlock(); + } + CFormat.Printf(Out, "} data_index-%u", value.data_index); + } + + // Instrumentation data holds handles in the collecting host's pointer size. + private static ulong ReadPointer(ReadOnlySpan data, int offset) + => IntPtr.Size == 8 ? U64(data, offset) : U32(data, offset); + + public void dmpGetSystemVAmd64PassStructInRegisterDescriptor(ulong key, in Agnostic_GetSystemVAmd64PassStructInRegisterDescriptor value) + { + CFormat.Printf(Out, "GetSystemVAmd64PassStructInRegisterDescriptor key structHnd-%016llX, value passInReg-%u 8bCount-%u", key, + value.passedInRegisters, value.eightByteCount); + for (int i = 0; i < 2; i++) + { + CFormat.Printf(Out, " 8bClass[%u]-%u 8bSz[%u]-%u 8bOff[%u]-%u", i, value.eightByteClassifications[i], i, + value.eightByteSizes[i], i, value.eightByteOffsets[i]); + } + CFormat.Printf(Out, " result %u", value.result); + } + + public void dmpGetSwiftLowering(ulong key, in Agnostic_GetSwiftLowering value) + { + CFormat.Printf(Out, "GetSwiftLowering key structHnd-%016llX, value byReference-%u numLoweredElements-%u", key, + value.byReference, value.numLoweredElements); + if (value.byReference == 0) + { + for (int i = 0; i < value.numLoweredElements; i++) + CFormat.Printf(Out, " [%zu] %u", i, value.loweredElements[i]); + } + } + + public void dmpGetFpStructLowering(ulong key, in Agnostic_GetFpStructLowering value) + { + CFormat.Printf(Out, "GetFpStructLowering key structHnd-%016llX, value byIntegerCallConv-%u numLoweredElements-%u", key, + value.byIntegerCallConv, value.numLoweredElements); + if (value.byIntegerCallConv == 0) + { + for (int i = 0; i < value.numLoweredElements; i++) + CFormat.Printf(Out, " [%zu] %u", i, value.loweredElements[i]); + } + } + + public void dmpGetClassNameFromMetadata(DLD key, DD value) + { + string className = GetClassNameFromMetadata.GetString(value.A); + string namespaceName = GetClassNameFromMetadata.GetString(value.B); + CFormat.Printf(Out, "GetClassNameFromMetadata key - classNonNull-%llu namespaceNonNull-%u, value class-'%s', namespace-'%s'", + key.A, key.B, className, namespaceName); + GetClassNameFromMetadata.Unlock(); + } + + public void dmpPrint(string name, LightWeightMapBuffer buffer, ulong key, in Agnostic_PrintResult value) + { + CFormat.Printf(Out, "%s key hnd-%016llX, stringBufferSize-%u, requiredBufferSize-%u", name, key, value.stringBufferSize, value.requiredBufferSize); + buffer.Unlock(); + } + + public void dmpCheckMethodModifier(in Agnostic_CheckMethodModifier key, uint value) + { + CFormat.Printf(Out, "CheckMethodModifier key, ftn-%016llX mod-'%s' opt-%u, value res-%u", key.hMethod, + CheckMethodModifier.GetString(key.modifier), key.fOptional, value); + CheckMethodModifier.Unlock(); + } + + public void dmpGetIntConfigValue(in Agnostic_ConfigIntInfo key, uint value) + { + string name = GetIntConfigValue.GetString(key.nameIndex); + CFormat.Printf(Out, "GetIntConfigValue name %s, default value %d, value %d", name, key.defaultValue, value); + GetIntConfigValue.Unlock(); + } + + public void dmpGetStringConfigValue(uint nameIndex, uint resultIndex) + { + string name = GetStringConfigValue.GetString(nameIndex); + string result = GetStringConfigValue.GetString(resultIndex); + CFormat.Printf(Out, "GetStringConfigValue name %s, result %s", name, result); + GetStringConfigValue.Unlock(); + } + + public void dmpCompileMethod(uint key, in Agnostic_CompileMethod value) + => CFormat.Printf(Out, "CompileMethod key %u, value ftn-%016llX scp-%016llX ilo-%u ils-%u ms-%u ehc-%u opt-%u rk-%u args-%s locals-%s flg-%08X os-%u", + key, value.info.ftn, value.info.scope, value.info.ILCode_offset, value.info.ILCodeSize, value.info.maxStack, + value.info.EHcount, value.info.options, value.info.regionKind, + SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INFO(value.info.args, CompileMethod, SigInstHandleMap), + SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INFO(value.info.locals, CompileMethod, SigInstHandleMap), + value.flags, value.os); + + public void dmpGetMethodClass(ulong key, ulong value) + => CFormat.Printf(Out, "GetMethodClass key %016llX, value %016llX", key, value); + + public void dmpGetClassAttribs(ulong key, uint value) + => CFormat.Printf(Out, "GetClassAttribs key %016llX, value %08X (%s)", key, value, SpmiDumpHelper.DumpCorInfoFlag(value)); + + public void dmpIsIntrinsic(ulong key, uint value) + => CFormat.Printf(Out, "IsIntrinsic key ftn-%016llX, value res-%u", key, value); + + public void dmpNotifyMethodInfoUsage(ulong key, uint value) + => CFormat.Printf(Out, "NotifyMethodInfoUsage key ftn-%016llX, value res-%u", key, value); + + public void dmpNotifyInstructionSetUsage(DD key, uint value) + => CFormat.Printf(Out, "NotifyInstructionSetUsage key isa-%u, supported-%u, preserve-negative-dependency-%u, res-%u", + key.A, key.B & 1, (key.B >> 1) & 1, value); + + public void dmpGetMethodAttribs(ulong key, uint value) + => CFormat.Printf(Out, "GetMethodAttribs key %016llX, value %08X (%s)", key, value, SpmiDumpHelper.DumpCorInfoFlag(value)); + + public void dmpInitClass(in Agnostic_InitClass key, uint value) + => CFormat.Printf(Out, "InitClass key fld-%016llX meth-%016llX con-%016llX, value res-%u", key.field, key.method, + key.context, value); + + public void dmpCanInline(DLDL key, in Agnostic_CanInline value) + => CFormat.Printf(Out, "CanInline key - callerHnd-%016llX calleeHnd-%016llX, value result-%u exceptionCode-%08X", + key.A, key.B, value.result, value.exceptionCode); + + public void dmpResolveToken(in Agnostic_CORINFO_RESOLVED_TOKENin key, in ResolveTokenValue value) + => CFormat.Printf(Out, "ResolveToken key: %s, value: %s excp-%08X", + SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKENin(key), + SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKENout(value.tokenOut), + value.exceptionCode); + + public void dmpGetCallInfo(in Agnostic_GetCallInfo key, in Agnostic_CORINFO_CALL_INFO value) + => CFormat.Printf(Out, "GetCallInfo key rt{%s} crt{%s} ch-%016llX flg-%08X, value mth-%016llX, mf-%08X (%s) cf-%08X (%s) sig-%s aa-%u cch{hn-%u na-%u (TODO: dump callsiteCalloutHelper.args)} tt-%u k-%u (%s) nic-%u (%s) ch-%016llX ecnrl-%u (%s) stubLookup{%s} ipl{at-%08X (%s) hnd-%016llX} excp-%08X", + // input + SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.ResolvedToken), + SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.ConstrainedResolvedToken), + key.callerHandle, + key.flags, + // output + value.hMethod, + value.methodFlags, + SpmiDumpHelper.DumpCorInfoFlag(value.methodFlags), + value.classFlags, + SpmiDumpHelper.DumpCorInfoFlag(value.classFlags), + SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INFO(value.sig, GetCallInfo, SigInstHandleMap), + value.accessAllowed, + value.callsiteCalloutHelper.helperNum, + value.callsiteCalloutHelper.numArgs, + value.thisTransform, + value.kind, + toString_CORINFO_CALL_KIND(value.kind), + value.nullInstanceCheck, + (value.nullInstanceCheck != 0) ? "true" : "false", + value.contextHandle, + value.exactContextNeedsRuntimeLookup, + (value.exactContextNeedsRuntimeLookup != 0) ? "true" : "false", + SpmiDumpHelper.DumpAgnostic_CORINFO_LOOKUP(value.stubLookup), + value.instParamLookup.accessType, + toString_InfoAccessType(value.instParamLookup.accessType), + value.instParamLookup.handle, + value.exceptionCode); + + public void dmpExpandRawHandleIntrinsic(in Agnostic_ExpandRawHandleIntrinsic key, in Agnostic_CORINFO_GENERICHANDLE_RESULT result) + => CFormat.Printf(Out, "ExpandRawHandleIntrinsic key: %s, value %s cth-%016llx ht-%u", + SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKENin(key.ResolvedToken), + SpmiDumpHelper.DumpAgnostic_CORINFO_LOOKUP(result.lookup), + result.compileTimeHandle, + result.handleType); + + public void dmpIsIntrinsicType(ulong key, uint value) + => CFormat.Printf(Out, "IsIntrinsicType key mth-%016llX, value intr-%u", key, value); + + public void dmpAsCorInfoType(ulong key, uint value) + => CFormat.Printf(Out, "AsCorInfoType key cls-%016llX, value cit-%u(%s)", key, value, toString_CorInfoType(value)); + + public void dmpIsValueClass(ulong key, uint value) + => CFormat.Printf(Out, "IsValueClass key cls-%016llX, value res-%u", key, value); + + public void dmpIsByRefLike(ulong key, uint value) + => CFormat.Printf(Out, "IsByRefLike key cls-%016llX, value res-%u", key, value); + + public void dmpIsSharedInst(ulong key, uint value) + => CFormat.Printf(Out, "IsSharedInst key cls-%016llX, value res-%u", key, value); + + public void dmpGetClassSize(ulong key, uint val) + => CFormat.Printf(Out, "GetClassSize key %016llX, value %u", key, val); + + public void dmpGetHeapClassSize(ulong key, uint val) + => CFormat.Printf(Out, "GetHeapClassSize key %016llX, value %u", key, val); + + public void dmpCanAllocateOnStack(ulong key, uint val) + => CFormat.Printf(Out, "CanAllocateOnStack key %016llX, value %u", key, val); + + public void dmpGetClassNumInstanceFields(ulong key, uint value) + => CFormat.Printf(Out, "GetClassNumInstanceFields key cls-%016llX, value res-%u", key, value); + + public void dmpGetNewArrHelper(ulong key, uint value) + => CFormat.Printf(Out, "GetNewArrHelper key cls-%016llX, value res-%u", key, value); + + public void dmpGetSharedCCtorHelper(ulong key, uint value) + => CFormat.Printf(Out, "GetSharedCCtorHelper key cls-%016llX, value res-%u", key, value); + + public void dmpGetTypeForBox(ulong key, ulong value) + => CFormat.Printf(Out, "GetTypeForBox key cls-%016llX, value res-%016llX", key, value); + + public void dmpGetBoxHelper(ulong key, uint value) + => CFormat.Printf(Out, "GetBoxHelper key cls-%016llX, value res-%u", key, value); + + public void dmpGetBuiltinClass(uint key, ulong value) + => CFormat.Printf(Out, "GetBuiltinClass key cls-%08X, value cls-%016llX", key, value); + + public void dmpGetTypeForPrimitiveValueClass(ulong key, uint value) + => CFormat.Printf(Out, "GetTypeForPrimitiveValueClass key cls-%016llX, value cit-%u(%s)", key, value, toString_CorInfoType(value)); + + public void dmpGetTypeForPrimitiveNumericClass(ulong key, uint value) + => CFormat.Printf(Out, "GetTypeForPrimitiveNumericClass key cls-%016llX, value cit-%u(%s)", key, value, + toString_CorInfoType(value)); + + public void dmpGetParentType(ulong key, ulong value) + => CFormat.Printf(Out, "GetParentType key cls-%016llX, value cls-%016llX", key, value); + + public void dmpIsSDArray(ulong key, uint value) + => CFormat.Printf(Out, "IsSDArray key cls-%016llX, value res-%u", key, value); + + public void dmpGetFieldClass(ulong key, ulong value) + => CFormat.Printf(Out, "GetFieldClass key %016llX, value %016llX", key, value); + + public void dmpGetFieldOffset(ulong key, uint value) + => CFormat.Printf(Out, "GetFieldOffset key FLD-%016llX, value %08X", key, value); + + public void dmpGetUnBoxHelper(ulong key, uint value) + => CFormat.Printf(Out, "GetUnBoxHelper key cls-%016llX, value res-%u", key, value); + + public void dmpGetRuntimeTypePointer(ulong key, ulong value) + => CFormat.Printf(Out, "GetRuntimeTypePointer key cls-%016llX, value res-%016llX", key, value); + + public void dmpIsObjectImmutable(ulong key, uint value) + => CFormat.Printf(Out, "IsObjectImmutable key obj-%016llX, value res-%u", key, value); + + public void dmpGetStringChar(DLD key, DD value) + => CFormat.Printf(Out, "IsObjectImmutable key obj-%016llX, index-%u, value res-%u, val-%u", key.A, key.B, value.A, value.B); + + public void dmpGetObjectType(ulong key, ulong value) + => CFormat.Printf(Out, "GetObjectType key obj-%016llX, value res-%016llX", key, value); + + public void dmpGetReadyToRunHelper(GetReadyToRunHelper_TOKENin key, GetReadyToRunHelper_TOKENout value) + { + CFormat.Printf(Out, "GetReadyToRunHelper key: tk{%s} id-%u", + SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.ResolvedToken), key.id); + CFormat.Printf(Out, ", value: lk{ %s } %u", SpmiDumpHelper.DumpAgnostic_CORINFO_CONST_LOOKUP(value.Lookup), + value.result); + } + + public void dmpGetReadyToRunDelegateCtorHelper(GetReadyToRunDelegateCtorHelper_TOKENIn key, Agnostic_CORINFO_LOOKUP value) + { + CFormat.Printf(Out, "GetReadyToRunDelegateCtorHelper key: method tk{%s} type-%016llX constraint-%08X", + SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.TargetMethod), key.delegateType, key.targetConstraint); + CFormat.Printf(Out, ", value: %s", SpmiDumpHelper.DumpAgnostic_CORINFO_LOOKUP(value)); + } + + public void dmpGetHelperFtn(uint key, Agnostic_GetHelperFtn value) + => CFormat.Printf(Out, "GetHelperFtn key ftn-%u nativeEntrypoint {%s}, helperMethod-%016llX", key, + SpmiDumpHelper.DumpAgnostic_CORINFO_CONST_LOOKUP(value.helperLookup), + value.helperMethod); + + public void dmpGetJustMyCodeHandle(ulong key, DLDL value) + => CFormat.Printf(Out, "GetJustMyCodeHandle key ftn-%016llX, value pp-%016llX, res-%016llX", key, value.A, value.B); + + public void dmpGetFunctionEntryPoint(DLD key, DLD value) + => CFormat.Printf(Out, "GetFunctionEntryPoint key ftn-%016llX af-%08X, value add-%016llX at-%u", key.A, key.B, value.A, value.B); + + public void dmpConstructStringLiteral(DLD key, DLD value) + => CFormat.Printf(Out, "ConstructStringLiteral key mod-%016llX tok-%08X, value pp-%016llX iat-%u", key.A, key.B, value.A, value.B); + + public void dmpConvertPInvokeCalliToCall(DLD key, DLDL value) + => CFormat.Printf(Out, "ConvertPInvokeCalliToCall key mod-%016llX tok-%08X, value cls-%016llX meth-%016llX", + key.A, key.B, value.A, value.B); + + public void dmpEmptyStringLiteral(uint key, DLD value) + => CFormat.Printf(Out, "EmptyStringLiteral key %u, value pVal-%016llX res-%u", key, value.A, value.B); + + public void dmpGetArgType(in Agnostic_GetArgType_Key key, in Agnostic_GetArgType_Value value) + { + CFormat.Printf(Out, "GetArgType key flg-%08X na-%u %s %s msig-%016llX scp-%016llX arg-%016llX", + key.flags, key.numArgs, + SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INST_Element("", "cc", "ci", key.sigInst_classInstCount, key.sigInst_classInst_Index, SigInstHandleMap), + SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INST_Element("", "mc", "mi", key.sigInst_methInstCount, key.sigInst_methInst_Index, SigInstHandleMap), + key.methodSignature, key.scope, key.args); + CFormat.Printf(Out, ", value result(cit)-%u(%s) vcType-%016llX excp-%08X", value.result, toString_CorInfoTypeWithMod(value.result), value.vcTypeRet, value.exceptionCode); + } + + public void dmpGetExactClasses(DLD key, in Agnostic_GetExactClassesResult value) + => CFormat.Printf(Out, "GetExactClasses key baseType-%016llX, maxExactCls-%u, value numClasses-%d", + key.A, key.B, value.numClasses); + + public void dmpGetArgNext(ulong key, ulong value) + => CFormat.Printf(Out, "GetArgNext key %016llX, value %016llX", key, value); + + public void dmpGetMethodSig(DLDL key, in Agnostic_CORINFO_SIG_INFO value) + => CFormat.Printf(Out, "GetMethodSig key ftn-%016llX prt-%016llX, value-%s", key.A, key.B, + SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INFO(value, GetMethodSig, SigInstHandleMap)); + + public void dmpGetArgClass(in Agnostic_GetArgClass_Key key, in Agnostic_GetArgClass_Value value) + { + CFormat.Printf(Out, "GetArgClass key %s %s msig-%016llX scp-%016llX args-%016llX", + SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INST_Element("", "cc", "ci", key.sigInst_classInstCount, key.sigInst_classInst_Index, SigInstHandleMap), + SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INST_Element("", "mc", "mi", key.sigInst_methInstCount, key.sigInst_methInst_Index, SigInstHandleMap), + key.methodSignature, key.scope, key.args); + CFormat.Printf(Out, ", value %016llX excp-%08X", value.result, value.exceptionCode); + } + + public void dmpGetHFAType(ulong key, uint value) + => CFormat.Printf(Out, "GetHFAType key %016llX, value %u ", key, value); + + public void dmpGetMethodInfo(DLDL key, in Agnostic_GetMethodInfo value) + { + if (value.result != 0) + { + CFormat.Printf(Out, "GetMethodInfo key ftn-%016llX ctx-%016llX, value res-%u ftn-%016llX scp-%016llX ilo-%u ils-%u ms-%u ehc-%u opt-%08X rk-%u args-%s locals-%s excp-%08X", + key.A, key.B, value.result, value.info.ftn, value.info.scope, value.info.ILCode_offset, value.info.ILCodeSize, + value.info.maxStack, value.info.EHcount, value.info.options, value.info.regionKind, + SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INFO(value.info.args, GetMethodInfo, SigInstHandleMap), + SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INFO(value.info.locals, GetMethodInfo, SigInstHandleMap), + value.exceptionCode); + } + else + { + CFormat.Printf(Out, "GetMethodInfo key ftn-%016llX ctx-%016llX, value res-%u excp-%08X", + key.A, key.B, value.result, value.exceptionCode); + } + } + + public void dmpHaveSameMethodDefinition(in DLDL key, uint value) + => CFormat.Printf(Out, "HaveSameMethodDefinition key methHnd1-%016llX, methHnd2-%016llX, value %u", key.A, key.B, value); + + public void dmpGetTypeDefinition(ulong key, ulong value) + => CFormat.Printf(Out, "GetTypeDefinition key cls-%016llX, value cls-%016llX", key, value); + + public void dmpGetNewHelper(ulong key, in DDD value) + => CFormat.Printf(Out, "GetNewHelper key %016llX, hasSideEffects-%u, value res-%u, exceptionCode-%08X", key, value.A, value.B, value.C); + + public void dmpEmbedGenericHandle(in Agnostic_EmbedGenericHandle key, in Agnostic_CORINFO_GENERICHANDLE_RESULT value) + => CFormat.Printf(Out, "EmbedGenericHandle key rt{%s} emb-%u, value %s cth-%016llX ht-%u", + SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.ResolvedToken), + key.fEmbedParent, + SpmiDumpHelper.DumpAgnostic_CORINFO_LOOKUP(value.lookup), + value.compileTimeHandle, + value.handleType); + + public void dmpGetEHinfo(DLD key, in Agnostic_CORINFO_EH_CLAUSE value) + => CFormat.Printf(Out, "GetEHinfo key ftn-%016llX ehn-%u, value flg-%u to-%u tl-%u ho-%u hl-%u ct-%u", key.A, key.B, value.Flags, + value.TryOffset, value.TryLength, value.HandlerOffset, value.HandlerLength, value.ClassToken); + + public void dmpGetMethodVTableOffset(ulong key, DDD value) + => CFormat.Printf(Out, "GetMethodVTableOffset key ftn-%016llX, value offi-%u, offa-%u. offr-%d", key, value.A, value.B, value.C); + + public void dmpResolveVirtualMethod(in Agnostic_ResolveVirtualMethodKey key, in Agnostic_ResolveVirtualMethodResult result) + { + CFormat.Printf(Out, "ResolveVirtualMethod key virtMethod-%016llX, objClass-%016llX, context-%016llX pResolvedTokenVirtualMethodNonNull-%08X pResolvedTokenVirtualMethod{%s}", + key.virtualMethod, + key.objClass, + key.context, + key.pResolvedTokenVirtualMethodNonNull, + (key.pResolvedTokenVirtualMethodNonNull != 0) ? SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.pResolvedTokenVirtualMethod) : "???"); + CFormat.Printf(Out, ", value returnValue-%s, devirtMethod-%016llX, tokenLookupContext-%016llX, detail-%d, tokDvMeth{%s}, tokDvUnboxMeth{%s}, instParamLookup{%s}", + (result.returnValue != 0) ? "true" : "false", + result.devirtualizedMethod, + result.tokenLookupContext, + result.detail, + (result.returnValue != 0) ? SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKEN(result.resolvedTokenDevirtualizedMethod) : "???", + (result.returnValue != 0) ? SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKEN(result.resolvedTokenDevirtualizedUnboxedMethod) : "???", + SpmiDumpHelper.DumpAgnostic_CORINFO_LOOKUP(result.instParamLookup)); + } + + public void dmpGetAsyncOtherVariant(ulong key, DLD value) + => CFormat.Printf(Out, "GetAsyncOtherVariant ftn-%016llX, result-%016llX, variantIsThunk-%u", key, value.A, value.B); + + public void dmpGetDefaultComparerClass(ulong key, ulong value) + => CFormat.Printf(Out, "GetDefaultComparerClass key cls-%016llX, value cls-%016llX", key, value); + + public void dmpGetDefaultEqualityComparerClass(ulong key, ulong value) + => CFormat.Printf(Out, "GetDefaultEqualityComparerClass key cls-%016llX, value cls-%016llX", key, value); + + public void dmpGetSZArrayHelperEnumeratorClass(ulong key, ulong value) + => CFormat.Printf(Out, "GetSZArrayHelperEnumeratorClass key cls-%016llX, value cls-%016llX", key, value); + + public void dmpGetTokenTypeAsHandle(in GetTokenTypeAsHandleValue key, ulong value) + => CFormat.Printf(Out, "GetTokenTypeAsHandle key ftn-%016llX fld-%016llX, value cls-%016llX", key.hMethod, key.hField, value); + + public void dmpGetThreadLocalFieldInfo(DLD key, uint value) + => CFormat.Printf(Out, "GetThreadLocalFieldInfo key hnd-%016llX,gctype-%d result-%u", key.A, key.B, value); + + public void dmpGetThreadLocalStaticBlocksInfo(uint key, in Agnostic_GetThreadLocalStaticBlocksInfo value) + => CFormat.Printf(Out, "GetThreadLocalStaticBlocksInfo key %u, tlsIndex-%s, , tlsGetAddrFtnPtr-%016llX, tlsIndexObject - %016llX, threadVarsSection - %016llX, offsetOfThreadLocalStoragePointer-%u, offsetOfMaxThreadStaticBlocks-%u, offsetOfThreadStaticBlocks-%u, offsetOfBaseOfThreadLocalData-%u", + key, SpmiDumpHelper.DumpAgnostic_CORINFO_CONST_LOOKUP(value.tlsIndex), value.tlsGetAddrFtnPtr, + value.tlsIndexObject, value.threadVarsSection, value.offsetOfThreadLocalStoragePointer, + value.offsetOfMaxThreadStaticBlocks, value.offsetOfThreadStaticBlocks, value.offsetOfBaseOfThreadLocalData); + + public void dmpGetThreadLocalStaticInfo_NativeAOT(ulong key, in Agnostic_GetThreadStaticInfo_NativeAOT value) + => CFormat.Printf(Out, "GetThreadLocalStaticInfo_NativeAOT key %016llX, tlsRootObject-%s, tlsIndexObject-%s, offsetOfThreadLocalStoragePointer-%u, threadStaticBaseSlow-%s, tlsGetAddrFtnPtr-%s", + key, SpmiDumpHelper.DumpAgnostic_CORINFO_CONST_LOOKUP(value.tlsRootObject), + SpmiDumpHelper.DumpAgnostic_CORINFO_CONST_LOOKUP(value.tlsIndexObject), + value.offsetOfThreadLocalStoragePointer, + SpmiDumpHelper.DumpAgnostic_CORINFO_CONST_LOOKUP(value.threadStaticBaseSlow), + SpmiDumpHelper.DumpAgnostic_CORINFO_CONST_LOOKUP(value.tlsGetAddrFtnPtr)); + + public void dmpEmbedMethodHandle(ulong key, DLDL value) + => CFormat.Printf(Out, "EmbedMethodHandle key ftn-%016llX, value pp-%016llX res-%016llX", key, value.A, value.B); + + public void dmpGetStaticFieldContent(DLDDD key, DD value) + { + CFormat.Printf(Out, "GetStaticFieldContent key fld-%016llX bufSize-%u, ignoremovable-%u, valOffset-%u result-%u", key.A, key.B, key.C, key.D, value.A); + GetStaticFieldContent.Unlock(); + } + + public void dmpGetObjectContent(DLDD key, DD value) + { + CFormat.Printf(Out, "GetObjectContent key fld-%016llX bufSize-%u, valOffset-%u result-%u", key.A, key.B, key.C, value.A); + GetObjectContent.Unlock(); + } + + public void dmpGetStaticFieldCurrentClass(DLD key, in Agnostic_GetStaticFieldCurrentClass value) + => CFormat.Printf(Out, "GetStaticFieldCurrentClass key fld-%016llX, value clsHnd-%016llX isSpeculative-%u", key.A, value.classHandle, + value.isSpeculative); + + public void dmpGetClassAlignmentRequirement(DLD key, uint value) + => CFormat.Printf(Out, "GetClassAlignmentRequirement key %016llX %u, value %u", key.A, key.B, value); + + public void dmpGetCastingHelper(in Agnostic_GetCastingHelper key, uint value) + => CFormat.Printf(Out, "GetCastingHelper key cls-%016llX, thw-%u, value res-%u", key.hClass, key.fThrowing, value); + + public void dmpEmbedModuleHandle(ulong key, DLDL value) + => CFormat.Printf(Out, "EmbedModuleHandle key mod-%016llX, value pp-%016llX res-%016llX", key, value.A, value.B); + + public void dmpEmbedClassHandle(ulong key, DLDL value) + => CFormat.Printf(Out, "EmbedClassHandle key cls-%016llX, value pp-%016llX res-%016llX", key, value.A, value.B); + + public void dmpPInvokeMarshalingRequired(in MethodOrSigInfoValue key, uint value) + => CFormat.Printf(Out, "PInvokeMarshalingRequired key mth-%016llX scp-%016llX sig-%s, value res-%u", + key.method, key.scope, + SpmiDumpHelper.DumpPSig(key.pSig_Index, key.cbSig, PInvokeMarshalingRequired), + value); + + public void dmpGetUnmanagedCallConv(in MethodOrSigInfoValue key, DD value) + => CFormat.Printf(Out, "GetUnmanagedCallConv key mth-%016llX scp-%016llX sig-%s, value res-%u,%u", + key.method, key.scope, + SpmiDumpHelper.DumpPSig(key.pSig_Index, key.cbSig, GetUnmanagedCallConv), + value.A, value.B); + + public void dmpFindSig(in Agnostic_FindSig key, in Agnostic_CORINFO_SIG_INFO value) + { + CFormat.Printf(Out, "FindSig key module-%016llX sigTOK-%08X context-%016llX", key.module, key.sigTOK, key.context); + CFormat.Printf(Out, ", value-%s", + SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INFO(value, FindSig, SigInstHandleMap)); + } + + public void dmpGetEEInfo(uint key, in Agnostic_CORINFO_EE_INFO value) + => CFormat.Printf(Out, "GetEEInfo key %u, value icfi{sz-%u sz-witharg-%u ofl-%u ocsp-%u ocsfp-%u oct-%u ora-%u ossa-%u osap-%u} otf-%u ogcs-%u odi-%u odft-%u srpf-%u osps-%u muono-%u tabi-%u osType-%u", + key, value.inlinedCallFrameInfo.size, value.inlinedCallFrameInfo.sizeWithSecretStubArg, + value.inlinedCallFrameInfo.offsetOfFrameLink, + value.inlinedCallFrameInfo.offsetOfCallSiteSP, value.inlinedCallFrameInfo.offsetOfCalleeSavedFP, + value.inlinedCallFrameInfo.offsetOfCallTarget, value.inlinedCallFrameInfo.offsetOfReturnAddress, + value.inlinedCallFrameInfo.offsetOfSecretStubArg, value.inlinedCallFrameInfo.offsetOfSPAfterProlog, + value.offsetOfThreadFrame, value.offsetOfGCState, value.offsetOfDelegateInstance, + value.offsetOfDelegateFirstTarget, + value.sizeOfReversePInvokeFrame, value.osPageSize, value.maxUncheckedOffsetForNullObject, value.targetAbi, + value.osType); + + public void dmpGetAsyncInfo(uint key, in Agnostic_CORINFO_ASYNC_INFO value) + => CFormat.Printf(Out, "GetAsyncInfo key %u value contClsHnd-%016llX contNextFldHnd-%016llX contResumeInfoFldHnd-%016llX contStateFldHnd-%016llX contFlagsFldHnd-%016llX", + key, value.continuationClsHnd, value.continuationNextFldHnd, value.continuationResumeInfoFldHnd, + value.continuationStateFldHnd, value.continuationFlagsFldHnd); + + public void dmpGetWasmWellKnownGlobals(uint key, in Agnostic_CORINFO_WASM_WELLKNOWN_GLOBALS value) + => CFormat.Printf(Out, "GetWasmWellKnownGlobals key %u value stackPointer-%016llX imageBase-%016llX tableBase-%016llX asyncContinuation-%016llX", + key, value.stackPointer, value.imageBase, value.tableBase, value.asyncContinuation); + + public void dmpGetAwaitReturnCall(ulong key, in Agnostic_GetAwaitReturnCallResult value) + => CFormat.Printf(Out, "GetAwaitReturnCall key %016llX value methodHnd-%016llX contextHandle-%016llX instArg %s", + key, + value.methodHnd, + value.contextHandle, + SpmiDumpHelper.DumpAgnostic_CORINFO_LOOKUP(value.instArg)); + + public void dmpGetAwaitAwaiterInContinuationCall(in Agnostic_GetAwaitAwaiterInContinuationCall key, in Agnostic_GetAwaitReturnCallResult value) + => CFormat.Printf(Out, "GetAwaitAwaiterInContinuationCall caller-%016llX rt{%s} unsafe-%u methodHnd-%016llX contextHandle-%016llX instArg %s", + key.callerHnd, + SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.ResolvedToken), + key.isUnsafe, + value.methodHnd, + value.contextHandle, + SpmiDumpHelper.DumpAgnostic_CORINFO_LOOKUP(value.instArg)); + + public void dmpGetGSCookie(uint key, DLDL value) + => CFormat.Printf(Out, "GetGSCookie key 0, value pCookieVal-%016llX ppCookieVal-%016llX", value.A, value.B); + + public void dmpGetOSRInfo(uint key, in Agnostic_GetOSRInfo value) + { + // todo - dump patchpoint info? + CFormat.Printf(Out, "GetOSRInfo key %u, value patchpointInfo-%u {...} iloffset-%u\n", + key, value.index, value.ilOffset); + } + + public void dmpGetClassModuleIdForStatics(ulong key, in Agnostic_GetClassModuleIdForStatics value) + => CFormat.Printf(Out, "GetClassModuleIdForStatics key cls-%016llX, value mod-%016llX pp-%016llX res-%016llX", key, value.Module, + value.pIndirection, value.result); + + public void dmpGetIsClassInitedFlagAddress(ulong key, in Agnostic_GetIsClassInitedFlagAddress value) + => CFormat.Printf(Out, "GetIsClassInitedFlagAddress key hnd-%016llX, value addr-%016llX, result-%u", key, value.addr.handle, value.result); + + public void dmpGetStaticBaseAddress(DLD key, in Agnostic_GetStaticBaseAddress value) + => CFormat.Printf(Out, "GetStaticBaseAddress key hnd-%016llX, value addr-%016llX, result-%u", key.A, value.addr.handle, value.result); + + public void dmpGetThreadTLSIndex(uint key, DLD value) + => CFormat.Printf(Out, "GetThreadTLSIndex key 0, value ppIndirection-%016llX result-%08X", value.A, value.B); + + public void dmpGetAddrOfCaptureThreadGlobal(uint key, DLDL value) + => CFormat.Printf(Out, "GetAddrOfCaptureThreadGlobal key %u, value ppi-%016llX res-%016llX", key, value.A, value.B); + + public void dmpGetClassStaticDynamicInfo(ulong key, DLD value) + => CFormat.Printf(Out, "GetClassStaticDynamicInfo key cls-%016llX, value pp-%016llX res-%u", key, value.A, value.B); + + public void dmpGetClassThreadStaticDynamicInfo(ulong key, DLD value) + => CFormat.Printf(Out, "GetClassThreadStaticDynamicInfo key cls-%016llX, value pp-%016llX res-%u", key, value.A, value.B); + + public void dmpGetLocationOfThisType(ulong key, in Agnostic_CORINFO_LOOKUP_KIND value) + => CFormat.Printf(Out, "GetLocationOfThisType key ftn-%016llX, value %s", key, + SpmiDumpHelper.DumpAgnostic_CORINFO_LOOKUP_KIND(value)); + + public void dmpGetDelegateCtor(in Agnostic_GetDelegateCtorIn key, in Agnostic_GetDelegateCtorOut value) + => CFormat.Printf(Out, "GetDelegateCtor key ftn-%016llX cls-%016llX tftn-%016llX, value pm-%016llX a3-%016llX a4-%016llX a5-%016llX res-%016llX", + key.methHnd, key.clsHnd, key.targetMethodHnd, value.CtorData.pMethod, value.CtorData.pArg3, + value.CtorData.pArg4, value.CtorData.pArg5, value.result); + + public void dmpGetFunctionFixedEntryPoint(ulong key, in Agnostic_CORINFO_CONST_LOOKUP value) + => CFormat.Printf(Out, "GetFunctionFixedEntryPoint key ftn-%016llX, value %s", key, + SpmiDumpHelper.DumpAgnostic_CORINFO_CONST_LOOKUP(value)); + + public void dmpGetFieldInClass(DLD key, ulong value) + => CFormat.Printf(Out, "GetFieldInClass key cls-%016llX ind-%u, value %016llX", key.A, key.B, value); + + public void dmpGetFieldType(DLDL key, DLD value) + => CFormat.Printf(Out, "GetFieldType key fld-%016llX cls-%016llX, value ch-%016llX cit-%u(%s)", key.A, key.B, value.A, value.B, + toString_CorInfoType(value.B)); + + public void dmpSatisfiesMethodConstraints(DLDL key, uint value) + => CFormat.Printf(Out, "SatisfiesMethodConstraints key cls-%016llX ftn-%016llX, value res-%u", key.A, key.B, value); + + public void dmpGetStringLiteral(DLDDD key, DD value) + { + CFormat.Printf(Out, "GetStringLiteral key mod-%016llX tok-%08X, bufSize-%u, startIndex-%u, len-%u", key.A, key.B, key.C, key.D, value.A); + GetStringLiteral.Unlock(); + } + + public void dmpCanCast(DLDL key, uint value) + => CFormat.Printf(Out, "CanCast key chd-%016llX par-%016llX, value res-%u", key.A, key.B, value); + + public void dmpGetChildType(ulong key, DLD value) + => CFormat.Printf(Out, "GetChildType key cls-%016llX, value clsr-%016llX cit-%u(%s)", key, value.A, value.B, + toString_CorInfoType(value.B)); + + public void dmpGetArrayInitializationData(DLD key, ulong value) + => CFormat.Printf(Out, "GetArrayInitializationData key field-%016llX size-%08X, value result-%016llX", key.A, key.B, value); + + public void dmpGetAddressOfPInvokeTarget(ulong key, DLD value) + => CFormat.Printf(Out, "GetAddressOfPInvokeTarget key ftn-%016llX, value addr-%016llX at-%u", key, value.A, value.B); + + public void dmpGetMethodHash(ulong key, uint value) + => CFormat.Printf(Out, "GetMethodHash key %016llX, value %u", key, value); + + public void dmpCanTailCall(in Agnostic_CanTailCall key, uint value) + => CFormat.Printf(Out, "CanTailCall key clr-%016llX dcle-%016llX ecle-%016llX pfx-%u, value res-%u", key.callerHnd, + key.declaredCalleeHnd, key.exactCalleeHnd, key.fIsTailPrefix, value); + + public void dmpIsDelegateCreationAllowed(DLDL key, uint value) + => CFormat.Printf(Out, "IsDelegateCreationAllowed key delegateHnd-%016llX calleeHnd-%016llX result-%08X", key.A, key.B, value); + + public void dmpFindCallSiteSig(in Agnostic_FindCallSiteSig key, in Agnostic_CORINFO_SIG_INFO value) + { + CFormat.Printf(Out, "dmpFindCallSiteSig key module-%016llX methTok-%08X context-%016llX", key.module, key.methTok, key.context); + CFormat.Printf(Out, ", value-%s", + SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INFO(value, FindCallSiteSig, SigInstHandleMap)); + } + + public void dmpGetVarArgsHandle(in GetVarArgsHandleValue key, DLDL value) + { + CFormat.Printf(Out, "GetVarArgsHandle key sig-%s scope-%016llX token-%08X methHnd-%016llX", + SpmiDumpHelper.DumpPSig(key.pSig_Index, key.cbSig, GetVarArgsHandle), + key.scope, key.token, key.methHnd); + CFormat.Printf(Out, ", value ppIndirection-%016llX result-%016llX", value.A, value.B); + } + + public void dmpGetFieldThreadLocalStoreID(ulong key, DLD value) + => CFormat.Printf(Out, "GetFieldThreadLocalStoreID key field-%016llX, value ppIndirection-%016llX result-%08X", key, value.A, + value.B); + + public void dmpIsMoreSpecificType(DLDL key, uint value) + => CFormat.Printf(Out, "IsMoreSpecificType key cls1-%016llX cls2-%016llX, value %u", key.A, key.B, value); + + public void dmpIsExactType(ulong key, uint value) + => CFormat.Printf(Out, "IsExactType key cls-%016llX, value res-%u", key, value); + + public void dmpIsGenericType(ulong key, uint value) + => CFormat.Printf(Out, "IsGenericType key cls-%016llX, value res-%d", key, value); + + public void dmpIsNullableType(ulong key, uint value) + => CFormat.Printf(Out, "IsNullableType key cls-%016llX, value res-%d", key, value); + + public void dmpIsEnum(ulong key, DLD value) + => CFormat.Printf(Out, "IsEnum key cls-%016llX, value underlyingType-%016llX result-%u", key, value.A, value.B); + + public void dmpGetCookieForInterpreterCalliSig(in GetCookieForInterpreterCalliSigValue key, DLDL value) + => CFormat.Printf(Out, "GetCookieForInterpreterCalliSig NYI"); + + public void dmpErrorList(uint key, uint value) + => CFormat.Printf(Out, "ErrorList NYI"); + + public void dmpGetProfilingHandle(uint key, in Agnostic_GetProfilingHandle value) + => CFormat.Printf(Out, "GetProfilingHandle key %u, value bHookFtn-%u profHnd-%016llX bIndHnd-%u", key, value.bHookFunction, + value.ProfilerHandle, value.bIndirectedHandles); + + public void dmpEmbedFieldHandle(ulong key, DLDL value) + => CFormat.Printf(Out, "EmbedFieldHandle NYI"); + + public void dmpCompareTypesForCast(DLDL key, uint value) + => CFormat.Printf(Out, "CompareTypesForCast key fromClass=%016llX, toClass=%016llx, result=%d", key.A, key.B, value); + + public void dmpCompareTypesForEquality(DLDL key, uint value) + => CFormat.Printf(Out, "CompareTypesForEquality key cls1=%016llX, cls2=%016llx, result=%d", key.A, key.B, value); + + public void dmpGetWasmLowering(ulong key, uint value) + => CFormat.Printf(Out, "GetWasmLowering key structHnd-%016llX, value %d ", key, value); + + public void dmpGetRelocTypeHint(ulong key, uint value) + => CFormat.Printf(Out, "GetRelocTypeHint key tgt-%016llX, value hint-%u", key, value); + + public void dmpGetAddressAlignment(ulong key, uint value) + => CFormat.Printf(Out, "GetAddressAlignment key addr-%016llX, value align-%u", key, value); + + public void dmpGetExpectedTargetArchitecture(uint key, uint result) + => CFormat.Printf(Out, "GetExpectedTargetArchitecture key %u, res %u", key, result); + + public void dmpDoesFieldBelongToClass(DLDL key, uint value) + => CFormat.Printf(Out, "DoesFieldBelongToClass key fld=%016llX, cls=%016llx, result=%d", key.A, key.B, value); + + public void dmpGetTypeInstantiationArgument(DLD key, ulong value) + { + CFormat.Printf(Out, "GetTypeInstantiationArgument key - classNonNull-%llu, index-%u, value NonNull-%llu", key.A, key.B, value); + GetTypeInstantiationArgument.Unlock(); + } + + public void dmpGetMethodInstantiationArgument(DLD key, ulong value) + { + CFormat.Printf(Out, "GetMethodInstantiationArgument key - methodNonNull-%llu, index-%u, value NonNull-%llu", key.A, key.B, value); + GetMethodInstantiationArgument.Unlock(); + } + + public void dmpPrintObjectDescription(ulong key, in Agnostic_PrintResult value) + { + dmpPrint("PrintObjectDescription", PrintObjectDescription, key, value); + } + + public void dmpPrintClassName(ulong key, in Agnostic_PrintResult value) + { + dmpPrint("PrintClassName", PrintClassName, key, value); + } + + public void dmpPrintFieldName(ulong key, in Agnostic_PrintResult value) + { + dmpPrint("PrintFieldName", PrintFieldName, key, value); + } + + public void dmpPrintMethodName(ulong key, in Agnostic_PrintResult value) + { + dmpPrint("PrintMethodName", PrintMethodName, key, value); + } + + public void dmpGetTailCallHelpers(in Agnostic_GetTailCallHelpers key, in Agnostic_CORINFO_TAILCALL_HELPERS value) + { + CFormat.Printf(Out, "GetTailCallHelpers key callToken-%s sig-%s flg-%08X", + SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.callToken), + SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INFO(key.sig, GetTailCallHelpers, SigInstHandleMap), + key.flags); + CFormat.Printf(Out, ", value result-%s flg-%08X hStoreArgs-%016llX hCallTarget-%016llX hDispatcher-%016llX", + (value.result != 0) ? "true" : "false", + value.flags, + value.hStoreArgs, + value.hCallTarget, + value.hDispatcher); + } + + public void dmpGetAsyncResumptionStub(uint key, in DLDL value) + => CFormat.Printf(Out, "GetAsyncResumptionStub key-%u, hnd-%016llX, entrypoint-%016llX", key, value.A, value.B); + + public void dmpGetContinuationType(in Agnostic_GetContinuationTypeIn key, ulong value) + => CFormat.Printf(Out, "GetContinuationType dataSize-%016llX, objRefs-%u, handle-%016llX", + key.dataSize, key.objRefs, value); + + public void dmpUpdateEntryPointForTailCall(in Agnostic_CORINFO_CONST_LOOKUP origEntryPoint, in Agnostic_CORINFO_CONST_LOOKUP newEntryPoint) + => CFormat.Printf(Out, "UpdateEntryPointForTailcall orig=%s new=%s", + SpmiDumpHelper.DumpAgnostic_CORINFO_CONST_LOOKUP(origEntryPoint), + SpmiDumpHelper.DumpAgnostic_CORINFO_CONST_LOOKUP(newEntryPoint)); + + public void dmpGetMethodDefFromMethod(ulong key, uint value) + => CFormat.Printf(Out, "GetMethodDefFromMethod key ftn-%016llX, value res-%u", key, value); + + public void dmpGetArrayRank(ulong key, uint value) + => CFormat.Printf(Out, "GetArrayRank key %016llX, value %u", key, value); + + public void dmpGetArrayIntrinsicID(ulong key, uint value) + => CFormat.Printf(Out, "GetArrayIntrinsicID key %016llX, value %u", key, value); + + public void dmpIsFieldStatic(ulong key, uint value) + => CFormat.Printf(Out, "IsFieldStatic key %016llX, value %u", key, value); + + public void dmpGetArrayOrStringLength(ulong key, uint value) + => CFormat.Printf(Out, "GetArrayOrStringLength key %016llX, value %u", key, value); + + public void dmpGetSpecialCopyHelper(ulong key, ulong value) + => CFormat.Printf(Out, "getSpecialCopyHelper key %016llX, value %016llX", key, value); + + public void dmpGetWasmTypeSymbol(in Agnostic_GetWasmTypeSymbol key, ulong value) + => CFormat.Printf(Out, "getWasmTypeSymbol types %u, typesSize %u, value %016llX", key.types, key.typesSize, value); + + public void dmpSigInstHandleMap(uint key, ulong value) + => CFormat.Printf(Out, "SigInstHandleMap key %u, value %016llX", key, value); + + public void dmpCanValueClassInstancePointerEscape(ulong key, uint value) + => CFormat.Printf(Out, "CanValueClassInstancePointerEscape key ftn-%016llX, value res-%u", key, value); +} diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Identity.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Identity.cs new file mode 100644 index 00000000000000..833429c7d1c0e2 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Identity.cs @@ -0,0 +1,171 @@ +// 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.Buffers.Binary; +using Internal.JitInterface; +using Internal.Pgo; + +using static SuperPmi.SpmiRecordsHelper; + +namespace SuperPmi; + +public sealed unsafe partial class MethodContext +{ + private const int METHOD_IDENTITY_INFO_SIZE = 0x10000; + // Reserved for everything in the identity except the method name. + private const int METHOD_IDENTITY_INFO_NON_NAME_RESERVE = 0x400; + + // CORINFO_InstructionSetFlags::FlagsFieldCount in inc/corinfoinstructionset.h. + public const int InstructionFlagsFieldCount = 2; + + public uint methodSize; + + public CORINFO_METHOD_INFO repCompileMethod(out uint flags, out CORINFO_OS os) + { + CORINFO_METHOD_INFO info; + uint f; + CORINFO_OS o; + repCompileMethod(&info, &f, &o); + flags = f; + os = o; + return info; + } + + // The JIT flags word, followed by the instruction set flags. + public (ulong JitFlags, ulong[] InstructionSetFlags) repGetJitFlags() + { + ulong* raw = stackalloc ulong[1 + InstructionFlagsFieldCount]; + new Span(raw, 1 + InstructionFlagsFieldCount).Clear(); + repGetJitFlags((CORJIT_FLAGS*)raw, (uint)(sizeof(ulong) * (1 + InstructionFlagsFieldCount))); + return (raw[0], new ReadOnlySpan(raw + 1, InstructionFlagsFieldCount).ToArray()); + } + + // The text that identifies a method: its signature, calling convention, options, JIT and ISA flags, + // and hashes of its IL and root method PGO counters. + public byte[] dumpMethodIdentityInfoToBuffer(bool ignoreMethodName = false, CORINFO_METHOD_INFO* optInfo = null, uint optFlags = 0) + { + CORINFO_METHOD_INFO info = optInfo != null ? *optInfo : repCompileMethod(out _, out _); + (ulong jitFlags, ulong[] isaFlags) = repGetJitFlags(); + + var buff = new ByteBuilder(); + + // Huge method signatures are truncated. + buff.Append(CallUtils.GetMethodFullName(this, info.ftn, info.args, ignoreMethodName)); + buff.Append(" -- "u8); + buff.Truncate(METHOD_IDENTITY_INFO_SIZE - METHOD_IDENTITY_INFO_NON_NAME_RESERVE - 1); + + buff.Append($"CallingConvention: {(int)info.args.callConv}, CorInfoOptions: {(int)info.options}, CorInfoRegionKind: {(int)info.regionKind}, JitFlags {jitFlags:x16}, ISA Flags"); + for (int i = InstructionFlagsFieldCount - 1; i >= 0; i--) + buff.Append($" {isaFlags[i]:X16}"); + + buff.Append($" ILCode Hash: {Hash.HashBuffer(new ReadOnlySpan(info.ILCode, (int)info.ILCodeSize))}"); + + if (GetPgoInstrumentationResults != null && GetPgoInstrumentationResults.GetIndex(CastHandle(info.ftn)) != -1) + AppendPgoCountersHash(buff, info.ftn); + + return buff.ToArray(); + } + + private void AppendPgoCountersHash(ByteBuilder buff, CORINFO_METHOD_STRUCT_* ftn) + { + PgoInstrumentationSchema* schema; + uint schemaCount; + byte* schemaData; + PgoSource pgoSource; + bool dynamicPgo; + if (repGetPgoInstrumentationResults(ftn, &schema, &schemaCount, &schemaData, &pgoSource, &dynamicPgo) < 0) + return; + + ulong minOffset = ulong.MaxValue; + ulong maxOffset = 0; + ulong totalCount = 0; + for (uint i = 0; i < schemaCount; i++) + { + ulong start = (ulong)schema[i].Offset; + ulong end; + switch (schema[i].InstrumentationKind) + { + case PgoInstrumentationKind.BasicBlockIntCount: + case PgoInstrumentationKind.EdgeIntCount: + totalCount += BinaryPrimitives.ReadUInt32LittleEndian(new ReadOnlySpan(schemaData + start, sizeof(uint))); + end = start + 4; + break; + case PgoInstrumentationKind.BasicBlockLongCount: + case PgoInstrumentationKind.EdgeLongCount: + totalCount += BinaryPrimitives.ReadUInt64LittleEndian(new ReadOnlySpan(schemaData + start, sizeof(ulong))); + end = start + 8; + break; + default: + continue; + } + + minOffset = Math.Min(minOffset, start); + maxOffset = Math.Max(maxOffset, end); + } + + if (minOffset < maxOffset) + { + string pgoHash = Hash.HashBuffer(new ReadOnlySpan(schemaData + minOffset, (int)(maxOffset - minOffset))); + buff.Append($" Pgo Counters {schemaCount}, Count {totalCount}, Hash: {pgoHash}"); + } + } + + public string dumpMethodHashToBuffer(bool ignoreMethodName = false, CORINFO_METHOD_INFO* optInfo = null, uint optFlags = 0) + => Hash.HashBuffer(dumpMethodIdentityInfoToBuffer(ignoreMethodName, optInfo, optFlags)); + + public string dumpMethodHashToBuffer() => dumpMethodHashToBuffer(false, null, 0); + + // Dumps every map of the method context and its compile result. With 'simple', the header skips the + // method name, which is useful when debugging the name lookups themselves. + public void dumpToConsole(int mcNumber, bool simple) + { + Logger.Out.Write("*****************************************"); + if (mcNumber != -1) + Logger.Out.Write($" method context #{mcNumber}"); + if (!simple) + Logger.Out.Write(" " + System.Text.Encoding.UTF8.GetString(dumpMethodIdentityInfoToBuffer())); + Logger.Out.Write("\n"); + + dumpMaps(); + cr.dumpMaps(); + } + + // Permissive equality for the legacy duplicate removal: may treat too many method contexts as equal. + public bool Equal(MethodContext other) + { + CORINFO_METHOD_INFO otherInfo = other.repCompileMethod(out uint otherFlags, out CORINFO_OS otherOs); + CORINFO_METHOD_INFO ourInfo = repCompileMethod(out uint ourFlags, out CORINFO_OS ourOs); + + if (otherInfo.ILCodeSize != ourInfo.ILCodeSize || + otherInfo.args.numArgs != ourInfo.args.numArgs || + otherInfo.args.retType != ourInfo.args.retType || + otherInfo.locals.numArgs != ourInfo.locals.numArgs || + otherInfo.EHcount != ourInfo.EHcount || + otherInfo.options != ourInfo.options || + !new ReadOnlySpan(otherInfo.ILCode, (int)otherInfo.ILCodeSize).SequenceEqual(new ReadOnlySpan(ourInfo.ILCode, (int)ourInfo.ILCodeSize)) || + otherInfo.maxStack != ourInfo.maxStack || + otherInfo.regionKind != ourInfo.regionKind || + otherInfo.args.callConv != ourInfo.args.callConv || + otherInfo.args.cbSig != ourInfo.args.cbSig || + otherInfo.args.flags != ourInfo.args.flags || + otherInfo.locals.cbSig != ourInfo.locals.cbSig || + otherFlags != ourFlags || + otherOs != ourOs) + { + return false; + } + + return SoftMapsEqual(_maps, other._maps) && SoftMapsEqual(cr.Maps, other.cr.Maps); + } + + private static bool SoftMapsEqual(LightWeightMapBuffer[] ours, LightWeightMapBuffer[] theirs) + { + for (int i = 0; i < ours.Length; i++) + { + if (ours[i] == null ? theirs[i] != null : theirs[i] == null || ours[i].GetCount() != theirs[i].GetCount()) + return false; + } + return true; + } +} diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Maps.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Maps.cs new file mode 100644 index 00000000000000..92d18eff66aa01 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Maps.cs @@ -0,0 +1,507 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// The maps of a method context, one for each kind of JIT-EE interface call; each is a packet of the .mc format. + +namespace SuperPmi; + +public partial class MethodContext +{ + // The maps are serialized in this order. + internal static readonly MapInfo[] s_maps = + [ + new MapInfo(0, "AllocPgoInstrumentationBySchema", PacketId.AllocPgoInstrumentationBySchema, static () => new LightWeightMap()), + new MapInfo(1, "GetPgoInstrumentationResults", PacketId.GetPgoInstrumentationResults, static () => new LightWeightMap()), + new MapInfo(2, "AsCorInfoType", PacketId.AsCorInfoType, static () => new LightWeightMap()), + new MapInfo(3, "CanAccessClass", PacketId.CanAccessClass, static () => new LightWeightMap()), + new MapInfo(4, "CanCast", PacketId.CanCast, static () => new LightWeightMap()), + new MapInfo(5, "CanInline", PacketId.CanInline, static () => new LightWeightMap()), + new MapInfo(6, "CanTailCall", PacketId.CanTailCall, static () => new LightWeightMap()), + new MapInfo(7, "CheckMethodModifier", PacketId.CheckMethodModifier, static () => new LightWeightMap()), + new MapInfo(8, "CompareTypesForCast", PacketId.CompareTypesForCast, static () => new LightWeightMap()), + new MapInfo(9, "CompareTypesForEquality", PacketId.CompareTypesForEquality, static () => new LightWeightMap()), + new MapInfo(10, "CompileMethod", PacketId.CompileMethod, static () => new LightWeightMap()), + new MapInfo(11, "ConstructStringLiteral", PacketId.ConstructStringLiteral, static () => new LightWeightMap()), + new MapInfo(12, "ConvertPInvokeCalliToCall", PacketId.ConvertPInvokeCalliToCall, static () => new LightWeightMap()), + new MapInfo(13, "EmbedClassHandle", PacketId.EmbedClassHandle, static () => new LightWeightMap()), + new MapInfo(14, "EmbedFieldHandle", PacketId.EmbedFieldHandle, static () => new LightWeightMap()), + new MapInfo(15, "EmbedGenericHandle", PacketId.EmbedGenericHandle, static () => new LightWeightMap()), + new MapInfo(16, "EmbedMethodHandle", PacketId.EmbedMethodHandle, static () => new LightWeightMap()), + new MapInfo(17, "EmbedModuleHandle", PacketId.EmbedModuleHandle, static () => new LightWeightMap()), + new MapInfo(18, "GetThreadLocalFieldInfo", PacketId.GetThreadLocalFieldInfo, static () => new LightWeightMap()), + new MapInfo(19, "GetThreadLocalStaticBlocksInfo", PacketId.GetThreadLocalStaticBlocksInfo, static () => new LightWeightMap()), + new MapInfo(20, "GetThreadLocalStaticInfo_NativeAOT", PacketId.GetThreadLocalStaticInfo_NativeAOT, static () => new LightWeightMap()), + new MapInfo(21, "EmptyStringLiteral", PacketId.EmptyStringLiteral, static () => new DenseLightWeightMap()), + new MapInfo(22, "ErrorList", PacketId.ErrorList, static () => new DenseLightWeightMap()), + new MapInfo(23, "FindCallSiteSig", PacketId.FindCallSiteSig, static () => new LightWeightMap()), + new MapInfo(24, "FindSig", PacketId.FindSig, static () => new LightWeightMap()), + new MapInfo(25, "GetAddressOfPInvokeTarget", PacketId.GetAddressOfPInvokeTarget, static () => new LightWeightMap()), + new MapInfo(26, "GetAddrOfCaptureThreadGlobal", PacketId.GetAddrOfCaptureThreadGlobal, static () => new LightWeightMap()), + new MapInfo(27, "GetArgClass", PacketId.GetArgClass, static () => new LightWeightMap()), + new MapInfo(28, "GetArgNext", PacketId.GetArgNext, static () => new LightWeightMap()), + new MapInfo(29, "GetArgType", PacketId.GetArgType, static () => new LightWeightMap()), + new MapInfo(30, "GetExactClasses", PacketId.GetExactClasses, static () => new LightWeightMap()), + new MapInfo(31, "GetArrayInitializationData", PacketId.GetArrayInitializationData, static () => new LightWeightMap()), + new MapInfo(32, "GetArrayRank", PacketId.GetArrayRank, static () => new LightWeightMap()), + new MapInfo(33, "GetArrayIntrinsicID", PacketId.GetArrayIntrinsicID, static () => new LightWeightMap()), + new MapInfo(34, "GetBoundaries", PacketId.GetBoundaries, static () => new LightWeightMap()), + new MapInfo(35, "GetBoxHelper", PacketId.GetBoxHelper, static () => new LightWeightMap()), + new MapInfo(36, "GetBuiltinClass", PacketId.GetBuiltinClass, static () => new LightWeightMap()), + new MapInfo(37, "GetCallInfo", PacketId.GetCallInfo, static () => new LightWeightMap()), + new MapInfo(38, "GetCastingHelper", PacketId.GetCastingHelper, static () => new LightWeightMap()), + new MapInfo(39, "GetChildType", PacketId.GetChildType, static () => new LightWeightMap()), + new MapInfo(40, "GetClassAlignmentRequirement", PacketId.GetClassAlignmentRequirement, static () => new LightWeightMap()), + new MapInfo(41, "GetClassAttribs", PacketId.GetClassAttribs, static () => new LightWeightMap()), + new MapInfo(42, "GetClassStaticDynamicInfo", PacketId.GetClassStaticDynamicInfo, static () => new LightWeightMap()), + new MapInfo(43, "GetClassThreadStaticDynamicInfo", PacketId.GetClassThreadStaticDynamicInfo, static () => new LightWeightMap()), + new MapInfo(44, "GetClassGClayout", PacketId.GetClassGClayout, static () => new LightWeightMap()), + new MapInfo(45, "GetClassModuleIdForStatics", PacketId.GetClassModuleIdForStatics, static () => new LightWeightMap()), + new MapInfo(46, "GetIsClassInitedFlagAddress", PacketId.GetIsClassInitedFlagAddress, static () => new LightWeightMap()), + new MapInfo(47, "GetStaticBaseAddress", PacketId.GetStaticBaseAddress, static () => new LightWeightMap()), + new MapInfo(48, "GetClassNameFromMetadata", PacketId.GetClassNameFromMetadata, static () => new LightWeightMap()), + new MapInfo(49, "GetTypeInstantiationArgument", PacketId.GetTypeInstantiationArgument, static () => new LightWeightMap()), + new MapInfo(50, "GetMethodInstantiationArgument", PacketId.GetMethodInstantiationArgument, static () => new LightWeightMap()), + new MapInfo(51, "GetClassNumInstanceFields", PacketId.GetClassNumInstanceFields, static () => new LightWeightMap()), + new MapInfo(52, "GetClassSize", PacketId.GetClassSize, static () => new LightWeightMap()), + new MapInfo(53, "GetHeapClassSize", PacketId.GetHeapClassSize, static () => new LightWeightMap()), + new MapInfo(54, "CanAllocateOnStack", PacketId.CanAllocateOnStack, static () => new LightWeightMap()), + new MapInfo(55, "GetCookieForInterpreterCalliSig", PacketId.GetCookieForInterpreterCalliSig, static () => new LightWeightMap()), + new MapInfo(56, "GetDefaultComparerClass", PacketId.GetDefaultComparerClass, static () => new LightWeightMap()), + new MapInfo(57, "GetDefaultEqualityComparerClass", PacketId.GetDefaultEqualityComparerClass, static () => new LightWeightMap()), + new MapInfo(58, "GetSZArrayHelperEnumeratorClass", PacketId.GetSZArrayHelperEnumeratorClass, static () => new LightWeightMap()), + new MapInfo(59, "GetDelegateCtor", PacketId.GetDelegateCtor, static () => new LightWeightMap()), + new MapInfo(60, "GetEEInfo", PacketId.GetEEInfo, static () => new LightWeightMap()), + new MapInfo(61, "GetAsyncInfo", PacketId.GetAsyncInfo, static () => new LightWeightMap()), + new MapInfo(62, "GetAwaitReturnCall", PacketId.GetAwaitReturnCall, static () => new LightWeightMap()), + new MapInfo(63, "GetAwaitAwaiterInContinuationCall", PacketId.GetAwaitAwaiterInContinuationCall, static () => new LightWeightMap()), + new MapInfo(64, "GetEHinfo", PacketId.GetEHinfo, static () => new LightWeightMap()), + new MapInfo(65, "GetStaticFieldContent", PacketId.GetStaticFieldContent, static () => new LightWeightMap()), + new MapInfo(66, "GetObjectContent", PacketId.GetObjectContent, static () => new LightWeightMap()), + new MapInfo(67, "GetStaticFieldCurrentClass", PacketId.GetStaticFieldCurrentClass, static () => new LightWeightMap()), + new MapInfo(68, "GetFieldClass", PacketId.GetFieldClass, static () => new LightWeightMap()), + new MapInfo(69, "GetFieldInClass", PacketId.GetFieldInClass, static () => new LightWeightMap()), + new MapInfo(70, "GetTypeLayout", PacketId.GetTypeLayout, static () => new LightWeightMap()), + new MapInfo(71, "GetFieldInfo", PacketId.GetFieldInfo, static () => new LightWeightMap()), + new MapInfo(72, "GetFieldOffset", PacketId.GetFieldOffset, static () => new LightWeightMap()), + new MapInfo(73, "GetFieldThreadLocalStoreID", PacketId.GetFieldThreadLocalStoreID, static () => new LightWeightMap()), + new MapInfo(74, "GetFieldType", PacketId.GetFieldType, static () => new LightWeightMap()), + new MapInfo(75, "GetFunctionEntryPoint", PacketId.GetFunctionEntryPoint, static () => new LightWeightMap()), + new MapInfo(76, "GetFunctionFixedEntryPoint", PacketId.GetFunctionFixedEntryPoint, static () => new LightWeightMap()), + new MapInfo(77, "GetGSCookie", PacketId.GetGSCookie, static () => new LightWeightMap()), + new MapInfo(78, "GetHelperFtn", PacketId.GetHelperFtn, static () => new LightWeightMap()), + new MapInfo(79, "GetHFAType", PacketId.GetHFAType, static () => new LightWeightMap()), + new MapInfo(80, "GetIntConfigValue", PacketId.GetIntConfigValue, static () => new LightWeightMap()), + new MapInfo(81, "GetJitFlags", PacketId.GetJitFlags, static () => new LightWeightMap()), + new MapInfo(82, "GetJustMyCodeHandle", PacketId.GetJustMyCodeHandle, static () => new LightWeightMap()), + new MapInfo(83, "GetLocationOfThisType", PacketId.GetLocationOfThisType, static () => new LightWeightMap()), + new MapInfo(84, "IsIntrinsic", PacketId.IsIntrinsic, static () => new LightWeightMap()), + new MapInfo(85, "NotifyMethodInfoUsage", PacketId.NotifyMethodInfoUsage, static () => new LightWeightMap()), + new MapInfo(86, "NotifyInstructionSetUsage", PacketId.NotifyInstructionSetUsage, static () => new LightWeightMap()), + new MapInfo(87, "GetMethodAttribs", PacketId.GetMethodAttribs, static () => new LightWeightMap()), + new MapInfo(88, "GetClassAssemblyName", PacketId.GetClassAssemblyName, static () => new LightWeightMap()), + new MapInfo(89, "GetMethodClass", PacketId.GetMethodClass, static () => new LightWeightMap()), + new MapInfo(90, "GetMethodDefFromMethod", PacketId.GetMethodDefFromMethod, static () => new LightWeightMap()), + new MapInfo(91, "GetMethodHash", PacketId.GetMethodHash, static () => new LightWeightMap()), + new MapInfo(92, "GetMethodInfo", PacketId.GetMethodInfo, static () => new LightWeightMap()), + new MapInfo(93, "HaveSameMethodDefinition", PacketId.HaveSameMethodDefinition, static () => new LightWeightMap()), + new MapInfo(94, "GetTypeDefinition", PacketId.GetTypeDefinition, static () => new LightWeightMap()), + new MapInfo(95, "GetMethodNameFromMetadata", PacketId.GetMethodNameFromMetadata, static () => new LightWeightMap()), + new MapInfo(96, "GetMethodSig", PacketId.GetMethodSig, static () => new LightWeightMap()), + new MapInfo(97, "GetMethodVTableOffset", PacketId.GetMethodVTableOffset, static () => new LightWeightMap()), + new MapInfo(98, "GetNewArrHelper", PacketId.GetNewArrHelper, static () => new LightWeightMap()), + new MapInfo(99, "GetNewHelper", PacketId.GetNewHelper, static () => new LightWeightMap()), + new MapInfo(100, "GetOSRInfo", PacketId.GetOSRInfo, static () => new LightWeightMap()), + new MapInfo(101, "GetParentType", PacketId.GetParentType, static () => new LightWeightMap()), + new MapInfo(102, "GetProfilingHandle", PacketId.GetProfilingHandle, static () => new LightWeightMap()), + new MapInfo(103, "GetReadyToRunHelper", PacketId.GetReadyToRunHelper, static () => new LightWeightMap()), + new MapInfo(104, "GetReadyToRunDelegateCtorHelper", PacketId.GetReadyToRunDelegateCtorHelper, static () => new LightWeightMap()), + new MapInfo(105, "GetRelocTypeHint", PacketId.GetRelocTypeHint, static () => new LightWeightMap()), + new MapInfo(106, "GetExpectedTargetArchitecture", PacketId.GetExpectedTargetArchitecture, static () => new LightWeightMap()), + new MapInfo(107, "GetSharedCCtorHelper", PacketId.GetSharedCCtorHelper, static () => new LightWeightMap()), + new MapInfo(108, "GetStringConfigValue", PacketId.GetStringConfigValue, static () => new LightWeightMap()), + new MapInfo(109, "GetSystemVAmd64PassStructInRegisterDescriptor", PacketId.GetSystemVAmd64PassStructInRegisterDescriptor, static () => new LightWeightMap()), + new MapInfo(110, "GetSwiftLowering", PacketId.GetSwiftLowering, static () => new LightWeightMap()), + new MapInfo(111, "GetFpStructLowering", PacketId.GetFpStructLowering, static () => new LightWeightMap()), + new MapInfo(112, "GetWasmLowering", PacketId.GetWasmLowering, static () => new LightWeightMap()), + new MapInfo(113, "GetTailCallHelpers", PacketId.GetTailCallHelpers, static () => new LightWeightMap()), + new MapInfo(114, "GetAsyncResumptionStub", PacketId.GetAsyncResumptionStub, static () => new LightWeightMap()), + new MapInfo(115, "GetContinuationType", PacketId.GetContinuationType, static () => new LightWeightMap()), + new MapInfo(116, "UpdateEntryPointForTailCall", PacketId.UpdateEntryPointForTailCall, static () => new LightWeightMap()), + new MapInfo(117, "GetSpecialCopyHelper", PacketId.GetSpecialCopyHelper, static () => new LightWeightMap()), + new MapInfo(118, "GetThreadTLSIndex", PacketId.GetThreadTLSIndex, static () => new LightWeightMap()), + new MapInfo(119, "GetTokenTypeAsHandle", PacketId.GetTokenTypeAsHandle, static () => new LightWeightMap()), + new MapInfo(120, "GetTypeForBox", PacketId.GetTypeForBox, static () => new LightWeightMap()), + new MapInfo(121, "GetTypeForPrimitiveValueClass", PacketId.GetTypeForPrimitiveValueClass, static () => new LightWeightMap()), + new MapInfo(122, "GetTypeForPrimitiveNumericClass", PacketId.GetTypeForPrimitiveNumericClass, static () => new LightWeightMap()), + new MapInfo(123, "GetAsyncOtherVariant", PacketId.GetAsyncOtherVariant, static () => new LightWeightMap()), + new MapInfo(124, "GetUnBoxHelper", PacketId.GetUnBoxHelper, static () => new LightWeightMap()), + new MapInfo(125, "GetRuntimeTypePointer", PacketId.GetRuntimeTypePointer, static () => new LightWeightMap()), + new MapInfo(126, "IsObjectImmutable", PacketId.IsObjectImmutable, static () => new LightWeightMap()), + new MapInfo(127, "GetStringChar", PacketId.GetStringChar, static () => new LightWeightMap()), + new MapInfo(128, "GetObjectType", PacketId.GetObjectType, static () => new LightWeightMap()), + new MapInfo(129, "GetVarArgsHandle", PacketId.GetVarArgsHandle, static () => new LightWeightMap()), + new MapInfo(130, "GetVars", PacketId.GetVars, static () => new LightWeightMap()), + new MapInfo(131, "InitClass", PacketId.InitClass, static () => new LightWeightMap()), + new MapInfo(132, "IsDelegateCreationAllowed", PacketId.IsDelegateCreationAllowed, static () => new LightWeightMap()), + new MapInfo(133, "IsFieldStatic", PacketId.IsFieldStatic, static () => new LightWeightMap()), + new MapInfo(134, "GetArrayOrStringLength", PacketId.GetArrayOrStringLength, static () => new LightWeightMap()), + new MapInfo(135, "ExpandRawHandleIntrinsic", PacketId.ExpandRawHandleIntrinsic, static () => new LightWeightMap()), + new MapInfo(136, "IsIntrinsicType", PacketId.IsIntrinsicType, static () => new LightWeightMap()), + new MapInfo(137, "IsSDArray", PacketId.IsSDArray, static () => new LightWeightMap()), + new MapInfo(138, "GetStringLiteral", PacketId.GetStringLiteral, static () => new LightWeightMap()), + new MapInfo(139, "PrintObjectDescription", PacketId.PrintObjectDescription, static () => new LightWeightMap()), + new MapInfo(140, "PrintClassName", PacketId.PrintClassName, static () => new LightWeightMap()), + new MapInfo(141, "PrintFieldName", PacketId.PrintFieldName, static () => new LightWeightMap()), + new MapInfo(142, "PrintMethodName", PacketId.PrintMethodName, static () => new LightWeightMap()), + new MapInfo(143, "IsValueClass", PacketId.IsValueClass, static () => new LightWeightMap()), + new MapInfo(144, "IsMoreSpecificType", PacketId.IsMoreSpecificType, static () => new LightWeightMap()), + new MapInfo(145, "IsExactType", PacketId.IsExactType, static () => new LightWeightMap()), + new MapInfo(146, "IsGenericType", PacketId.IsGenericType, static () => new LightWeightMap()), + new MapInfo(147, "IsNullableType", PacketId.IsNullableType, static () => new LightWeightMap()), + new MapInfo(148, "IsEnum", PacketId.IsEnum, static () => new LightWeightMap()), + new MapInfo(149, "PInvokeMarshalingRequired", PacketId.PInvokeMarshalingRequired, static () => new LightWeightMap()), + new MapInfo(150, "ResolveToken", PacketId.ResolveToken, static () => new LightWeightMap()), + new MapInfo(151, "ResolveVirtualMethod", PacketId.ResolveVirtualMethod, static () => new LightWeightMap()), + new MapInfo(152, "SatisfiesMethodConstraints", PacketId.SatisfiesMethodConstraints, static () => new LightWeightMap()), + new MapInfo(153, "GetUnmanagedCallConv", PacketId.GetUnmanagedCallConv, static () => new LightWeightMap()), + new MapInfo(154, "DoesFieldBelongToClass", PacketId.DoesFieldBelongToClass, static () => new LightWeightMap()), + new MapInfo(155, "SigInstHandleMap", PacketId.SigInstHandleMap, static () => new DenseLightWeightMap()), + new MapInfo(156, "GetWasmTypeSymbol", PacketId.GetWasmTypeSymbol, static () => new LightWeightMap()), + new MapInfo(157, "GetAddressAlignment", PacketId.GetAddressAlignment, static () => new LightWeightMap()), + new MapInfo(158, "CanValueClassInstancePointerEscape", PacketId.CanValueClassInstancePointerEscape, static () => new LightWeightMap()), + new MapInfo(159, "GetWasmWellKnownGlobals", PacketId.GetWasmWellKnownGlobals, static () => new LightWeightMap()), + new MapInfo(160, "IsByRefLike", PacketId.IsByRefLike, static () => new LightWeightMap()), + new MapInfo(161, "IsSharedInst", PacketId.IsSharedInst, static () => new LightWeightMap()), + ]; + + private readonly LightWeightMapBuffer[] _maps = new LightWeightMapBuffer[s_maps.Length]; + + public LightWeightMap AllocPgoInstrumentationBySchema { get => (LightWeightMap)_maps[0]; set => _maps[0] = value; } + public LightWeightMap GetPgoInstrumentationResults { get => (LightWeightMap)_maps[1]; set => _maps[1] = value; } + public LightWeightMap AsCorInfoType { get => (LightWeightMap)_maps[2]; set => _maps[2] = value; } + public LightWeightMap CanAccessClass { get => (LightWeightMap)_maps[3]; set => _maps[3] = value; } + public LightWeightMap CanCast { get => (LightWeightMap)_maps[4]; set => _maps[4] = value; } + public LightWeightMap CanInline { get => (LightWeightMap)_maps[5]; set => _maps[5] = value; } + public LightWeightMap CanTailCall { get => (LightWeightMap)_maps[6]; set => _maps[6] = value; } + public LightWeightMap CheckMethodModifier { get => (LightWeightMap)_maps[7]; set => _maps[7] = value; } + public LightWeightMap CompareTypesForCast { get => (LightWeightMap)_maps[8]; set => _maps[8] = value; } + public LightWeightMap CompareTypesForEquality { get => (LightWeightMap)_maps[9]; set => _maps[9] = value; } + public LightWeightMap CompileMethod { get => (LightWeightMap)_maps[10]; set => _maps[10] = value; } + public LightWeightMap ConstructStringLiteral { get => (LightWeightMap)_maps[11]; set => _maps[11] = value; } + public LightWeightMap ConvertPInvokeCalliToCall { get => (LightWeightMap)_maps[12]; set => _maps[12] = value; } + public LightWeightMap EmbedClassHandle { get => (LightWeightMap)_maps[13]; set => _maps[13] = value; } + public LightWeightMap EmbedFieldHandle { get => (LightWeightMap)_maps[14]; set => _maps[14] = value; } + public LightWeightMap EmbedGenericHandle { get => (LightWeightMap)_maps[15]; set => _maps[15] = value; } + public LightWeightMap EmbedMethodHandle { get => (LightWeightMap)_maps[16]; set => _maps[16] = value; } + public LightWeightMap EmbedModuleHandle { get => (LightWeightMap)_maps[17]; set => _maps[17] = value; } + public LightWeightMap GetThreadLocalFieldInfo { get => (LightWeightMap)_maps[18]; set => _maps[18] = value; } + public LightWeightMap GetThreadLocalStaticBlocksInfo { get => (LightWeightMap)_maps[19]; set => _maps[19] = value; } + public LightWeightMap GetThreadLocalStaticInfo_NativeAOT { get => (LightWeightMap)_maps[20]; set => _maps[20] = value; } + public DenseLightWeightMap EmptyStringLiteral { get => (DenseLightWeightMap)_maps[21]; set => _maps[21] = value; } + public DenseLightWeightMap ErrorList { get => (DenseLightWeightMap)_maps[22]; set => _maps[22] = value; } + public LightWeightMap FindCallSiteSig { get => (LightWeightMap)_maps[23]; set => _maps[23] = value; } + public LightWeightMap FindSig { get => (LightWeightMap)_maps[24]; set => _maps[24] = value; } + public LightWeightMap GetAddressOfPInvokeTarget { get => (LightWeightMap)_maps[25]; set => _maps[25] = value; } + public LightWeightMap GetAddrOfCaptureThreadGlobal { get => (LightWeightMap)_maps[26]; set => _maps[26] = value; } + public LightWeightMap GetArgClass { get => (LightWeightMap)_maps[27]; set => _maps[27] = value; } + public LightWeightMap GetArgNext { get => (LightWeightMap)_maps[28]; set => _maps[28] = value; } + public LightWeightMap GetArgType { get => (LightWeightMap)_maps[29]; set => _maps[29] = value; } + public LightWeightMap GetExactClasses { get => (LightWeightMap)_maps[30]; set => _maps[30] = value; } + public LightWeightMap GetArrayInitializationData { get => (LightWeightMap)_maps[31]; set => _maps[31] = value; } + public LightWeightMap GetArrayRank { get => (LightWeightMap)_maps[32]; set => _maps[32] = value; } + public LightWeightMap GetArrayIntrinsicID { get => (LightWeightMap)_maps[33]; set => _maps[33] = value; } + public LightWeightMap GetBoundaries { get => (LightWeightMap)_maps[34]; set => _maps[34] = value; } + public LightWeightMap GetBoxHelper { get => (LightWeightMap)_maps[35]; set => _maps[35] = value; } + public LightWeightMap GetBuiltinClass { get => (LightWeightMap)_maps[36]; set => _maps[36] = value; } + public LightWeightMap GetCallInfo { get => (LightWeightMap)_maps[37]; set => _maps[37] = value; } + public LightWeightMap GetCastingHelper { get => (LightWeightMap)_maps[38]; set => _maps[38] = value; } + public LightWeightMap GetChildType { get => (LightWeightMap)_maps[39]; set => _maps[39] = value; } + public LightWeightMap GetClassAlignmentRequirement { get => (LightWeightMap)_maps[40]; set => _maps[40] = value; } + public LightWeightMap GetClassAttribs { get => (LightWeightMap)_maps[41]; set => _maps[41] = value; } + public LightWeightMap GetClassStaticDynamicInfo { get => (LightWeightMap)_maps[42]; set => _maps[42] = value; } + public LightWeightMap GetClassThreadStaticDynamicInfo { get => (LightWeightMap)_maps[43]; set => _maps[43] = value; } + public LightWeightMap GetClassGClayout { get => (LightWeightMap)_maps[44]; set => _maps[44] = value; } + public LightWeightMap GetClassModuleIdForStatics { get => (LightWeightMap)_maps[45]; set => _maps[45] = value; } + public LightWeightMap GetIsClassInitedFlagAddress { get => (LightWeightMap)_maps[46]; set => _maps[46] = value; } + public LightWeightMap GetStaticBaseAddress { get => (LightWeightMap)_maps[47]; set => _maps[47] = value; } + public LightWeightMap GetClassNameFromMetadata { get => (LightWeightMap)_maps[48]; set => _maps[48] = value; } + public LightWeightMap GetTypeInstantiationArgument { get => (LightWeightMap)_maps[49]; set => _maps[49] = value; } + public LightWeightMap GetMethodInstantiationArgument { get => (LightWeightMap)_maps[50]; set => _maps[50] = value; } + public LightWeightMap GetClassNumInstanceFields { get => (LightWeightMap)_maps[51]; set => _maps[51] = value; } + public LightWeightMap GetClassSize { get => (LightWeightMap)_maps[52]; set => _maps[52] = value; } + public LightWeightMap GetHeapClassSize { get => (LightWeightMap)_maps[53]; set => _maps[53] = value; } + public LightWeightMap CanAllocateOnStack { get => (LightWeightMap)_maps[54]; set => _maps[54] = value; } + public LightWeightMap GetCookieForInterpreterCalliSig { get => (LightWeightMap)_maps[55]; set => _maps[55] = value; } + public LightWeightMap GetDefaultComparerClass { get => (LightWeightMap)_maps[56]; set => _maps[56] = value; } + public LightWeightMap GetDefaultEqualityComparerClass { get => (LightWeightMap)_maps[57]; set => _maps[57] = value; } + public LightWeightMap GetSZArrayHelperEnumeratorClass { get => (LightWeightMap)_maps[58]; set => _maps[58] = value; } + public LightWeightMap GetDelegateCtor { get => (LightWeightMap)_maps[59]; set => _maps[59] = value; } + public LightWeightMap GetEEInfo { get => (LightWeightMap)_maps[60]; set => _maps[60] = value; } + public LightWeightMap GetAsyncInfo { get => (LightWeightMap)_maps[61]; set => _maps[61] = value; } + public LightWeightMap GetAwaitReturnCall { get => (LightWeightMap)_maps[62]; set => _maps[62] = value; } + public LightWeightMap GetAwaitAwaiterInContinuationCall { get => (LightWeightMap)_maps[63]; set => _maps[63] = value; } + public LightWeightMap GetEHinfo { get => (LightWeightMap)_maps[64]; set => _maps[64] = value; } + public LightWeightMap GetStaticFieldContent { get => (LightWeightMap)_maps[65]; set => _maps[65] = value; } + public LightWeightMap GetObjectContent { get => (LightWeightMap)_maps[66]; set => _maps[66] = value; } + public LightWeightMap GetStaticFieldCurrentClass { get => (LightWeightMap)_maps[67]; set => _maps[67] = value; } + public LightWeightMap GetFieldClass { get => (LightWeightMap)_maps[68]; set => _maps[68] = value; } + public LightWeightMap GetFieldInClass { get => (LightWeightMap)_maps[69]; set => _maps[69] = value; } + public LightWeightMap GetTypeLayout { get => (LightWeightMap)_maps[70]; set => _maps[70] = value; } + public LightWeightMap GetFieldInfo { get => (LightWeightMap)_maps[71]; set => _maps[71] = value; } + public LightWeightMap GetFieldOffset { get => (LightWeightMap)_maps[72]; set => _maps[72] = value; } + public LightWeightMap GetFieldThreadLocalStoreID { get => (LightWeightMap)_maps[73]; set => _maps[73] = value; } + public LightWeightMap GetFieldType { get => (LightWeightMap)_maps[74]; set => _maps[74] = value; } + public LightWeightMap GetFunctionEntryPoint { get => (LightWeightMap)_maps[75]; set => _maps[75] = value; } + public LightWeightMap GetFunctionFixedEntryPoint { get => (LightWeightMap)_maps[76]; set => _maps[76] = value; } + public LightWeightMap GetGSCookie { get => (LightWeightMap)_maps[77]; set => _maps[77] = value; } + public LightWeightMap GetHelperFtn { get => (LightWeightMap)_maps[78]; set => _maps[78] = value; } + public LightWeightMap GetHFAType { get => (LightWeightMap)_maps[79]; set => _maps[79] = value; } + public LightWeightMap GetIntConfigValue { get => (LightWeightMap)_maps[80]; set => _maps[80] = value; } + public LightWeightMap GetJitFlags { get => (LightWeightMap)_maps[81]; set => _maps[81] = value; } + public LightWeightMap GetJustMyCodeHandle { get => (LightWeightMap)_maps[82]; set => _maps[82] = value; } + public LightWeightMap GetLocationOfThisType { get => (LightWeightMap)_maps[83]; set => _maps[83] = value; } + public LightWeightMap IsIntrinsic { get => (LightWeightMap)_maps[84]; set => _maps[84] = value; } + public LightWeightMap NotifyMethodInfoUsage { get => (LightWeightMap)_maps[85]; set => _maps[85] = value; } + public LightWeightMap NotifyInstructionSetUsage { get => (LightWeightMap)_maps[86]; set => _maps[86] = value; } + public LightWeightMap GetMethodAttribs { get => (LightWeightMap)_maps[87]; set => _maps[87] = value; } + public LightWeightMap GetClassAssemblyName { get => (LightWeightMap)_maps[88]; set => _maps[88] = value; } + public LightWeightMap GetMethodClass { get => (LightWeightMap)_maps[89]; set => _maps[89] = value; } + public LightWeightMap GetMethodDefFromMethod { get => (LightWeightMap)_maps[90]; set => _maps[90] = value; } + public LightWeightMap GetMethodHash { get => (LightWeightMap)_maps[91]; set => _maps[91] = value; } + public LightWeightMap GetMethodInfo { get => (LightWeightMap)_maps[92]; set => _maps[92] = value; } + public LightWeightMap HaveSameMethodDefinition { get => (LightWeightMap)_maps[93]; set => _maps[93] = value; } + public LightWeightMap GetTypeDefinition { get => (LightWeightMap)_maps[94]; set => _maps[94] = value; } + public LightWeightMap GetMethodNameFromMetadata { get => (LightWeightMap)_maps[95]; set => _maps[95] = value; } + public LightWeightMap GetMethodSig { get => (LightWeightMap)_maps[96]; set => _maps[96] = value; } + public LightWeightMap GetMethodVTableOffset { get => (LightWeightMap)_maps[97]; set => _maps[97] = value; } + public LightWeightMap GetNewArrHelper { get => (LightWeightMap)_maps[98]; set => _maps[98] = value; } + public LightWeightMap GetNewHelper { get => (LightWeightMap)_maps[99]; set => _maps[99] = value; } + public LightWeightMap GetOSRInfo { get => (LightWeightMap)_maps[100]; set => _maps[100] = value; } + public LightWeightMap GetParentType { get => (LightWeightMap)_maps[101]; set => _maps[101] = value; } + public LightWeightMap GetProfilingHandle { get => (LightWeightMap)_maps[102]; set => _maps[102] = value; } + public LightWeightMap GetReadyToRunHelper { get => (LightWeightMap)_maps[103]; set => _maps[103] = value; } + public LightWeightMap GetReadyToRunDelegateCtorHelper { get => (LightWeightMap)_maps[104]; set => _maps[104] = value; } + public LightWeightMap GetRelocTypeHint { get => (LightWeightMap)_maps[105]; set => _maps[105] = value; } + public LightWeightMap GetExpectedTargetArchitecture { get => (LightWeightMap)_maps[106]; set => _maps[106] = value; } + public LightWeightMap GetSharedCCtorHelper { get => (LightWeightMap)_maps[107]; set => _maps[107] = value; } + public LightWeightMap GetStringConfigValue { get => (LightWeightMap)_maps[108]; set => _maps[108] = value; } + public LightWeightMap GetSystemVAmd64PassStructInRegisterDescriptor { get => (LightWeightMap)_maps[109]; set => _maps[109] = value; } + public LightWeightMap GetSwiftLowering { get => (LightWeightMap)_maps[110]; set => _maps[110] = value; } + public LightWeightMap GetFpStructLowering { get => (LightWeightMap)_maps[111]; set => _maps[111] = value; } + public LightWeightMap GetWasmLowering { get => (LightWeightMap)_maps[112]; set => _maps[112] = value; } + public LightWeightMap GetTailCallHelpers { get => (LightWeightMap)_maps[113]; set => _maps[113] = value; } + public LightWeightMap GetAsyncResumptionStub { get => (LightWeightMap)_maps[114]; set => _maps[114] = value; } + public LightWeightMap GetContinuationType { get => (LightWeightMap)_maps[115]; set => _maps[115] = value; } + public LightWeightMap UpdateEntryPointForTailCall { get => (LightWeightMap)_maps[116]; set => _maps[116] = value; } + public LightWeightMap GetSpecialCopyHelper { get => (LightWeightMap)_maps[117]; set => _maps[117] = value; } + public LightWeightMap GetThreadTLSIndex { get => (LightWeightMap)_maps[118]; set => _maps[118] = value; } + public LightWeightMap GetTokenTypeAsHandle { get => (LightWeightMap)_maps[119]; set => _maps[119] = value; } + public LightWeightMap GetTypeForBox { get => (LightWeightMap)_maps[120]; set => _maps[120] = value; } + public LightWeightMap GetTypeForPrimitiveValueClass { get => (LightWeightMap)_maps[121]; set => _maps[121] = value; } + public LightWeightMap GetTypeForPrimitiveNumericClass { get => (LightWeightMap)_maps[122]; set => _maps[122] = value; } + public LightWeightMap GetAsyncOtherVariant { get => (LightWeightMap)_maps[123]; set => _maps[123] = value; } + public LightWeightMap GetUnBoxHelper { get => (LightWeightMap)_maps[124]; set => _maps[124] = value; } + public LightWeightMap GetRuntimeTypePointer { get => (LightWeightMap)_maps[125]; set => _maps[125] = value; } + public LightWeightMap IsObjectImmutable { get => (LightWeightMap)_maps[126]; set => _maps[126] = value; } + public LightWeightMap GetStringChar { get => (LightWeightMap)_maps[127]; set => _maps[127] = value; } + public LightWeightMap GetObjectType { get => (LightWeightMap)_maps[128]; set => _maps[128] = value; } + public LightWeightMap GetVarArgsHandle { get => (LightWeightMap)_maps[129]; set => _maps[129] = value; } + public LightWeightMap GetVars { get => (LightWeightMap)_maps[130]; set => _maps[130] = value; } + public LightWeightMap InitClass { get => (LightWeightMap)_maps[131]; set => _maps[131] = value; } + public LightWeightMap IsDelegateCreationAllowed { get => (LightWeightMap)_maps[132]; set => _maps[132] = value; } + public LightWeightMap IsFieldStatic { get => (LightWeightMap)_maps[133]; set => _maps[133] = value; } + public LightWeightMap GetArrayOrStringLength { get => (LightWeightMap)_maps[134]; set => _maps[134] = value; } + public LightWeightMap ExpandRawHandleIntrinsic { get => (LightWeightMap)_maps[135]; set => _maps[135] = value; } + public LightWeightMap IsIntrinsicType { get => (LightWeightMap)_maps[136]; set => _maps[136] = value; } + public LightWeightMap IsSDArray { get => (LightWeightMap)_maps[137]; set => _maps[137] = value; } + public LightWeightMap GetStringLiteral { get => (LightWeightMap)_maps[138]; set => _maps[138] = value; } + public LightWeightMap PrintObjectDescription { get => (LightWeightMap)_maps[139]; set => _maps[139] = value; } + public LightWeightMap PrintClassName { get => (LightWeightMap)_maps[140]; set => _maps[140] = value; } + public LightWeightMap PrintFieldName { get => (LightWeightMap)_maps[141]; set => _maps[141] = value; } + public LightWeightMap PrintMethodName { get => (LightWeightMap)_maps[142]; set => _maps[142] = value; } + public LightWeightMap IsValueClass { get => (LightWeightMap)_maps[143]; set => _maps[143] = value; } + public LightWeightMap IsMoreSpecificType { get => (LightWeightMap)_maps[144]; set => _maps[144] = value; } + public LightWeightMap IsExactType { get => (LightWeightMap)_maps[145]; set => _maps[145] = value; } + public LightWeightMap IsGenericType { get => (LightWeightMap)_maps[146]; set => _maps[146] = value; } + public LightWeightMap IsNullableType { get => (LightWeightMap)_maps[147]; set => _maps[147] = value; } + public LightWeightMap IsEnum { get => (LightWeightMap)_maps[148]; set => _maps[148] = value; } + public LightWeightMap PInvokeMarshalingRequired { get => (LightWeightMap)_maps[149]; set => _maps[149] = value; } + public LightWeightMap ResolveToken { get => (LightWeightMap)_maps[150]; set => _maps[150] = value; } + public LightWeightMap ResolveVirtualMethod { get => (LightWeightMap)_maps[151]; set => _maps[151] = value; } + public LightWeightMap SatisfiesMethodConstraints { get => (LightWeightMap)_maps[152]; set => _maps[152] = value; } + public LightWeightMap GetUnmanagedCallConv { get => (LightWeightMap)_maps[153]; set => _maps[153] = value; } + public LightWeightMap DoesFieldBelongToClass { get => (LightWeightMap)_maps[154]; set => _maps[154] = value; } + public DenseLightWeightMap SigInstHandleMap { get => (DenseLightWeightMap)_maps[155]; set => _maps[155] = value; } + public LightWeightMap GetWasmTypeSymbol { get => (LightWeightMap)_maps[156]; set => _maps[156] = value; } + public LightWeightMap GetAddressAlignment { get => (LightWeightMap)_maps[157]; set => _maps[157] = value; } + public LightWeightMap CanValueClassInstancePointerEscape { get => (LightWeightMap)_maps[158]; set => _maps[158] = value; } + public LightWeightMap GetWasmWellKnownGlobals { get => (LightWeightMap)_maps[159]; set => _maps[159] = value; } + public LightWeightMap IsByRefLike { get => (LightWeightMap)_maps[160]; set => _maps[160] = value; } + public LightWeightMap IsSharedInst { get => (LightWeightMap)_maps[161]; set => _maps[161] = value; } + + internal void dumpMaps() + { + MapDumper.Dump(nameof(AllocPgoInstrumentationBySchema), AllocPgoInstrumentationBySchema, (k, v) => dmpAllocPgoInstrumentationBySchema(k, v)); + MapDumper.Dump(nameof(GetPgoInstrumentationResults), GetPgoInstrumentationResults, (k, v) => dmpGetPgoInstrumentationResults(k, v)); + MapDumper.Dump(nameof(AsCorInfoType), AsCorInfoType, (k, v) => dmpAsCorInfoType(k, v)); + MapDumper.Dump(nameof(CanAccessClass), CanAccessClass, (k, v) => dmpCanAccessClass(k, v)); + MapDumper.Dump(nameof(CanCast), CanCast, (k, v) => dmpCanCast(k, v)); + MapDumper.Dump(nameof(CanInline), CanInline, (k, v) => dmpCanInline(k, v)); + MapDumper.Dump(nameof(CanTailCall), CanTailCall, (k, v) => dmpCanTailCall(k, v)); + MapDumper.Dump(nameof(CheckMethodModifier), CheckMethodModifier, (k, v) => dmpCheckMethodModifier(k, v)); + MapDumper.Dump(nameof(CompareTypesForCast), CompareTypesForCast, (k, v) => dmpCompareTypesForCast(k, v)); + MapDumper.Dump(nameof(CompareTypesForEquality), CompareTypesForEquality, (k, v) => dmpCompareTypesForEquality(k, v)); + MapDumper.Dump(nameof(CompileMethod), CompileMethod, (k, v) => dmpCompileMethod(k, v)); + MapDumper.Dump(nameof(ConstructStringLiteral), ConstructStringLiteral, (k, v) => dmpConstructStringLiteral(k, v)); + MapDumper.Dump(nameof(ConvertPInvokeCalliToCall), ConvertPInvokeCalliToCall, (k, v) => dmpConvertPInvokeCalliToCall(k, v)); + MapDumper.Dump(nameof(EmbedClassHandle), EmbedClassHandle, (k, v) => dmpEmbedClassHandle(k, v)); + MapDumper.Dump(nameof(EmbedFieldHandle), EmbedFieldHandle, (k, v) => dmpEmbedFieldHandle(k, v)); + MapDumper.Dump(nameof(EmbedGenericHandle), EmbedGenericHandle, (k, v) => dmpEmbedGenericHandle(k, v)); + MapDumper.Dump(nameof(EmbedMethodHandle), EmbedMethodHandle, (k, v) => dmpEmbedMethodHandle(k, v)); + MapDumper.Dump(nameof(EmbedModuleHandle), EmbedModuleHandle, (k, v) => dmpEmbedModuleHandle(k, v)); + MapDumper.Dump(nameof(GetThreadLocalFieldInfo), GetThreadLocalFieldInfo, (k, v) => dmpGetThreadLocalFieldInfo(k, v)); + MapDumper.Dump(nameof(GetThreadLocalStaticBlocksInfo), GetThreadLocalStaticBlocksInfo, (k, v) => dmpGetThreadLocalStaticBlocksInfo(k, v)); + MapDumper.Dump(nameof(GetThreadLocalStaticInfo_NativeAOT), GetThreadLocalStaticInfo_NativeAOT, (k, v) => dmpGetThreadLocalStaticInfo_NativeAOT(k, v)); + MapDumper.Dump(nameof(EmptyStringLiteral), EmptyStringLiteral, (k, v) => dmpEmptyStringLiteral(k, v)); + MapDumper.Dump(nameof(ErrorList), ErrorList, (k, v) => dmpErrorList(k, v)); + MapDumper.Dump(nameof(FindCallSiteSig), FindCallSiteSig, (k, v) => dmpFindCallSiteSig(k, v)); + MapDumper.Dump(nameof(FindSig), FindSig, (k, v) => dmpFindSig(k, v)); + MapDumper.Dump(nameof(GetAddressOfPInvokeTarget), GetAddressOfPInvokeTarget, (k, v) => dmpGetAddressOfPInvokeTarget(k, v)); + MapDumper.Dump(nameof(GetAddrOfCaptureThreadGlobal), GetAddrOfCaptureThreadGlobal, (k, v) => dmpGetAddrOfCaptureThreadGlobal(k, v)); + MapDumper.Dump(nameof(GetArgClass), GetArgClass, (k, v) => dmpGetArgClass(k, v)); + MapDumper.Dump(nameof(GetArgNext), GetArgNext, (k, v) => dmpGetArgNext(k, v)); + MapDumper.Dump(nameof(GetArgType), GetArgType, (k, v) => dmpGetArgType(k, v)); + MapDumper.Dump(nameof(GetExactClasses), GetExactClasses, (k, v) => dmpGetExactClasses(k, v)); + MapDumper.Dump(nameof(GetArrayInitializationData), GetArrayInitializationData, (k, v) => dmpGetArrayInitializationData(k, v)); + MapDumper.Dump(nameof(GetArrayRank), GetArrayRank, (k, v) => dmpGetArrayRank(k, v)); + MapDumper.Dump(nameof(GetArrayIntrinsicID), GetArrayIntrinsicID, (k, v) => dmpGetArrayIntrinsicID(k, v)); + MapDumper.Dump(nameof(GetBoundaries), GetBoundaries, (k, v) => dmpGetBoundaries(k, v)); + MapDumper.Dump(nameof(GetBoxHelper), GetBoxHelper, (k, v) => dmpGetBoxHelper(k, v)); + MapDumper.Dump(nameof(GetBuiltinClass), GetBuiltinClass, (k, v) => dmpGetBuiltinClass(k, v)); + MapDumper.Dump(nameof(GetCallInfo), GetCallInfo, (k, v) => dmpGetCallInfo(k, v)); + MapDumper.Dump(nameof(GetCastingHelper), GetCastingHelper, (k, v) => dmpGetCastingHelper(k, v)); + MapDumper.Dump(nameof(GetChildType), GetChildType, (k, v) => dmpGetChildType(k, v)); + MapDumper.Dump(nameof(GetClassAlignmentRequirement), GetClassAlignmentRequirement, (k, v) => dmpGetClassAlignmentRequirement(k, v)); + MapDumper.Dump(nameof(GetClassAttribs), GetClassAttribs, (k, v) => dmpGetClassAttribs(k, v)); + MapDumper.Dump(nameof(GetClassStaticDynamicInfo), GetClassStaticDynamicInfo, (k, v) => dmpGetClassStaticDynamicInfo(k, v)); + MapDumper.Dump(nameof(GetClassThreadStaticDynamicInfo), GetClassThreadStaticDynamicInfo, (k, v) => dmpGetClassThreadStaticDynamicInfo(k, v)); + MapDumper.Dump(nameof(GetClassGClayout), GetClassGClayout, (k, v) => dmpGetClassGClayout(k, v)); + MapDumper.Dump(nameof(GetClassModuleIdForStatics), GetClassModuleIdForStatics, (k, v) => dmpGetClassModuleIdForStatics(k, v)); + MapDumper.Dump(nameof(GetIsClassInitedFlagAddress), GetIsClassInitedFlagAddress, (k, v) => dmpGetIsClassInitedFlagAddress(k, v)); + MapDumper.Dump(nameof(GetStaticBaseAddress), GetStaticBaseAddress, (k, v) => dmpGetStaticBaseAddress(k, v)); + MapDumper.Dump(nameof(GetClassNameFromMetadata), GetClassNameFromMetadata, (k, v) => dmpGetClassNameFromMetadata(k, v)); + MapDumper.Dump(nameof(GetTypeInstantiationArgument), GetTypeInstantiationArgument, (k, v) => dmpGetTypeInstantiationArgument(k, v)); + MapDumper.Dump(nameof(GetMethodInstantiationArgument), GetMethodInstantiationArgument, (k, v) => dmpGetMethodInstantiationArgument(k, v)); + MapDumper.Dump(nameof(GetClassNumInstanceFields), GetClassNumInstanceFields, (k, v) => dmpGetClassNumInstanceFields(k, v)); + MapDumper.Dump(nameof(GetClassSize), GetClassSize, (k, v) => dmpGetClassSize(k, v)); + MapDumper.Dump(nameof(GetHeapClassSize), GetHeapClassSize, (k, v) => dmpGetHeapClassSize(k, v)); + MapDumper.Dump(nameof(CanAllocateOnStack), CanAllocateOnStack, (k, v) => dmpCanAllocateOnStack(k, v)); + MapDumper.Dump(nameof(GetCookieForInterpreterCalliSig), GetCookieForInterpreterCalliSig, (k, v) => dmpGetCookieForInterpreterCalliSig(k, v)); + MapDumper.Dump(nameof(GetDefaultComparerClass), GetDefaultComparerClass, (k, v) => dmpGetDefaultComparerClass(k, v)); + MapDumper.Dump(nameof(GetDefaultEqualityComparerClass), GetDefaultEqualityComparerClass, (k, v) => dmpGetDefaultEqualityComparerClass(k, v)); + MapDumper.Dump(nameof(GetSZArrayHelperEnumeratorClass), GetSZArrayHelperEnumeratorClass, (k, v) => dmpGetSZArrayHelperEnumeratorClass(k, v)); + MapDumper.Dump(nameof(GetDelegateCtor), GetDelegateCtor, (k, v) => dmpGetDelegateCtor(k, v)); + MapDumper.Dump(nameof(GetEEInfo), GetEEInfo, (k, v) => dmpGetEEInfo(k, v)); + MapDumper.Dump(nameof(GetAsyncInfo), GetAsyncInfo, (k, v) => dmpGetAsyncInfo(k, v)); + MapDumper.Dump(nameof(GetAwaitReturnCall), GetAwaitReturnCall, (k, v) => dmpGetAwaitReturnCall(k, v)); + MapDumper.Dump(nameof(GetAwaitAwaiterInContinuationCall), GetAwaitAwaiterInContinuationCall, (k, v) => dmpGetAwaitAwaiterInContinuationCall(k, v)); + MapDumper.Dump(nameof(GetEHinfo), GetEHinfo, (k, v) => dmpGetEHinfo(k, v)); + MapDumper.Dump(nameof(GetStaticFieldContent), GetStaticFieldContent, (k, v) => dmpGetStaticFieldContent(k, v)); + MapDumper.Dump(nameof(GetObjectContent), GetObjectContent, (k, v) => dmpGetObjectContent(k, v)); + MapDumper.Dump(nameof(GetStaticFieldCurrentClass), GetStaticFieldCurrentClass, (k, v) => dmpGetStaticFieldCurrentClass(k, v)); + MapDumper.Dump(nameof(GetFieldClass), GetFieldClass, (k, v) => dmpGetFieldClass(k, v)); + MapDumper.Dump(nameof(GetFieldInClass), GetFieldInClass, (k, v) => dmpGetFieldInClass(k, v)); + MapDumper.Dump(nameof(GetTypeLayout), GetTypeLayout, (k, v) => dmpGetTypeLayout(k, v)); + MapDumper.Dump(nameof(GetFieldInfo), GetFieldInfo, (k, v) => dmpGetFieldInfo(k, v)); + MapDumper.Dump(nameof(GetFieldOffset), GetFieldOffset, (k, v) => dmpGetFieldOffset(k, v)); + MapDumper.Dump(nameof(GetFieldThreadLocalStoreID), GetFieldThreadLocalStoreID, (k, v) => dmpGetFieldThreadLocalStoreID(k, v)); + MapDumper.Dump(nameof(GetFieldType), GetFieldType, (k, v) => dmpGetFieldType(k, v)); + MapDumper.Dump(nameof(GetFunctionEntryPoint), GetFunctionEntryPoint, (k, v) => dmpGetFunctionEntryPoint(k, v)); + MapDumper.Dump(nameof(GetFunctionFixedEntryPoint), GetFunctionFixedEntryPoint, (k, v) => dmpGetFunctionFixedEntryPoint(k, v)); + MapDumper.Dump(nameof(GetGSCookie), GetGSCookie, (k, v) => dmpGetGSCookie(k, v)); + MapDumper.Dump(nameof(GetHelperFtn), GetHelperFtn, (k, v) => dmpGetHelperFtn(k, v)); + MapDumper.Dump(nameof(GetHFAType), GetHFAType, (k, v) => dmpGetHFAType(k, v)); + MapDumper.Dump(nameof(GetIntConfigValue), GetIntConfigValue, (k, v) => dmpGetIntConfigValue(k, v)); + MapDumper.Dump(nameof(GetJitFlags), GetJitFlags, (k, v) => dmpGetJitFlags(k, v)); + MapDumper.Dump(nameof(GetJustMyCodeHandle), GetJustMyCodeHandle, (k, v) => dmpGetJustMyCodeHandle(k, v)); + MapDumper.Dump(nameof(GetLocationOfThisType), GetLocationOfThisType, (k, v) => dmpGetLocationOfThisType(k, v)); + MapDumper.Dump(nameof(IsIntrinsic), IsIntrinsic, (k, v) => dmpIsIntrinsic(k, v)); + MapDumper.Dump(nameof(NotifyMethodInfoUsage), NotifyMethodInfoUsage, (k, v) => dmpNotifyMethodInfoUsage(k, v)); + MapDumper.Dump(nameof(NotifyInstructionSetUsage), NotifyInstructionSetUsage, (k, v) => dmpNotifyInstructionSetUsage(k, v)); + MapDumper.Dump(nameof(GetMethodAttribs), GetMethodAttribs, (k, v) => dmpGetMethodAttribs(k, v)); + MapDumper.Dump(nameof(GetClassAssemblyName), GetClassAssemblyName, (k, v) => dmpGetClassAssemblyName(k, v)); + MapDumper.Dump(nameof(GetMethodClass), GetMethodClass, (k, v) => dmpGetMethodClass(k, v)); + MapDumper.Dump(nameof(GetMethodDefFromMethod), GetMethodDefFromMethod, (k, v) => dmpGetMethodDefFromMethod(k, v)); + MapDumper.Dump(nameof(GetMethodHash), GetMethodHash, (k, v) => dmpGetMethodHash(k, v)); + MapDumper.Dump(nameof(GetMethodInfo), GetMethodInfo, (k, v) => dmpGetMethodInfo(k, v)); + MapDumper.Dump(nameof(HaveSameMethodDefinition), HaveSameMethodDefinition, (k, v) => dmpHaveSameMethodDefinition(k, v)); + MapDumper.Dump(nameof(GetTypeDefinition), GetTypeDefinition, (k, v) => dmpGetTypeDefinition(k, v)); + MapDumper.Dump(nameof(GetMethodNameFromMetadata), GetMethodNameFromMetadata, (k, v) => dmpGetMethodNameFromMetadata(k, v)); + MapDumper.Dump(nameof(GetMethodSig), GetMethodSig, (k, v) => dmpGetMethodSig(k, v)); + MapDumper.Dump(nameof(GetMethodVTableOffset), GetMethodVTableOffset, (k, v) => dmpGetMethodVTableOffset(k, v)); + MapDumper.Dump(nameof(GetNewArrHelper), GetNewArrHelper, (k, v) => dmpGetNewArrHelper(k, v)); + MapDumper.Dump(nameof(GetNewHelper), GetNewHelper, (k, v) => dmpGetNewHelper(k, v)); + MapDumper.Dump(nameof(GetOSRInfo), GetOSRInfo, (k, v) => dmpGetOSRInfo(k, v)); + MapDumper.Dump(nameof(GetParentType), GetParentType, (k, v) => dmpGetParentType(k, v)); + MapDumper.Dump(nameof(GetProfilingHandle), GetProfilingHandle, (k, v) => dmpGetProfilingHandle(k, v)); + MapDumper.Dump(nameof(GetReadyToRunHelper), GetReadyToRunHelper, (k, v) => dmpGetReadyToRunHelper(k, v)); + MapDumper.Dump(nameof(GetReadyToRunDelegateCtorHelper), GetReadyToRunDelegateCtorHelper, (k, v) => dmpGetReadyToRunDelegateCtorHelper(k, v)); + MapDumper.Dump(nameof(GetRelocTypeHint), GetRelocTypeHint, (k, v) => dmpGetRelocTypeHint(k, v)); + MapDumper.Dump(nameof(GetExpectedTargetArchitecture), GetExpectedTargetArchitecture, (k, v) => dmpGetExpectedTargetArchitecture(k, v)); + MapDumper.Dump(nameof(GetSharedCCtorHelper), GetSharedCCtorHelper, (k, v) => dmpGetSharedCCtorHelper(k, v)); + MapDumper.Dump(nameof(GetStringConfigValue), GetStringConfigValue, (k, v) => dmpGetStringConfigValue(k, v)); + MapDumper.Dump(nameof(GetSystemVAmd64PassStructInRegisterDescriptor), GetSystemVAmd64PassStructInRegisterDescriptor, (k, v) => dmpGetSystemVAmd64PassStructInRegisterDescriptor(k, v)); + MapDumper.Dump(nameof(GetSwiftLowering), GetSwiftLowering, (k, v) => dmpGetSwiftLowering(k, v)); + MapDumper.Dump(nameof(GetFpStructLowering), GetFpStructLowering, (k, v) => dmpGetFpStructLowering(k, v)); + MapDumper.Dump(nameof(GetWasmLowering), GetWasmLowering, (k, v) => dmpGetWasmLowering(k, v)); + MapDumper.Dump(nameof(GetTailCallHelpers), GetTailCallHelpers, (k, v) => dmpGetTailCallHelpers(k, v)); + MapDumper.Dump(nameof(GetAsyncResumptionStub), GetAsyncResumptionStub, (k, v) => dmpGetAsyncResumptionStub(k, v)); + MapDumper.Dump(nameof(GetContinuationType), GetContinuationType, (k, v) => dmpGetContinuationType(k, v)); + MapDumper.Dump(nameof(UpdateEntryPointForTailCall), UpdateEntryPointForTailCall, (k, v) => dmpUpdateEntryPointForTailCall(k, v)); + MapDumper.Dump(nameof(GetSpecialCopyHelper), GetSpecialCopyHelper, (k, v) => dmpGetSpecialCopyHelper(k, v)); + MapDumper.Dump(nameof(GetThreadTLSIndex), GetThreadTLSIndex, (k, v) => dmpGetThreadTLSIndex(k, v)); + MapDumper.Dump(nameof(GetTokenTypeAsHandle), GetTokenTypeAsHandle, (k, v) => dmpGetTokenTypeAsHandle(k, v)); + MapDumper.Dump(nameof(GetTypeForBox), GetTypeForBox, (k, v) => dmpGetTypeForBox(k, v)); + MapDumper.Dump(nameof(GetTypeForPrimitiveValueClass), GetTypeForPrimitiveValueClass, (k, v) => dmpGetTypeForPrimitiveValueClass(k, v)); + MapDumper.Dump(nameof(GetTypeForPrimitiveNumericClass), GetTypeForPrimitiveNumericClass, (k, v) => dmpGetTypeForPrimitiveNumericClass(k, v)); + MapDumper.Dump(nameof(GetAsyncOtherVariant), GetAsyncOtherVariant, (k, v) => dmpGetAsyncOtherVariant(k, v)); + MapDumper.Dump(nameof(GetUnBoxHelper), GetUnBoxHelper, (k, v) => dmpGetUnBoxHelper(k, v)); + MapDumper.Dump(nameof(GetRuntimeTypePointer), GetRuntimeTypePointer, (k, v) => dmpGetRuntimeTypePointer(k, v)); + MapDumper.Dump(nameof(IsObjectImmutable), IsObjectImmutable, (k, v) => dmpIsObjectImmutable(k, v)); + MapDumper.Dump(nameof(GetStringChar), GetStringChar, (k, v) => dmpGetStringChar(k, v)); + MapDumper.Dump(nameof(GetObjectType), GetObjectType, (k, v) => dmpGetObjectType(k, v)); + MapDumper.Dump(nameof(GetVarArgsHandle), GetVarArgsHandle, (k, v) => dmpGetVarArgsHandle(k, v)); + MapDumper.Dump(nameof(GetVars), GetVars, (k, v) => dmpGetVars(k, v)); + MapDumper.Dump(nameof(InitClass), InitClass, (k, v) => dmpInitClass(k, v)); + MapDumper.Dump(nameof(IsDelegateCreationAllowed), IsDelegateCreationAllowed, (k, v) => dmpIsDelegateCreationAllowed(k, v)); + MapDumper.Dump(nameof(IsFieldStatic), IsFieldStatic, (k, v) => dmpIsFieldStatic(k, v)); + MapDumper.Dump(nameof(GetArrayOrStringLength), GetArrayOrStringLength, (k, v) => dmpGetArrayOrStringLength(k, v)); + MapDumper.Dump(nameof(ExpandRawHandleIntrinsic), ExpandRawHandleIntrinsic, (k, v) => dmpExpandRawHandleIntrinsic(k, v)); + MapDumper.Dump(nameof(IsIntrinsicType), IsIntrinsicType, (k, v) => dmpIsIntrinsicType(k, v)); + MapDumper.Dump(nameof(IsSDArray), IsSDArray, (k, v) => dmpIsSDArray(k, v)); + MapDumper.Dump(nameof(GetStringLiteral), GetStringLiteral, (k, v) => dmpGetStringLiteral(k, v)); + MapDumper.Dump(nameof(PrintObjectDescription), PrintObjectDescription, (k, v) => dmpPrintObjectDescription(k, v)); + MapDumper.Dump(nameof(PrintClassName), PrintClassName, (k, v) => dmpPrintClassName(k, v)); + MapDumper.Dump(nameof(PrintFieldName), PrintFieldName, (k, v) => dmpPrintFieldName(k, v)); + MapDumper.Dump(nameof(PrintMethodName), PrintMethodName, (k, v) => dmpPrintMethodName(k, v)); + MapDumper.Dump(nameof(IsValueClass), IsValueClass, (k, v) => dmpIsValueClass(k, v)); + MapDumper.Dump(nameof(IsMoreSpecificType), IsMoreSpecificType, (k, v) => dmpIsMoreSpecificType(k, v)); + MapDumper.Dump(nameof(IsExactType), IsExactType, (k, v) => dmpIsExactType(k, v)); + MapDumper.Dump(nameof(IsGenericType), IsGenericType, (k, v) => dmpIsGenericType(k, v)); + MapDumper.Dump(nameof(IsNullableType), IsNullableType, (k, v) => dmpIsNullableType(k, v)); + MapDumper.Dump(nameof(IsEnum), IsEnum, (k, v) => dmpIsEnum(k, v)); + MapDumper.Dump(nameof(PInvokeMarshalingRequired), PInvokeMarshalingRequired, (k, v) => dmpPInvokeMarshalingRequired(k, v)); + MapDumper.Dump(nameof(ResolveToken), ResolveToken, (k, v) => dmpResolveToken(k, v)); + MapDumper.Dump(nameof(ResolveVirtualMethod), ResolveVirtualMethod, (k, v) => dmpResolveVirtualMethod(k, v)); + MapDumper.Dump(nameof(SatisfiesMethodConstraints), SatisfiesMethodConstraints, (k, v) => dmpSatisfiesMethodConstraints(k, v)); + MapDumper.Dump(nameof(GetUnmanagedCallConv), GetUnmanagedCallConv, (k, v) => dmpGetUnmanagedCallConv(k, v)); + MapDumper.Dump(nameof(DoesFieldBelongToClass), DoesFieldBelongToClass, (k, v) => dmpDoesFieldBelongToClass(k, v)); + MapDumper.Dump(nameof(SigInstHandleMap), SigInstHandleMap, (k, v) => dmpSigInstHandleMap(k, v)); + MapDumper.Dump(nameof(GetWasmTypeSymbol), GetWasmTypeSymbol, (k, v) => dmpGetWasmTypeSymbol(k, v)); + MapDumper.Dump(nameof(GetAddressAlignment), GetAddressAlignment, (k, v) => dmpGetAddressAlignment(k, v)); + MapDumper.Dump(nameof(CanValueClassInstancePointerEscape), CanValueClassInstancePointerEscape, (k, v) => dmpCanValueClassInstancePointerEscape(k, v)); + MapDumper.Dump(nameof(GetWasmWellKnownGlobals), GetWasmWellKnownGlobals, (k, v) => dmpGetWasmWellKnownGlobals(k, v)); + MapDumper.Dump(nameof(IsByRefLike), IsByRefLike, (k, v) => dmpIsByRefLike(k, v)); + MapDumper.Dump(nameof(IsSharedInst), IsSharedInst, (k, v) => dmpIsSharedInst(k, v)); + } +} diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Record.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Record.cs new file mode 100644 index 00000000000000..1762d8012e789b --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Record.cs @@ -0,0 +1,2441 @@ +// 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.InteropServices; +using Internal.JitInterface; +using Internal.Pgo; + +using static SuperPmi.SpmiRecordsHelper; + +namespace SuperPmi; + +// The recording side of the JIT-EE interface: stores the EE's answers to the JIT's queries, keyed the way +// the replay side looks them up. +public sealed unsafe partial class MethodContext +{ + private static nuint strlen(byte* s) => (nuint)System.Runtime.InteropServices.MemoryMarshal.CreateReadOnlySpanFromNullTerminated(s).Length; + + private static ulong CastPointer(void* p) => (ulong)p; + + private static ulong CastPointer(nuint p) => p; + + // The signature instantiation handles are stored in their own map, created on first use. + private Agnostic_CORINFO_SIG_INFO StoreSig(in CORINFO_SIG_INFO sig, LightWeightMapBuffer buffers) + { + DenseLightWeightMap handleMap = SigInstHandleMap; + Agnostic_CORINFO_SIG_INFO result = StoreAgnostic_CORINFO_SIG_INFO(sig, buffers, ref handleMap); + SigInstHandleMap = handleMap; + return result; + } + + private void StoreSigInstHandles(uint count, CORINFO_CLASS_STRUCT_** handles, out uint countOut, out uint indexOut) + { + DenseLightWeightMap handleMap = SigInstHandleMap; + StoreAgnostic_CORINFO_SIG_INST_HandleArray(count, handles, ref handleMap, out countOut, out indexOut); + SigInstHandleMap = handleMap; + } + + public void recGlobalContext(MethodContext other) + { + ErrorHandling.AssertMsg(GetIntConfigValue == null, "GetIntConfigValue == null", ""); + ErrorHandling.AssertMsg(GetStringConfigValue == null, "GetStringConfigValue == null", ""); + + if (other.GetIntConfigValue != null) + { + GetIntConfigValue = other.GetIntConfigValue.Clone(); + } + + if (other.GetStringConfigValue != null) + { + GetStringConfigValue = other.GetStringConfigValue.Clone(); + } + } + + public void recCompileMethod(CORINFO_METHOD_INFO* info, uint flags, CORINFO_OS os) + { + CompileMethod ??= new(); + + Agnostic_CompileMethod value = default; + + value.info.ftn = CastHandle(info->ftn); + value.info.scope = CastHandle(info->scope); + value.info.ILCode_offset = (uint)CompileMethod.AddBuffer(Bytes(info->ILCode, info->ILCodeSize)); + value.info.ILCodeSize = (uint)info->ILCodeSize; + value.info.maxStack = (uint)info->maxStack; + value.info.EHcount = (uint)info->EHcount; + value.info.options = (uint)info->options; + value.info.regionKind = (uint)info->regionKind; + + value.info.args = StoreSig(info->args, CompileMethod); + value.info.locals = StoreSig(info->locals, CompileMethod); + + value.os = (uint)os; + + value.flags = (uint)flags; + + CompileMethod.Add(0, value); + } + + public void recGetMethodClass(CORINFO_METHOD_STRUCT_* methodHandle, CORINFO_CLASS_STRUCT_* classHandle) + { + GetMethodClass ??= new(); + + ulong key = CastHandle(methodHandle); + ulong value = CastHandle(classHandle); + GetMethodClass.Add(key, value); + } + + public void recGetClassAttribs(CORINFO_CLASS_STRUCT_* classHandle, uint attribs) + { + GetClassAttribs ??= new(); + + ulong key = CastHandle(classHandle); + GetClassAttribs.Add(key, attribs); + } + + public void recIsIntrinsic(CORINFO_METHOD_STRUCT_* ftn, bool result) + { + IsIntrinsic ??= new(); + + ulong key = CastHandle(ftn); + uint value = result ? 1u : 0u; + IsIntrinsic.Add(key, value); + } + + public void recNotifyMethodInfoUsage(CORINFO_METHOD_STRUCT_* ftn, bool result) + { + NotifyMethodInfoUsage ??= new(); + + ulong key = CastHandle(ftn); + uint value = result ? 1u : 0u; + NotifyMethodInfoUsage.Add(key, value); + } + + public void recNotifyInstructionSetUsage(InstructionSet isa, bool supported, bool preserveNegativeDependency, bool result) + { + NotifyInstructionSetUsage ??= new(); + + DD key = default; + key.A = (uint)isa; + key.B = (supported ? 1u : 0u) | (preserveNegativeDependency ? 2u : 0u); + NotifyInstructionSetUsage.Add(key, result ? 1u : 0u); + } + + public void recGetMethodAttribs(CORINFO_METHOD_STRUCT_* methodHandle, uint attribs) + { + GetMethodAttribs ??= new(); + + ulong key = CastHandle(methodHandle); + GetMethodAttribs.Add(key, attribs); + } + + public void recGetClassAssemblyName(CORINFO_CLASS_STRUCT_* cls, byte* assemblyName) + { + GetClassAssemblyName ??= new(); + + uint value; + if (assemblyName != null) + { + value = GetClassAssemblyName.AddBuffer(Bytes(assemblyName, strlen(assemblyName) + 1)); + } + else + { + value = uint.MaxValue; + } + + ulong key = CastHandle(cls); + GetClassAssemblyName.Add(key, value); + } + + public void recGetVars(CORINFO_METHOD_STRUCT_* ftn, uint* cVars, ILVarInfo** vars_in, bool* extendOthers) + { + GetVars ??= new(); + + Agnostic_GetVars value = default; + value.cVars = (uint)*cVars; + value.vars_offset = + (uint)GetVars.AddBuffer(Bytes(*vars_in, (nuint)(sizeof(ILVarInfo) * (*cVars)))); + value.extendOthers = (*extendOthers ? 1u : 0u); + + ulong key = CastHandle(ftn); + GetVars.Add(key, value); + } + + public void recGetBoundaries(CORINFO_METHOD_STRUCT_* ftn, uint* cILOffsets, uint** pILOffsets, BoundaryTypes* implicitBoundaries) + { + GetBoundaries ??= new(); + + Agnostic_GetBoundaries value = default; + + value.cILOffsets = (uint)*cILOffsets; + value.pILOffset_offset = + (uint)GetBoundaries.AddBuffer(Bytes(*pILOffsets, sizeof(uint) * (*cILOffsets))); + value.implicitBoundaries = (uint)*implicitBoundaries; + + ulong key = CastHandle(ftn); + GetBoundaries.Add(key, value); + } + + public void recInitClass(CORINFO_FIELD_STRUCT_* field, CORINFO_METHOD_STRUCT_* method, CORINFO_CONTEXT_STRUCT* context, CorInfoInitClassResult result) + { + InitClass ??= new(); + + Agnostic_InitClass key = default; + key.field = CastHandle(field); + key.method = CastHandle(method); + key.context = CastHandle(context); + + uint value = (uint)result; + InitClass.Add(key, value); + } + + public void recGetMethodNameFromMetadata(CORINFO_METHOD_STRUCT_* ftn, byte* methodName, byte** className, byte** namespaceName, byte** enclosingClassNames, nuint maxEnclosingClassNames) + { + GetMethodNameFromMetadata ??= new(); + Agnostic_CORINFO_METHODNAME_TOKENout value = default; + Agnostic_CORINFO_METHODNAME_TOKENin key = default; + key.ftn = CastHandle(ftn); + key.className = (className != null) ? 1u : 0u; + key.namespaceName = (namespaceName != null) ? 1u : 0u; + key.maxEnclosingClassNames = (uint)maxEnclosingClassNames; + + if (methodName != null) + value.methodName = GetMethodNameFromMetadata.AddBuffer(Bytes(methodName, strlen(methodName) + 1)); + else + value.methodName = uint.MaxValue; + + if ((className != null) && (*className != null)) + value.className = GetMethodNameFromMetadata.AddBuffer(Bytes(*className, strlen(*className) + 1)); + else + value.className = uint.MaxValue; + + if ((namespaceName != null) && (*namespaceName != null)) + value.namespaceName = + GetMethodNameFromMetadata.AddBuffer(Bytes(*namespaceName, strlen(*namespaceName) + 1)); + else + value.namespaceName = uint.MaxValue; + + uint* enclosingClassNameIndices = stackalloc uint[(int)maxEnclosingClassNames]; + for (nuint i = 0; i < maxEnclosingClassNames; i++) + { + byte* enclosingClassName = enclosingClassNames[i]; + if (enclosingClassName != null) + enclosingClassNameIndices[i] = GetMethodNameFromMetadata.AddBuffer(Bytes(enclosingClassName, strlen(enclosingClassName) + 1)); + else + enclosingClassNameIndices[i] = uint.MaxValue; + } + + if (maxEnclosingClassNames > 0) + value.enclosingClassNames = GetMethodNameFromMetadata.AddBuffer(Bytes(enclosingClassNameIndices, sizeof(uint) * (uint)maxEnclosingClassNames)); + else + value.enclosingClassNames = uint.MaxValue; + + GetMethodNameFromMetadata.Add(key, value); + } + + public void recGetJitFlags(CORJIT_FLAGS* jitFlags, uint sizeInBytes, uint result) + { + GetJitFlags ??= new(); + + DD value = default; + value.A = (uint)GetJitFlags.AddBuffer(Bytes(jitFlags, sizeInBytes)); + value.B = result; + + // NOTE: getJitFlags() is expected to be idempotent per method, so the mapping key is always + // zero. + GetJitFlags.Add(0, value); + } + + public void recCanInline(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* calleeHnd, CorInfoInline response, uint exceptionCode) + { + CanInline ??= new(); + + DLDL key = default; + key.A = CastHandle(callerHnd); + key.B = CastHandle(calleeHnd); + + Agnostic_CanInline value = default; + value.result = (uint)response; + value.exceptionCode = (uint)exceptionCode; + + CanInline.Add(key, value); + } + + public void recResolveToken(CORINFO_RESOLVED_TOKEN* pResolvedToken, uint exceptionCode) + { + ResolveToken ??= new(); + + Agnostic_CORINFO_RESOLVED_TOKENin key = default; + key = CreateAgnostic_CORINFO_RESOLVED_TOKENin(pResolvedToken); + + ResolveTokenValue value = default; + if (exceptionCode != 0) + { + // The output token memory might be corrupt or uninitialized, so just zero it out. + // (Set indexes to -1, indicating no buffer). + value.tokenOut = default; + value.tokenOut.pTypeSpec_Index = uint.MaxValue; + value.tokenOut.pMethodSpec_Index = uint.MaxValue; + } + else + { + value.tokenOut = StoreAgnostic_CORINFO_RESOLVED_TOKENout(pResolvedToken, ResolveToken); + } + value.exceptionCode = exceptionCode; + + ResolveToken.Add(key, value); + } + + public void recGetCallInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_CALLINFO_FLAGS flags, CORINFO_CALL_INFO* pResult, uint exceptionCode) + { + GetCallInfo ??= new(); + + Agnostic_GetCallInfo key = default; + key.ResolvedToken = StoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, GetCallInfo); + + if (pConstrainedResolvedToken != null) + { + key.ConstrainedResolvedToken = + StoreAgnostic_CORINFO_RESOLVED_TOKEN(pConstrainedResolvedToken, GetCallInfo); + } + + key.callerHandle = CastHandle(callerHandle); + key.flags = (uint)flags; + + Agnostic_CORINFO_CALL_INFO value = default; + + if (exceptionCode == 0) + { + value.hMethod = CastHandle(pResult->hMethod); + value.methodFlags = (uint)pResult->methodFlags; + value.classFlags = (uint)pResult->classFlags; + value.sig = StoreSig(pResult->sig, GetCallInfo); + + value.accessAllowed = (uint)pResult->accessAllowed; + value.callsiteCalloutHelper = StoreAgnostic_CORINFO_HELPER_DESC(pResult->callsiteCalloutHelper); + value.thisTransform = (uint)pResult->thisTransform; + + value.kind = (uint)pResult->kind; + value.nullInstanceCheck = (pResult->nullInstanceCheck ? 1u : 0u); + value.contextHandle = CastHandle(pResult->contextHandle); + value.exactContextNeedsRuntimeLookup = (pResult->exactContextNeedsRuntimeLookup ? 1u : 0u); + + value.stubLookup = StoreAgnostic_CORINFO_LOOKUP(&pResult->codePointerOrStubLookup); + + value.instParamLookup.accessType = (uint)pResult->instParamLookup.accessType; + value.instParamLookup.handle = CastHandle(pResult->instParamLookup.handle); + } + + value.exceptionCode = (uint)exceptionCode; + + GetCallInfo.Add(key, value); + } + + public void recExpandRawHandleIntrinsic(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_GENERICHANDLE_RESULT* pResult) + { + ExpandRawHandleIntrinsic ??= new(); + + Agnostic_ExpandRawHandleIntrinsic key = default; + key.ResolvedToken = CreateAgnostic_CORINFO_RESOLVED_TOKENin(pResolvedToken); + key.hCallerHandle = CastHandle(callerHandle); + + Agnostic_CORINFO_GENERICHANDLE_RESULT value = default; + value.lookup = StoreAgnostic_CORINFO_LOOKUP(&pResult->lookup); + value.compileTimeHandle = CastHandle(pResult->compileTimeHandle); + value.handleType = (uint)pResult->handleType; + + ExpandRawHandleIntrinsic.Add(key, value); + } + + public void recIsIntrinsicType(CORINFO_CLASS_STRUCT_* cls, bool result) + { + IsIntrinsicType ??= new(); + + ulong key = CastHandle(cls); + uint value = result ? 1u : 0u; + IsIntrinsicType.Add(key, value); + } + + public void recAsCorInfoType(CORINFO_CLASS_STRUCT_* cls, CorInfoType result) + { + AsCorInfoType ??= new(); + + ulong key = CastHandle(cls); + uint value = (uint)result; + AsCorInfoType.Add(key, value); + } + + public void recIsValueClass(CORINFO_CLASS_STRUCT_* cls, bool result) + { + IsValueClass ??= new(); + + ulong key = CastHandle(cls); + uint value = result ? 1u : 0u; + IsValueClass.Add(key, value); + } + + public void recIsByRefLike(CORINFO_CLASS_STRUCT_* cls, bool result) + { + IsByRefLike ??= new(); + + ulong key = CastHandle(cls); + uint value = result ? 1u : 0u; + IsByRefLike.Add(key, value); + } + + public void recIsSharedInst(CORINFO_CLASS_STRUCT_* cls, bool result) + { + IsSharedInst ??= new(); + + ulong key = CastHandle(cls); + uint value = result ? 1u : 0u; + IsSharedInst.Add(key, value); + } + + public void recGetClassSize(CORINFO_CLASS_STRUCT_* cls, uint result) + { + GetClassSize ??= new(); + + ulong key = CastHandle(cls); + uint value = (uint)result; + GetClassSize.Add(key, value); + } + + public void recGetHeapClassSize(CORINFO_CLASS_STRUCT_* cls, uint result) + { + GetHeapClassSize ??= new(); + + ulong key = CastHandle(cls); + uint value = (uint)result; + GetHeapClassSize.Add(key, value); + } + + public void recCanAllocateOnStack(CORINFO_CLASS_STRUCT_* cls, bool result) + { + CanAllocateOnStack ??= new(); + + ulong key = CastHandle(cls); + uint value = result ? 1u : 0u; + CanAllocateOnStack.Add(key, value); + } + + public void recGetClassNumInstanceFields(CORINFO_CLASS_STRUCT_* cls, uint result) + { + GetClassNumInstanceFields ??= new(); + + ulong key = CastHandle(cls); + uint value = (uint)result; + GetClassNumInstanceFields.Add(key, value); + } + + public void recGetNewArrHelper(CORINFO_CLASS_STRUCT_* arrayCls, CorInfoHelpFunc result) + { + GetNewArrHelper ??= new(); + + ulong key = CastHandle(arrayCls); + uint value = (uint)result; + GetNewArrHelper.Add(key, value); + } + + public void recGetSharedCCtorHelper(CORINFO_CLASS_STRUCT_* clsHnd, CorInfoHelpFunc result) + { + GetSharedCCtorHelper ??= new(); + + ulong key = CastHandle(clsHnd); + uint value = (uint)result; + GetSharedCCtorHelper.Add(key, value); + } + + public void recGetTypeForBox(CORINFO_CLASS_STRUCT_* cls, CORINFO_CLASS_STRUCT_* result) + { + GetTypeForBox ??= new(); + + ulong key = CastHandle(cls); + ulong value = CastHandle(result); + GetTypeForBox.Add(key, value); + } + + public void recGetBoxHelper(CORINFO_CLASS_STRUCT_* cls, CorInfoHelpFunc result) + { + GetBoxHelper ??= new(); + + ulong key = CastHandle(cls); + uint value = (uint)result; + GetBoxHelper.Add(key, value); + } + + public void recGetBuiltinClass(CorInfoClassId classId, CORINFO_CLASS_STRUCT_* result) + { + GetBuiltinClass ??= new(); + + uint key = (uint)classId; + ulong value = CastHandle(result); + GetBuiltinClass.Add(key, value); + } + + public void recGetTypeForPrimitiveValueClass(CORINFO_CLASS_STRUCT_* cls, CorInfoType result) + { + GetTypeForPrimitiveValueClass ??= new(); + + ulong key = CastHandle(cls); + uint value = (uint)result; + GetTypeForPrimitiveValueClass.Add(key, value); + } + + public void recGetTypeForPrimitiveNumericClass(CORINFO_CLASS_STRUCT_* cls, CorInfoType result) + { + GetTypeForPrimitiveNumericClass ??= new(); + + ulong key = CastHandle(cls); + uint value = (uint)result; + GetTypeForPrimitiveNumericClass.Add(key, value); + } + + public void recGetParentType(CORINFO_CLASS_STRUCT_* cls, CORINFO_CLASS_STRUCT_* result) + { + GetParentType ??= new(); + + ulong key = CastHandle(cls); + ulong value = CastHandle(result); + GetParentType.Add(key, value); + } + + public void recIsSDArray(CORINFO_CLASS_STRUCT_* cls, bool result) + { + IsSDArray ??= new(); + + ulong key = CastHandle(cls); + uint value = result ? 1u : 0u; + IsSDArray.Add(key, value); + } + + public void recGetFieldClass(CORINFO_FIELD_STRUCT_* field, CORINFO_CLASS_STRUCT_* result) + { + GetFieldClass ??= new(); + + ulong key = CastHandle(field); + ulong value = CastHandle(result); + GetFieldClass.Add(key, value); + } + + public void recGetFieldOffset(CORINFO_FIELD_STRUCT_* field, uint result) + { + GetFieldOffset ??= new(); + + ulong key = CastHandle(field); + uint value = (uint)result; + GetFieldOffset.Add(key, value); + } + + public void recGetUnBoxHelper(CORINFO_CLASS_STRUCT_* cls, CorInfoHelpFunc result) + { + GetUnBoxHelper ??= new(); + + ulong key = CastHandle(cls); + uint value = (uint)result; + GetUnBoxHelper.Add(key, value); + } + + public void recGetRuntimeTypePointer(CORINFO_CLASS_STRUCT_* cls, CORINFO_OBJECT_STRUCT_* result) + { + GetRuntimeTypePointer ??= new(); + + ulong key = CastHandle(cls); + ulong value = CastHandle(result); + GetRuntimeTypePointer.Add(key, value); + } + + public void recIsObjectImmutable(CORINFO_OBJECT_STRUCT_* objPtr, bool result) + { + IsObjectImmutable ??= new(); + + ulong key = CastHandle(objPtr); + uint value = (result ? 1u : 0u); + IsObjectImmutable.Add(key, value); + } + + public void recGetStringChar(CORINFO_OBJECT_STRUCT_* strObj, int index, ushort* charValue, bool result) + { + GetStringChar ??= new(); + + DLD key = default; + key.A = CastHandle(strObj); + key.B = (uint)index; + + DD value = default; + value.A = (result ? 1u : 0u); + value.B = (uint)*charValue; + + GetStringChar.Add(key, value); + } + + public void recGetObjectType(CORINFO_OBJECT_STRUCT_* objPtr, CORINFO_CLASS_STRUCT_* result) + { + GetObjectType ??= new(); + + ulong key = CastHandle(objPtr); + ulong value = CastHandle(result); + GetObjectType.Add(key, value); + } + + public void recGetReadyToRunHelper(CORINFO_RESOLVED_TOKEN* pResolvedToken, CorInfoHelpFunc id, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_CONST_LOOKUP* pLookup, bool result) + { + GetReadyToRunHelper ??= new(); + + GetReadyToRunHelper_TOKENin key = default; + key.ResolvedToken = StoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, GetReadyToRunHelper); + key.id = (uint)id; + key.callerHandle = CastHandle(callerHandle); + GetReadyToRunHelper_TOKENout value = default; + value.Lookup = StoreAgnostic_CORINFO_CONST_LOOKUP(pLookup); + value.result = result ? (byte)1 : (byte)0; + + GetReadyToRunHelper.Add(key, value); + } + + public void recGetReadyToRunDelegateCtorHelper(CORINFO_RESOLVED_TOKEN* pTargetMethod, uint targetConstraint, CORINFO_CLASS_STRUCT_* delegateType, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_LOOKUP* pLookup) + { + GetReadyToRunDelegateCtorHelper ??= new(); + + GetReadyToRunDelegateCtorHelper_TOKENIn key = default; + key.TargetMethod = + StoreAgnostic_CORINFO_RESOLVED_TOKEN(pTargetMethod, GetReadyToRunDelegateCtorHelper); + key.targetConstraint = targetConstraint; + key.delegateType = CastHandle(delegateType); + key.callerHandle = CastHandle(callerHandle); + Agnostic_CORINFO_LOOKUP value = StoreAgnostic_CORINFO_LOOKUP(pLookup); + GetReadyToRunDelegateCtorHelper.Add(key, value); + } + + public void recGetHelperFtn(CorInfoHelpFunc ftnNum, CORINFO_CONST_LOOKUP pNativeEntrypoint, CORINFO_METHOD_STRUCT_* methodHandle) + { + GetHelperFtn ??= new(); + + uint key = (uint)ftnNum; + + Agnostic_GetHelperFtn value = default; + value.helperLookup = StoreAgnostic_CORINFO_CONST_LOOKUP(&pNativeEntrypoint); + value.helperMethod = CastHandle(methodHandle); + + GetHelperFtn.Add(key, value); + } + + public void recGetJustMyCodeHandle(CORINFO_METHOD_STRUCT_* method, CORINFO_JUST_MY_CODE_HANDLE_** ppIndirection, CORINFO_JUST_MY_CODE_HANDLE_* result) + { + GetJustMyCodeHandle ??= new(); + + DLDL value = default; + value.A = CastPointer(*ppIndirection); + value.B = CastHandle(result); + + ulong key = CastHandle(method); + GetJustMyCodeHandle.Add(key, value); + } + + public void recGetFunctionEntryPoint(CORINFO_METHOD_STRUCT_* ftn, CORINFO_CONST_LOOKUP* pResult, CORINFO_ACCESS_FLAGS accessFlags) + { + GetFunctionEntryPoint ??= new(); + + DLD key = default; + key.A = CastHandle(ftn); + key.B = (uint)accessFlags; + + DLD value = default; + value.A = CastPointer(pResult->addr); // First union member + value.B = (uint)pResult->accessType; + + GetFunctionEntryPoint.Add(key, value); + } + + public void recConstructStringLiteral(CORINFO_MODULE_STRUCT_* moduleHandle, uint metaTok, void* pValue, InfoAccessType result) + { + ConstructStringLiteral ??= new(); + + DLD key = default; + key.A = CastHandle(moduleHandle); + key.B = (uint)metaTok; + + DLD value = default; + value.A = CastPointer(pValue); + value.B = (uint)result; + + ConstructStringLiteral.Add(key, value); + } + + public void recConvertPInvokeCalliToCall(CORINFO_RESOLVED_TOKEN* pResolvedToken, bool fMustConvert, bool result) + { + ConvertPInvokeCalliToCall ??= new(); + + DLD key = default; + key.A = CastHandle(pResolvedToken->tokenScope); + key.B = (uint)pResolvedToken->token; + + DLDL value = default; + value.A = result ? CastHandle(pResolvedToken->hClass) : 0; + value.B = result ? CastHandle(pResolvedToken->hMethod) : 0; + + ConvertPInvokeCalliToCall.Add(key, value); + } + + public void recEmptyStringLiteral(void** pValue, InfoAccessType result) + { + EmptyStringLiteral ??= new(); + DLD temp2 = default; + temp2.A = CastPointer(*pValue); + temp2.B = (uint)result; + + EmptyStringLiteral.Append(temp2); + } + + public void recGetArgType(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_STRUCT_* args, CORINFO_CLASS_STRUCT_** vcTypeRet, CorInfoTypeWithMod result, uint exceptionCode) + { + GetArgType ??= new(); + + Agnostic_GetArgType_Key key = default; + + // Only setting values for CORINFO_SIG_INFO things the EE seems to pay attention to... this is necessary since some of the values + // are unset and fail our precise comparisons ... + // TODO: verify that the above comment is still true (that some of the fields of incoming argument `sig` contain garbage), or + // can we store the whole thing and use StoreAgnostic_CORINFO_SIG_INFO()? + + key.flags = (uint)sig->flags; + key.numArgs = (uint)sig->numArgs; + + StoreSigInstHandles(sig->sigInst.classInstCount, sig->sigInst.classInst, out key.sigInst_classInstCount, out key.sigInst_classInst_Index); + StoreSigInstHandles(sig->sigInst.methInstCount, sig->sigInst.methInst, out key.sigInst_methInstCount, out key.sigInst_methInst_Index); + + key.methodSignature = CastPointer(sig->methodSignature); + key.scope = CastHandle(sig->scope); + key.args = CastHandle(args); + + Agnostic_GetArgType_Value value = default; + value.vcTypeRet = CastHandle(*vcTypeRet); + value.result = (uint)result; + value.exceptionCode = (uint)exceptionCode; + + GetArgType.Add(key, value); + } + + public void recGetExactClasses(CORINFO_CLASS_STRUCT_* baseType, int maxExactClasses, CORINFO_CLASS_STRUCT_** exactClsRet, int result) + { + GetExactClasses ??= new(); + + DLD key = default; + key.A = CastHandle(baseType); + key.B = (uint)maxExactClasses; + + int numResults = result < 0 ? 0 : result; + + var exactClassesAgnostic = new ulong[numResults]; + for (int i = 0; i < numResults; i++) + exactClassesAgnostic[i] = CastHandle(exactClsRet[i]); + + Agnostic_GetExactClassesResult value = default; + value.numClasses = result; + value.classes = GetExactClasses.AddBuffer(MemoryMarshal.AsBytes(exactClassesAgnostic.AsSpan())); + + GetExactClasses.Add(key, value); + } + + public void recGetArgNext(CORINFO_ARG_LIST_STRUCT_* args, CORINFO_ARG_LIST_STRUCT_* result) + { + GetArgNext ??= new(); + + ulong key = CastHandle(args); + ulong value = CastHandle(result); + GetArgNext.Add(key, value); + } + + public void recGetMethodSig(CORINFO_METHOD_STRUCT_* ftn, CORINFO_SIG_INFO* sig, CORINFO_CLASS_STRUCT_* memberParent) + { + GetMethodSig ??= new(); + + DLDL key = default; + key.A = CastHandle(ftn); + key.B = CastHandle(memberParent); + + Agnostic_CORINFO_SIG_INFO value = StoreSig(*sig, GetMethodSig); + + GetMethodSig.Add(key, value); + } + + public void recGetArgClass(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_STRUCT_* args, CORINFO_CLASS_STRUCT_* result, uint exceptionCode) + { + GetArgClass ??= new(); + + Agnostic_GetArgClass_Key key = default; + + // Only setting values for CORINFO_SIG_INFO things the EE seems to pay attention to... this is necessary since some of the values + // are unset and fail our precise comparisons... + + StoreSigInstHandles(sig->sigInst.classInstCount, sig->sigInst.classInst, out key.sigInst_classInstCount, out key.sigInst_classInst_Index); + StoreSigInstHandles(sig->sigInst.methInstCount, sig->sigInst.methInst, out key.sigInst_methInstCount, out key.sigInst_methInst_Index); + + key.methodSignature = CastPointer(sig->methodSignature); + key.scope = CastHandle(sig->scope); + key.args = CastHandle(args); + + Agnostic_GetArgClass_Value value = default; + value.result = CastHandle(result); + value.exceptionCode = exceptionCode; + + GetArgClass.Add(key, value); + } + + public void recGetHFAType(CORINFO_CLASS_STRUCT_* clsHnd, CorInfoHFAElemType result) + { + GetHFAType ??= new(); + + ulong key = CastHandle(clsHnd); + uint value = (uint)result; + GetHFAType.Add(key, value); + } + + public void recGetMethodInfo(CORINFO_METHOD_STRUCT_* ftn, CORINFO_METHOD_INFO* info, CORINFO_CONTEXT_STRUCT* context, bool result, uint exceptionCode) + { + GetMethodInfo ??= new(); + + Agnostic_GetMethodInfo value = default; + + if (result) + { + value.info.ftn = CastHandle(info->ftn); + value.info.scope = CastHandle(info->scope); + value.info.ILCode_offset = (uint)GetMethodInfo.AddBuffer(Bytes(info->ILCode, info->ILCodeSize)); + value.info.ILCodeSize = (uint)info->ILCodeSize; + value.info.maxStack = (uint)info->maxStack; + value.info.EHcount = (uint)info->EHcount; + value.info.options = (uint)info->options; + value.info.regionKind = (uint)info->regionKind; + + value.info.args = StoreSig(info->args, GetMethodInfo); + value.info.locals = StoreSig(info->locals, GetMethodInfo); + } + value.result = result ? (byte)1 : (byte)0; + value.exceptionCode = (uint)exceptionCode; + + DLDL key = default; + key.A = CastHandle(ftn); + key.B = CastHandle(context); + GetMethodInfo.Add(key, value); + } + + public void recHaveSameMethodDefinition(CORINFO_METHOD_STRUCT_* methHnd1, CORINFO_METHOD_STRUCT_* methHnd2, bool result) + { + HaveSameMethodDefinition ??= new(); + + DLDL key = default; + key.A = CastHandle(methHnd1); + key.B = CastHandle(methHnd2); + + uint value = result ? 1u : 0u; + HaveSameMethodDefinition.Add(key, value); + } + + public void recGetTypeDefinition(CORINFO_CLASS_STRUCT_* cls, CORINFO_CLASS_STRUCT_* result) + { + GetTypeDefinition ??= new(); + + ulong key = CastHandle(cls); + ulong value = CastHandle(result); + GetTypeDefinition.Add(key, value); + } + + public void recGetNewHelper(CORINFO_CLASS_STRUCT_* classHandle, bool hasSideEffects, CorInfoHelpFunc result, uint exceptionCode) + { + GetNewHelper ??= new(); + + ulong key = CastHandle(classHandle); + + DDD value = default; + value.A = hasSideEffects ? 1u : 0u; + value.B = (uint)result; + value.C = exceptionCode; + + GetNewHelper.Add(key, value); + } + + public void recEmbedGenericHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken, bool fEmbedParent, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_GENERICHANDLE_RESULT* pResult) + { + EmbedGenericHandle ??= new(); + + Agnostic_EmbedGenericHandle key = default; + key.ResolvedToken = StoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, EmbedGenericHandle); + key.fEmbedParent = (fEmbedParent ? 1u : 0u); + key.hCallerHandle = CastHandle(callerHandle); + + Agnostic_CORINFO_GENERICHANDLE_RESULT value = default; + value.lookup = StoreAgnostic_CORINFO_LOOKUP(&pResult->lookup); + value.compileTimeHandle = CastHandle(pResult->compileTimeHandle); + value.handleType = (uint)pResult->handleType; + + EmbedGenericHandle.Add(key, value); + } + + public void recGetEHinfo(CORINFO_METHOD_STRUCT_* ftn, uint EHnumber, CORINFO_EH_CLAUSE* clause) + { + GetEHinfo ??= new(); + + DLD key = default; + key.A = CastHandle(ftn); + key.B = (uint)EHnumber; + + Agnostic_CORINFO_EH_CLAUSE value = default; + value.Flags = (uint)clause->Flags; + value.TryOffset = (uint)clause->TryOffset; + value.TryLength = (uint)clause->TryLength; + value.HandlerOffset = (uint)clause->HandlerOffset; + value.HandlerLength = (uint)clause->HandlerLength; + value.ClassToken = (uint)clause->ClassTokenOrOffset; + + GetEHinfo.Add(key, value); + } + + public void recGetMethodVTableOffset(CORINFO_METHOD_STRUCT_* method, uint* offsetOfIndirection, uint* offsetAfterIndirection, bool* isRelative) + { + GetMethodVTableOffset ??= new(); + + DDD value = default; + value.A = (uint)*offsetOfIndirection; + value.B = (uint)*offsetAfterIndirection; + value.C = *isRelative ? 1u : 0u; + + ulong key = CastHandle(method); + GetMethodVTableOffset.Add(key, value); + } + + public void recResolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info, bool returnValue) + { + if (ResolveVirtualMethod == null) + { + ResolveVirtualMethod = new LightWeightMap(); + } + + Agnostic_ResolveVirtualMethodKey key = default; + key.virtualMethod = CastHandle(info->virtualMethod); + key.objClass = CastHandle(info->objClass); + key.context = CastHandle(info->context); + + key.pResolvedTokenVirtualMethodNonNull = info->pResolvedTokenVirtualMethod != null ? 1u : 0u; + if (key.pResolvedTokenVirtualMethodNonNull != 0) + key.pResolvedTokenVirtualMethod = StoreAgnostic_CORINFO_RESOLVED_TOKEN(info->pResolvedTokenVirtualMethod, ResolveToken); + + Agnostic_ResolveVirtualMethodResult result = default; + result.returnValue = returnValue ? (byte)1 : (byte)0; + result.devirtualizedMethod = CastHandle(info->devirtualizedMethod); + result.tokenLookupContext = CastHandle(info->tokenLookupContext); + result.detail = (uint)info->detail; + result.instParamLookup = StoreAgnostic_CORINFO_LOOKUP(&info->instParamLookup); + + if (returnValue) + { + result.resolvedTokenDevirtualizedMethod = StoreAgnostic_CORINFO_RESOLVED_TOKEN(&info->resolvedTokenDevirtualizedMethod, ResolveToken); + result.resolvedTokenDevirtualizedUnboxedMethod = StoreAgnostic_CORINFO_RESOLVED_TOKEN(&info->resolvedTokenDevirtualizedUnboxedMethod, ResolveToken); + } + else + { + result.resolvedTokenDevirtualizedMethod = default; + result.resolvedTokenDevirtualizedUnboxedMethod = default; + } + + ResolveVirtualMethod.Add(key, result); + } + + public void recGetAsyncOtherVariant(CORINFO_METHOD_STRUCT_* ftn, bool variantIsThunk, CORINFO_METHOD_STRUCT_* result) + { + if (GetAsyncOtherVariant == null) + { + GetAsyncOtherVariant = new LightWeightMap(); + } + + ulong key = CastHandle(ftn); + DLD value = default; + value.A = CastHandle(result); + value.B = variantIsThunk ? 1u : 0u; + GetAsyncOtherVariant.Add(key, value); + } + + public void recGetDefaultComparerClass(CORINFO_CLASS_STRUCT_* cls, CORINFO_CLASS_STRUCT_* result) + { + GetDefaultComparerClass ??= new(); + + ulong key = CastHandle(cls); + ulong value = CastHandle(result); + GetDefaultComparerClass.Add(key, value); + } + + public void recGetDefaultEqualityComparerClass(CORINFO_CLASS_STRUCT_* cls, CORINFO_CLASS_STRUCT_* result) + { + GetDefaultEqualityComparerClass ??= new(); + + ulong key = CastHandle(cls); + ulong value = CastHandle(result); + GetDefaultEqualityComparerClass.Add(key, value); + } + + public void recGetSZArrayHelperEnumeratorClass(CORINFO_CLASS_STRUCT_* cls, CORINFO_CLASS_STRUCT_* result) + { + GetSZArrayHelperEnumeratorClass ??= new(); + + ulong key = CastHandle(cls); + ulong value = CastHandle(result); + GetSZArrayHelperEnumeratorClass.Add(key, value); + } + + public void recGetTokenTypeAsHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_CLASS_STRUCT_* result) + { + GetTokenTypeAsHandle ??= new(); + + GetTokenTypeAsHandleValue key = default; + key.hMethod = CastHandle(pResolvedToken->hMethod); + key.hField = CastHandle(pResolvedToken->hField); + + ulong value = CastHandle(result); + GetTokenTypeAsHandle.Add(key, value); + } + + public void recGetFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult) + { + GetFieldInfo ??= new(); + + Agnostic_GetFieldInfo key = default; + key.ResolvedToken = StoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, GetFieldInfo); + key.callerHandle = CastHandle(callerHandle); + key.flags = (uint)flags; + + Agnostic_CORINFO_FIELD_INFO value = default; + value.fieldAccessor = (uint)pResult->fieldAccessor; + value.fieldFlags = (uint)pResult->fieldFlags; + value.helper = (uint)pResult->helper; + value.offset = (uint)pResult->offset; + value.fieldType = (uint)pResult->fieldType; + value.structType = CastHandle(pResult->structType); + value.accessAllowed = (uint)pResult->accessAllowed; + value.accessCalloutHelper = StoreAgnostic_CORINFO_HELPER_DESC(pResult->accessCalloutHelper); + value.fieldLookup = StoreAgnostic_CORINFO_CONST_LOOKUP(&pResult->fieldLookup); + GetFieldInfo.Add(key, value); + } + + public void recGetThreadLocalFieldInfo(CORINFO_FIELD_STRUCT_* field, bool isGCType, uint result) + { + GetThreadLocalFieldInfo ??= new(); + + DLD key = default; + key.A = CastHandle(field); + key.B = isGCType ? 0u : 1u; + GetThreadLocalFieldInfo.Add(key, result); + } + + public void recGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) + { + GetThreadLocalStaticBlocksInfo ??= new(); + + Agnostic_GetThreadLocalStaticBlocksInfo value = default; + + value.tlsIndex = StoreAgnostic_CORINFO_CONST_LOOKUP(&pInfo->tlsIndex); + value.tlsGetAddrFtnPtr = CastPointer(pInfo->tlsGetAddrFtnPtr); + value.tlsIndexObject = CastPointer(pInfo->tlsIndexObject); + value.threadVarsSection = CastPointer(pInfo->threadVarsSection); + value.offsetOfThreadLocalStoragePointer = pInfo->offsetOfThreadLocalStoragePointer; + value.offsetOfMaxThreadStaticBlocks = pInfo->offsetOfMaxThreadStaticBlocks; + value.offsetOfThreadStaticBlocks = pInfo->offsetOfThreadStaticBlocks; + value.offsetOfBaseOfThreadLocalData = pInfo->offsetOfBaseOfThreadLocalData; + + // This data is same for entire process, so just add it against key '0'. + uint key = 0; + GetThreadLocalStaticBlocksInfo.Add(key, value); + } + + public void recGetThreadLocalStaticInfo_NativeAOT(CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo) + { + GetThreadLocalStaticInfo_NativeAOT ??= new(); + + Agnostic_GetThreadStaticInfo_NativeAOT value = default; + value.tlsRootObject = StoreAgnostic_CORINFO_CONST_LOOKUP(&pInfo->tlsRootObject); + value.tlsIndexObject = StoreAgnostic_CORINFO_CONST_LOOKUP(&pInfo->tlsIndexObject); + value.offsetOfThreadLocalStoragePointer = pInfo->offsetOfThreadLocalStoragePointer; + value.threadStaticBaseSlow = StoreAgnostic_CORINFO_CONST_LOOKUP(&pInfo->threadStaticBaseSlow); + value.tlsGetAddrFtnPtr = StoreAgnostic_CORINFO_CONST_LOOKUP(&pInfo->tlsGetAddrFtnPtr); + + ulong key = 1; + + GetThreadLocalStaticInfo_NativeAOT.Add(key, value); + } + + public void recEmbedMethodHandle(CORINFO_METHOD_STRUCT_* handle, void** ppIndirection, CORINFO_METHOD_STRUCT_* result) + { + EmbedMethodHandle ??= new(); + + DLDL value = default; + if (ppIndirection == null) + value.A = 0; + else + value.A = CastPointer(*ppIndirection); + value.B = CastHandle(result); + + ulong key = CastHandle(handle); + EmbedMethodHandle.Add(key, value); + } + + public void recGetStaticFieldContent(CORINFO_FIELD_STRUCT_* field, byte* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects, bool result) + { + GetStaticFieldContent ??= new(); + + DLDDD key = default; + key.A = CastHandle(field); + key.B = (uint)bufferSize; + key.C = (ignoreMovableObjects ? 1u : 0u); + key.D = (uint)valueOffset; + + uint tmpBuf = uint.MaxValue; + if (buffer != null && result) + tmpBuf = (uint)GetStaticFieldContent.AddBuffer(Bytes((byte*)buffer, (uint)bufferSize)); + + DD value = default; + value.A = (result ? 1u : 0u); + value.B = (uint)tmpBuf; + + GetStaticFieldContent.Add(key, value); + } + + public void recGetObjectContent(CORINFO_OBJECT_STRUCT_* obj, byte* buffer, int bufferSize, int valueOffset, bool result) + { + GetObjectContent ??= new(); + + DLDD key = default; + key.A = CastHandle(obj); + key.B = (uint)bufferSize; + key.C = (uint)valueOffset; + + uint tmpBuf = uint.MaxValue; + if (buffer != null && result) + tmpBuf = (uint)GetObjectContent.AddBuffer(Bytes((byte*)buffer, (uint)bufferSize)); + + DD value = default; + value.A = (result ? 1u : 0u); + value.B = (uint)tmpBuf; + + GetObjectContent.Add(key, value); + } + + public void recGetStaticFieldCurrentClass(CORINFO_FIELD_STRUCT_* field, bool* pIsSpeculative, CORINFO_CLASS_STRUCT_* result) + { + GetStaticFieldCurrentClass ??= new(); + + DLD key = default; + key.A = CastHandle(field); + key.B = pIsSpeculative != null ? 1u : 0u; + + Agnostic_GetStaticFieldCurrentClass value = default; + value.classHandle = CastHandle(result); + value.isSpeculative = pIsSpeculative != null && *pIsSpeculative ? (byte)1 : (byte)0; + + GetStaticFieldCurrentClass.Add(key, value); + } + + public void recGetClassGClayout(CORINFO_CLASS_STRUCT_* cls, byte* gcPtrs, uint len, uint result) + { + GetClassGClayout ??= new(); + + Agnostic_GetClassGClayout value = default; + + value.gcPtrs_Index = (uint)GetClassGClayout.AddBuffer(Bytes(gcPtrs, len * sizeof(byte))); + value.len = (uint)len; + value.valCount = (uint)result; + + ulong key = CastHandle(cls); + GetClassGClayout.Add(key, value); + } + + public void recGetClassAlignmentRequirement(CORINFO_CLASS_STRUCT_* cls, bool fDoubleAlignHint, uint result) + { + GetClassAlignmentRequirement ??= new(); + + DLD key = default; + key.A = CastHandle(cls); + key.B = (fDoubleAlignHint ? 1u : 0u); + + uint value = (uint)result; + GetClassAlignmentRequirement.Add(key, value); + } + + public void recCanAccessClass(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_HELPER_DESC* pAccessHelper, CorInfoIsAccessAllowedResult result) + { + CanAccessClass ??= new(); + + Agnostic_CanAccessClassIn key = default; + key.ResolvedToken = StoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, CanAccessClass); + key.callerHandle = CastHandle(callerHandle); + + Agnostic_CanAccessClassOut value = default; + value.AccessHelper = StoreAgnostic_CORINFO_HELPER_DESC(*pAccessHelper); + value.result = (uint)result; + + CanAccessClass.Add(key, value); + } + + public void recGetCastingHelper(CORINFO_RESOLVED_TOKEN* pResolvedToken, bool fThrowing, CorInfoHelpFunc result) + { + GetCastingHelper ??= new(); + + Agnostic_GetCastingHelper key = default; + key.hClass = CastHandle(pResolvedToken->hClass); + key.fThrowing = (fThrowing ? 1u : 0u); + + uint value = (uint)result; + GetCastingHelper.Add(key, value); + } + + public void recEmbedModuleHandle(CORINFO_MODULE_STRUCT_* handle, void** ppIndirection, CORINFO_MODULE_STRUCT_* result) + { + EmbedModuleHandle ??= new(); + + DLDL value = default; + if (ppIndirection != null) + value.A = CastPointer(*ppIndirection); + else + value.A = 0; + value.B = CastHandle(result); + + ulong key = CastHandle(handle); + EmbedModuleHandle.Add(key, value); + } + + public void recEmbedClassHandle(CORINFO_CLASS_STRUCT_* handle, void** ppIndirection, CORINFO_CLASS_STRUCT_* result) + { + EmbedClassHandle ??= new(); + + DLDL value = default; + if (ppIndirection != null) + value.A = CastPointer(*ppIndirection); + else + value.A = 0; + value.B = CastHandle(result); + + ulong key = CastHandle(handle); + EmbedClassHandle.Add(key, value); + } + + public void recPInvokeMarshalingRequired(CORINFO_METHOD_STRUCT_* method, CORINFO_SIG_INFO* callSiteSig, bool result) + { + PInvokeMarshalingRequired ??= new(); + + MethodOrSigInfoValue key = default; + key.method = CastHandle(method); + key.pSig_Index = (uint)PInvokeMarshalingRequired.AddBuffer(Bytes(callSiteSig->pSig, callSiteSig->cbSig)); + key.cbSig = (uint)callSiteSig->cbSig; + key.scope = CastHandle(callSiteSig->scope); + + uint value = result ? 1u : 0u; + PInvokeMarshalingRequired.Add(key, value); + } + + public void recGetUnmanagedCallConv(CORINFO_METHOD_STRUCT_* method, CORINFO_SIG_INFO* callSiteSig, CorInfoCallConvExtension result, bool suppressGCTransitionResult) + { + GetUnmanagedCallConv ??= new(); + + MethodOrSigInfoValue key = default; + key.method = CastHandle(method); + if (callSiteSig != null) + { + key.pSig_Index = (uint)GetUnmanagedCallConv.AddBuffer(Bytes(callSiteSig->pSig, callSiteSig->cbSig)); + key.cbSig = (uint)callSiteSig->cbSig; + key.scope = CastHandle(callSiteSig->scope); + } + else + { + key.pSig_Index = 0; + key.cbSig = 0; + key.scope = 0; + } + + DD value = default; + value.A = (uint)result; + value.B = (suppressGCTransitionResult ? 1u : 0u); + + GetUnmanagedCallConv.Add(key, value); + } + + public void recFindSig(CORINFO_MODULE_STRUCT_* moduleHandle, uint sigTOK, CORINFO_CONTEXT_STRUCT* context, CORINFO_SIG_INFO* sig) + { + FindSig ??= new(); + + Agnostic_FindSig key = default; + key.module = CastHandle(moduleHandle); + key.sigTOK = (uint)sigTOK; + key.context = CastHandle(context); + + Agnostic_CORINFO_SIG_INFO value = StoreSig(*sig, FindSig); + + FindSig.Add(key, value); + } + + public void recGetEEInfo(CORINFO_EE_INFO* pEEInfoOut) + { + GetEEInfo ??= new(); + + Agnostic_CORINFO_EE_INFO value = default; + + value.inlinedCallFrameInfo.size = (uint)pEEInfoOut->inlinedCallFrameInfo.size; + value.inlinedCallFrameInfo.sizeWithSecretStubArg = (uint)pEEInfoOut->inlinedCallFrameInfo.sizeWithSecretStubArg; + value.inlinedCallFrameInfo.offsetOfFrameLink = (uint)pEEInfoOut->inlinedCallFrameInfo.offsetOfFrameLink; + value.inlinedCallFrameInfo.offsetOfCallSiteSP = (uint)pEEInfoOut->inlinedCallFrameInfo.offsetOfCallSiteSP; + value.inlinedCallFrameInfo.offsetOfCalleeSavedFP = (uint)pEEInfoOut->inlinedCallFrameInfo.offsetOfCalleeSavedFP; + value.inlinedCallFrameInfo.offsetOfCallTarget = (uint)pEEInfoOut->inlinedCallFrameInfo.offsetOfCallTarget; + value.inlinedCallFrameInfo.offsetOfReturnAddress = (uint)pEEInfoOut->inlinedCallFrameInfo.offsetOfReturnAddress; + value.inlinedCallFrameInfo.offsetOfSecretStubArg = (uint)pEEInfoOut->inlinedCallFrameInfo.offsetOfSecretStubArg; + value.inlinedCallFrameInfo.offsetOfSPAfterProlog = (uint)pEEInfoOut->inlinedCallFrameInfo.offsetOfSPAfterProlog; + value.offsetOfThreadFrame = (uint)pEEInfoOut->offsetOfThreadFrame; + value.offsetOfGCState = (uint)pEEInfoOut->offsetOfGCState; + value.offsetOfDelegateInstance = (uint)pEEInfoOut->offsetOfDelegateInstance; + value.offsetOfDelegateFirstTarget = (uint)pEEInfoOut->offsetOfDelegateFirstTarget; + value.sizeOfReversePInvokeFrame = (uint)pEEInfoOut->sizeOfReversePInvokeFrame; + value.osPageSize = (uint)pEEInfoOut->osPageSize; + value.maxUncheckedOffsetForNullObject = (uint)pEEInfoOut->maxUncheckedOffsetForNullObject; + value.targetAbi = (uint)pEEInfoOut->targetAbi; + value.osType = (uint)pEEInfoOut->osType; + + GetEEInfo.Add(0, value); + } + + public void recGetAsyncInfo(CORINFO_ASYNC_INFO* pAsyncInfo) + { + GetAsyncInfo ??= new(); + + Agnostic_CORINFO_ASYNC_INFO value = default; + + value.continuationClsHnd = CastHandle(pAsyncInfo->continuationClsHnd); + value.continuationNextFldHnd = CastHandle(pAsyncInfo->continuationNextFldHnd); + value.continuationResumeInfoFldHnd = CastHandle(pAsyncInfo->continuationResumeInfoFldHnd); + value.continuationStateFldHnd = CastHandle(pAsyncInfo->continuationStateFldHnd); + value.continuationFlagsFldHnd = CastHandle(pAsyncInfo->continuationFlagsFldHnd); + value.captureExecutionContextMethHnd = CastHandle(pAsyncInfo->captureExecutionContextMethHnd); + value.captureContinuationContextMethHnd = CastHandle(pAsyncInfo->captureContinuationContextMethHnd); + 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); + + GetAsyncInfo.Add(0, value); + } + + public void recGetWasmWellKnownGlobals(CORINFO_WASM_WELLKNOWN_GLOBALS* pBaseGlobals) + { + GetWasmWellKnownGlobals ??= new(); + + Agnostic_CORINFO_WASM_WELLKNOWN_GLOBALS value = default; + + value.stackPointer = CastHandle(pBaseGlobals->stackPointer); + value.imageBase = CastHandle(pBaseGlobals->imageBase); + value.tableBase = CastHandle(pBaseGlobals->tableBase); + value.asyncContinuation = CastHandle(pBaseGlobals->asyncContinuation); + + GetWasmWellKnownGlobals.Add(0, value); + } + + public void recGetAwaitReturnCall(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_CONTEXT_STRUCT** contextHandle, CORINFO_LOOKUP* instArg, CORINFO_METHOD_STRUCT_* methHnd) + { + GetAwaitReturnCall ??= new(); + + Agnostic_GetAwaitReturnCallResult value = default; + value.methodHnd = CastHandle(methHnd); + value.contextHandle = CastHandle(*contextHandle); + value.instArg = StoreAgnostic_CORINFO_LOOKUP(instArg); + + GetAwaitReturnCall.Add(CastHandle(callerHnd), value); + } + + public void recGetAwaitAwaiterInContinuationCall(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_RESOLVED_TOKEN* pResolvedToken, bool isUnsafe, CORINFO_CONTEXT_STRUCT** contextHandle, CORINFO_LOOKUP* instArg, CORINFO_METHOD_STRUCT_* methHnd) + { + if (GetAwaitAwaiterInContinuationCall == null) + { + GetAwaitAwaiterInContinuationCall = + new LightWeightMap(); + } + + Agnostic_GetAwaitAwaiterInContinuationCall key = default; + key.callerHnd = CastHandle(callerHnd); + key.ResolvedToken = + StoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, GetAwaitAwaiterInContinuationCall); + key.isUnsafe = isUnsafe ? 1u : 0u; + + Agnostic_GetAwaitReturnCallResult value = default; + value.methodHnd = CastHandle(methHnd); + value.contextHandle = CastHandle(*contextHandle); + value.instArg = StoreAgnostic_CORINFO_LOOKUP(instArg); + + GetAwaitAwaiterInContinuationCall.Add(key, value); + } + + public void recGetGSCookie(nint* pCookieVal, nint** ppCookieVal) + { + GetGSCookie ??= new(); + + DLDL value = default; + + if (pCookieVal != null) + value.A = (ulong)*pCookieVal; + else + value.A = 0; + + if (ppCookieVal != null) + value.B = CastPointer(*ppCookieVal); + else + value.B = 0; + + GetGSCookie.Add(0, value); + } + + public void recGetOSRInfo(PatchpointInfo* patchpointInfo, uint* ilOffset) + { + GetOSRInfo ??= new(); + + Agnostic_GetOSRInfo value = default; + + value.index = GetOSRInfo.AddBuffer(Bytes(patchpointInfo, PatchpointInfoSize(patchpointInfo))); + value.ilOffset = *ilOffset; + + // use 0 for key + uint key = 0; + GetOSRInfo.Add(key, value); + } + + public void recGetClassModuleIdForStatics(CORINFO_CLASS_STRUCT_* cls, CORINFO_MODULE_STRUCT_** pModule, void** ppIndirection, nuint result) + { + GetClassModuleIdForStatics ??= new(); + + Agnostic_GetClassModuleIdForStatics value = default; + + if (pModule != null) + value.Module = CastHandle(*pModule); + else + value.Module = 0; + if (ppIndirection != null) + value.pIndirection = CastPointer(*ppIndirection); + else + value.pIndirection = 0; + value.result = (ulong)result; + + ulong key = CastHandle(cls); + GetClassModuleIdForStatics.Add(key, value); + } + + public void recGetIsClassInitedFlagAddress(CORINFO_CLASS_STRUCT_* cls, CORINFO_CONST_LOOKUP* addr, int* offset, bool result) + { + GetIsClassInitedFlagAddress ??= new(); + + Agnostic_GetIsClassInitedFlagAddress value = default; + value.addr.handle = CastHandle(addr->addr); + value.addr.accessType = (uint)addr->accessType; + value.offset = (uint)*offset; + value.result = (result ? 1u : 0u); + + ulong key = CastHandle(cls); + GetIsClassInitedFlagAddress.Add(key, value); + } + + public void recGetStaticBaseAddress(CORINFO_CLASS_STRUCT_* cls, bool isGc, CORINFO_CONST_LOOKUP* addr, bool result) + { + GetStaticBaseAddress ??= new(); + + Agnostic_GetStaticBaseAddress value = default; + value.addr.handle = CastHandle(addr->addr); + value.addr.accessType = (uint)addr->accessType; + value.result = result ? 1u : 0u; + + DLD key = default; + key.A = CastHandle(cls); + key.B = (isGc ? 1u : 0u); + + GetStaticBaseAddress.Add(key, value); + } + + public void recGetThreadTLSIndex(void** ppIndirection, uint result) + { + GetThreadTLSIndex ??= new(); + + DLD value = default; + + if (ppIndirection != null) + value.A = CastPointer(*ppIndirection); + else + value.A = 0; + value.B = (uint)result; + + GetThreadTLSIndex.Add(0, value); + } + + public void recGetAddrOfCaptureThreadGlobal(void** ppIndirection, int* result) + { + GetAddrOfCaptureThreadGlobal ??= new(); + + DLDL value = default; + + if (ppIndirection != null) + value.A = CastPointer(*ppIndirection); + else + value.A = 0; + value.B = CastPointer(result); + + GetAddrOfCaptureThreadGlobal.Add(0, value); + } + + public void recGetClassStaticDynamicInfo(CORINFO_CLASS_STRUCT_* cls, void* result) + { + GetClassStaticDynamicInfo ??= new(); + + DLD value = default; + + value.A = CastPointer(result); + value.B = 0; + + ulong key = CastHandle(cls); + GetClassStaticDynamicInfo.Add(key, value); + } + + public void recGetClassThreadStaticDynamicInfo(CORINFO_CLASS_STRUCT_* cls, void* result) + { + GetClassThreadStaticDynamicInfo ??= new(); + + DLD value = default; + + value.A = CastPointer(result); + value.B = 0; + + ulong key = CastHandle(cls); + GetClassThreadStaticDynamicInfo.Add(key, value); + } + + public void recGetLocationOfThisType(CORINFO_METHOD_STRUCT_* context, CORINFO_LOOKUP_KIND* result) + { + GetLocationOfThisType ??= new(); + + Agnostic_CORINFO_LOOKUP_KIND value = CreateAgnostic_CORINFO_LOOKUP_KIND(result); + + ulong key = CastHandle(context); + GetLocationOfThisType.Add(key, value); + } + + public void recGetDelegateCtor(CORINFO_METHOD_STRUCT_* methHnd, CORINFO_CLASS_STRUCT_* clsHnd, CORINFO_METHOD_STRUCT_* targetMethodHnd, DelegateCtorArgs* pCtorData, CORINFO_METHOD_STRUCT_* result) + { + GetDelegateCtor ??= new(); + + Agnostic_GetDelegateCtorIn key = default; + key.methHnd = CastHandle(methHnd); + key.clsHnd = CastHandle(clsHnd); + key.targetMethodHnd = CastHandle(targetMethodHnd); + + Agnostic_GetDelegateCtorOut value = default; + value.CtorData.pMethod = CastPointer(pCtorData->pMethod); + value.CtorData.pArg3 = CastPointer(pCtorData->pArg3); + value.CtorData.pArg4 = CastPointer(pCtorData->pArg4); + value.CtorData.pArg5 = CastPointer(pCtorData->pArg5); + value.result = CastHandle(result); + + GetDelegateCtor.Add(key, value); + } + + public void recGetFunctionFixedEntryPoint(CORINFO_METHOD_STRUCT_* ftn, CORINFO_CONST_LOOKUP* pResult) + { + GetFunctionFixedEntryPoint ??= new(); + + Agnostic_CORINFO_CONST_LOOKUP value = StoreAgnostic_CORINFO_CONST_LOOKUP(pResult); + + ulong key = CastHandle(ftn); + GetFunctionFixedEntryPoint.Add(key, value); + } + + public void recGetFieldInClass(CORINFO_CLASS_STRUCT_* clsHnd, int num, CORINFO_FIELD_STRUCT_* result) + { + GetFieldInClass ??= new(); + + DLD key = default; + key.A = CastHandle(clsHnd); + key.B = (uint)num; + + ulong value = CastHandle(result); + GetFieldInClass.Add(key, value); + } + + public void recGetTypeLayout(GetTypeLayoutResult result, CORINFO_CLASS_STRUCT_* typeHnd, CORINFO_TYPE_LAYOUT_NODE* nodes, nuint numNodes) + { + GetTypeLayout ??= new(); + + ulong key = CastHandle(typeHnd); + + int index = GetTypeLayout.GetIndex(key); + if (index != -1) + { + // If we already have this then just skip. + Agnostic_GetTypeLayoutResult existing = GetTypeLayout.GetItem(index); + if ((existing.result != (uint)GetTypeLayoutResult.Partial) || + (result == GetTypeLayoutResult.Failure) || + (numNodes <= existing.numNodes)) + { + // No new data to add + return; + } + + // Otherwise fall through and update the map with more information. + } + + Agnostic_GetTypeLayoutResult value = default; + + value.result = (uint)result; + if (result == GetTypeLayoutResult.Failure) + { + value.nodesBuffer = uint.MaxValue; + } + else + { + var agnosticFields = new Agnostic_CORINFO_TYPE_LAYOUT_NODE[(int)numNodes]; + for (int i = 0; i < agnosticFields.Length; i++) + agnosticFields[i] = StoreAgnostic_CORINFO_TYPE_LAYOUT_NODE(nodes[i]); + + value.nodesBuffer = GetTypeLayout.AddBuffer(MemoryMarshal.AsBytes(agnosticFields.AsSpan())); + value.numNodes = (uint)numNodes; + } + + if (index != -1) + { + GetTypeLayout.Update(index, value); + } + else + { + GetTypeLayout.Add(key, value); + } + } + + public void recGetFieldType(CORINFO_FIELD_STRUCT_* field, CORINFO_CLASS_STRUCT_** structType, CORINFO_CLASS_STRUCT_* fieldOwnerHint, CorInfoType result) + { + GetFieldType ??= new(); + + DLDL key = default; + key.A = CastHandle(field); + key.B = CastHandle(fieldOwnerHint); + + DLD value = default; + value.B = (uint)result; + if (structType == null) + { + value.A = 0; + } + else + { + value.A = CastHandle(*structType); + + // If we had a previous call with null 'structType', we will not have captured the + // class handle (we use only 'field' and 'fieldOwnerHint' as keys). + // Update the value in that case. + int index = GetFieldType.GetIndex(key); + if ((index != -1) && (GetFieldType.GetItem(index).A == 0)) + { + GetFieldType.Update(index, value); + return; + } + } + GetFieldType.Add(key, value); + } + + public void recSatisfiesMethodConstraints(CORINFO_CLASS_STRUCT_* parent, CORINFO_METHOD_STRUCT_* method, bool result) + { + SatisfiesMethodConstraints ??= new(); + + DLDL key = default; + key.A = CastHandle(parent); + key.B = CastHandle(method); + + uint value = result ? 1u : 0u; + SatisfiesMethodConstraints.Add(key, value); + } + + public void recGetStringLiteral(CORINFO_MODULE_STRUCT_* module, uint metaTOK, char* buffer, int bufferSize, int startIndex, int length) + { + GetStringLiteral ??= new(); + + DLDDD key = default; + key.A = CastHandle(module); + key.B = (uint)metaTOK; + key.C = (uint)bufferSize; + key.D = (uint)startIndex; + + uint strBuf = uint.MaxValue; + if (buffer != null && length != -1) + { + int bufferRealSize = Math.Min(length, bufferSize) * sizeof(char); + strBuf = (uint)GetStringLiteral.AddBuffer(Bytes(buffer, (uint)bufferRealSize)); + } + + DD value = default; + value.A = (uint)length; + value.B = (uint)strBuf; + + GetStringLiteral.Add(key, value); + } + + public void recCanCast(CORINFO_CLASS_STRUCT_* child, CORINFO_CLASS_STRUCT_* parent, bool result) + { + CanCast ??= new(); + + DLDL key = default; + key.A = CastHandle(child); + key.B = CastHandle(parent); + + uint value = result ? 1u : 0u; + CanCast.Add(key, value); + } + + public void recGetChildType(CORINFO_CLASS_STRUCT_* clsHnd, CORINFO_CLASS_STRUCT_** clsRet, CorInfoType result) + { + GetChildType ??= new(); + + DLD value = default; + value.A = CastHandle(*clsRet); + value.B = (uint)result; + + ulong key = CastHandle(clsHnd); + GetChildType.Add(key, value); + } + + public void recGetArrayInitializationData(CORINFO_FIELD_STRUCT_* field, uint size, void* result) + { + GetArrayInitializationData ??= new(); + + DLD key = default; + key.A = CastHandle(field); + key.B = (uint)size; + + ulong value = CastPointer(result); + GetArrayInitializationData.Add(key, value); + } + + public void recGetAddressOfPInvokeTarget(CORINFO_METHOD_STRUCT_* method, CORINFO_CONST_LOOKUP* pLookup) + { + GetAddressOfPInvokeTarget ??= new(); + + DLD value = default; + value.A = CastPointer(pLookup->addr); + value.B = (uint)pLookup->accessType; + + ulong key = CastHandle(method); + GetAddressOfPInvokeTarget.Add(key, value); + } + + public void recGetMethodHash(CORINFO_METHOD_STRUCT_* ftn, uint result) + { + GetMethodHash ??= new(); + + ulong key = CastHandle(ftn); + uint value = (uint)result; + GetMethodHash.Add(key, value); + } + + public void recCanTailCall(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* declaredCalleeHnd, CORINFO_METHOD_STRUCT_* exactCalleeHnd, bool fIsTailPrefix, bool result) + { + CanTailCall ??= new(); + + Agnostic_CanTailCall key = default; + key.callerHnd = CastHandle(callerHnd); + key.declaredCalleeHnd = CastHandle(declaredCalleeHnd); + key.exactCalleeHnd = CastHandle(exactCalleeHnd); + key.fIsTailPrefix = fIsTailPrefix ? (ushort)1 : (ushort)0; + + uint value = result ? 1u : 0u; + CanTailCall.Add(key, value); + } + + public void recIsDelegateCreationAllowed(CORINFO_CLASS_STRUCT_* delegateHnd, CORINFO_METHOD_STRUCT_* calleeHnd, bool result) + { + IsDelegateCreationAllowed ??= new(); + + DLDL key = default; + key.A = CastHandle(delegateHnd); + key.B = CastHandle(calleeHnd); + + uint value = result ? 1u : 0u; + IsDelegateCreationAllowed.Add(key, value); + } + + public void recFindCallSiteSig(CORINFO_MODULE_STRUCT_* module, uint methTOK, CORINFO_CONTEXT_STRUCT* context, CORINFO_SIG_INFO* sig) + { + FindCallSiteSig ??= new(); + + Agnostic_FindCallSiteSig key = default; + key.module = CastHandle(module); + key.methTok = (uint)methTOK; + key.context = CastHandle(context); + + Agnostic_CORINFO_SIG_INFO value = StoreSig(*sig, FindCallSiteSig); + + FindCallSiteSig.Add(key, value); + } + + public void recGetVarArgsHandle(CORINFO_SIG_INFO* pSig, CORINFO_METHOD_STRUCT_* methHnd, void** ppIndirection, void* result) + { + GetVarArgsHandle ??= new(); + + GetVarArgsHandleValue key = default; + key.cbSig = (uint)pSig->cbSig; + key.pSig_Index = (uint)GetVarArgsHandle.AddBuffer(Bytes(pSig->pSig, pSig->cbSig)); + key.scope = CastHandle(pSig->scope); + key.token = (uint)pSig->token; + key.methHnd = CastHandle(methHnd); + + DLDL value = default; + if (ppIndirection != null) + value.A = CastPointer(*ppIndirection); + else + value.A = 0; + value.B = CastHandle(result); + + GetVarArgsHandle.Add(key, value); + } + + public void recGetFieldThreadLocalStoreID(CORINFO_FIELD_STRUCT_* field, void** ppIndirection, uint result) + { + GetFieldThreadLocalStoreID ??= new(); + + DLD value = default; + + if (ppIndirection != null) + value.A = CastPointer(*ppIndirection); + else + value.A = 0; + value.B = (uint)result; + + ulong key = CastHandle(field); + GetFieldThreadLocalStoreID.Add(key, value); + } + + public void recAllocPgoInstrumentationBySchema(CORINFO_METHOD_STRUCT_* ftnHnd, PgoInstrumentationSchema* pSchema, uint countSchemaItems, byte** pInstrumentationData, int result) + { + AllocPgoInstrumentationBySchema ??= new(); + + Agnostic_AllocPgoInstrumentationBySchema value = default; + + // PGO schema data poses a couple of challenges from SPMI's perspective: + // + // First of, the schema requested from the JIT can reasonably be considered + // a compile result that might change with different JIT versions and/or + // environment variables set. So that means SPMI should be able to handle + // seeing a different schema from recording time. + // + // On the other hand, the code generated by the JIT will refer to addresses + // based on pInstrumentationData and the offsets this function assigns in + // pSchema. That means this function should be consistent with the recorded + // EE in how it does layout, to ensure replay is going to match recording + // time. + // + // To handle these issues we store the recorded result of layout for the + // schema and use that if the JIT's requested schema matches it. Otherwise + // we use our own layout algorithm for the schema. This layout algorithm is + // probably not going to match the EE's algorithm exactly, but that's not + // problematic since a different schema likely means there are going to be + // diffs anyway. + + value.instrumentationDataAddress = CastPointer(*pInstrumentationData); + + // For the schema, note that we record *after* calling the VM API. Thus, it has already filled in the `Offset` fields. + // We save the "IN" parts to verify against the replayed call. + value.countSchemaItems = countSchemaItems; + var agnosticSchema = new Agnostic_PgoInstrumentationSchema[countSchemaItems]; + for (uint i = 0; i < countSchemaItems; i++) + { + agnosticSchema[i].Offset = (ulong)pSchema[i].Offset; + agnosticSchema[i].InstrumentationKind = (uint)pSchema[i].InstrumentationKind; + agnosticSchema[i].ILOffset = (uint)pSchema[i].ILOffset; + agnosticSchema[i].Count = (uint)pSchema[i].Count; + agnosticSchema[i].Other = (uint)pSchema[i].Other; + } + value.schema_index = AllocPgoInstrumentationBySchema.AddBuffer(MemoryMarshal.AsBytes(agnosticSchema.AsSpan())); + value.result = (uint)result; + + // Even though `countSchemaItems` and (most of) the `pSchema` array are IN parameters, they do not contribute to the lookup key; + // the `ftnHnd` is the sole key, and the schema passed in for the function is expected to be the same every time the same function + // handle is used. + ulong key = CastHandle(ftnHnd); + AllocPgoInstrumentationBySchema.Add(key, value); + } + + public void recGetPgoInstrumentationResults(CORINFO_METHOD_STRUCT_* ftnHnd, PgoInstrumentationSchema** pSchema, uint* pCountSchemaItems, byte** pInstrumentationData, PgoSource* pPgoSource, bool* pDynamicPgo, int result) + { + GetPgoInstrumentationResults ??= new(); + + Agnostic_GetPgoInstrumentationResults value = default; + + value.countSchemaItems = *pCountSchemaItems; + + PgoInstrumentationSchema* pInSchema = *pSchema; + var agnosticSchema = new Agnostic_PgoInstrumentationSchema[*pCountSchemaItems]; + nuint maxOffset = 0; + for (uint i = 0; i < (*pCountSchemaItems); i++) + { + agnosticSchema[i].Offset = (ulong)pInSchema[i].Offset; + agnosticSchema[i].InstrumentationKind = (uint)pInSchema[i].InstrumentationKind; + agnosticSchema[i].ILOffset = (uint)pInSchema[i].ILOffset; + agnosticSchema[i].Count = (uint)pInSchema[i].Count; + agnosticSchema[i].Other = (uint)pInSchema[i].Other; + + uint dataSize = InstrumentationKindToSize(pInSchema[i].InstrumentationKind); + maxOffset = Math.Max(maxOffset, (nuint)pInSchema[i].Offset + (uint)pInSchema[i].Count * dataSize); + } + value.schema_index = GetPgoInstrumentationResults.AddBuffer(MemoryMarshal.AsBytes(agnosticSchema.AsSpan())); + + value.data_index = GetPgoInstrumentationResults.AddBuffer(Bytes(*pInstrumentationData, (uint)maxOffset)); + value.dataByteCount = (uint)maxOffset; + value.result = (uint)result; + value.pgoSource = (uint)*pPgoSource; + value.dynamicPgo = (*pDynamicPgo ? 1u : 0u); + + ulong key = CastHandle(ftnHnd); + GetPgoInstrumentationResults.Add(key, value); + } + + public void recIsMoreSpecificType(CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2, bool result) + { + IsMoreSpecificType ??= new(); + + DLDL key = default; + key.A = CastHandle(cls1); + key.B = CastHandle(cls2); + + uint value = result ? 1u : 0u; + IsMoreSpecificType.Add(key, value); + } + + public void recIsExactType(CORINFO_CLASS_STRUCT_* cls, bool result) + { + IsExactType ??= new(); + + ulong key = CastHandle(cls); + uint value = result ? 1u : 0u; + IsExactType.Add(key, value); + } + + public void recIsGenericType(CORINFO_CLASS_STRUCT_* cls, TypeCompareState result) + { + IsGenericType ??= new(); + + ulong key = CastHandle(cls); + uint value = (uint)result; + IsGenericType.Add(key, value); + } + + public void recIsNullableType(CORINFO_CLASS_STRUCT_* cls, TypeCompareState result) + { + IsNullableType ??= new(); + + ulong key = CastHandle(cls); + uint value = (uint)result; + IsNullableType.Add(key, value); + } + + public void recIsEnum(CORINFO_CLASS_STRUCT_* cls, CORINFO_CLASS_STRUCT_* underlyingType, TypeCompareState result) + { + IsEnum ??= new(); + + ulong key = CastHandle(cls); + + DLD value = default; + value.A = CastHandle(underlyingType); + value.B = (uint)result; + + IsEnum.Add(key, value); + } + + public void recGetCookieForInterpreterCalliSig(CORINFO_SIG_INFO* szMetaSig, void* result) + { + GetCookieForInterpreterCalliSig ??= new(); + + GetCookieForInterpreterCalliSigValue key = default; + key.cbSig = (uint)szMetaSig->cbSig; + key.pSig_Index = (uint)GetCookieForInterpreterCalliSig.AddBuffer(Bytes(szMetaSig->pSig, szMetaSig->cbSig)); + key.scope = CastHandle(szMetaSig->scope); + key.token = (uint)szMetaSig->token; + + DLDL value = default; + value.A = CastPointer(result); + + GetCookieForInterpreterCalliSig.Add(key, value); + } + + public void recErrorList(byte* error) + { + ErrorList ??= new(); + + uint temp = uint.MaxValue; + + if (error != null) + temp = (uint)ErrorList.AddBuffer(Bytes(error, strlen(error) + 1)); + + ErrorList.Append(temp); + } + + public void recGetProfilingHandle(bool* pbHookFunction, void** pProfilerHandle, bool* pbIndirectedHandles) + { + GetProfilingHandle ??= new(); + + Agnostic_GetProfilingHandle value = default; + value.bHookFunction = (*pbHookFunction ? 1u : 0u); + value.ProfilerHandle = CastPointer(*pProfilerHandle); + value.bIndirectedHandles = (*pbIndirectedHandles ? 1u : 0u); + GetProfilingHandle.Add(0, value); + } + + public void recEmbedFieldHandle(CORINFO_FIELD_STRUCT_* handle, void** ppIndirection, CORINFO_FIELD_STRUCT_* result) + { + EmbedFieldHandle ??= new(); + + DLDL value = default; + if (ppIndirection != null) + value.A = CastPointer(*ppIndirection); + else + value.A = 0; + value.B = CastHandle(result); + + ulong key = CastHandle(handle); + EmbedFieldHandle.Add(key, value); + } + + public void recCompareTypesForCast(CORINFO_CLASS_STRUCT_* fromClass, CORINFO_CLASS_STRUCT_* toClass, TypeCompareState result) + { + CompareTypesForCast ??= new(); + + DLDL key = default; + key.A = CastHandle(fromClass); + key.B = CastHandle(toClass); + + uint value = (uint)result; + CompareTypesForCast.Add(key, value); + } + + public void recCompareTypesForEquality(CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2, TypeCompareState result) + { + CompareTypesForEquality ??= new(); + + DLDL key = default; + key.A = CastHandle(cls1); + key.B = CastHandle(cls2); + + uint value = (uint)result; + CompareTypesForEquality.Add(key, value); + } + + public void recGetSystemVAmd64PassStructInRegisterDescriptor(CORINFO_CLASS_STRUCT_* structHnd, SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr, bool result) + { + GetSystemVAmd64PassStructInRegisterDescriptor ??= new(); + + ulong key = CastHandle(structHnd); + + Agnostic_GetSystemVAmd64PassStructInRegisterDescriptor value = default; + value.passedInRegisters = structPassInRegDescPtr->passedInRegisters ? 1u : 0u; + value.eightByteCount = (uint)structPassInRegDescPtr->eightByteCount; + value.eightByteClassifications[0] = (uint)structPassInRegDescPtr->eightByteClassifications0; + value.eightByteClassifications[1] = (uint)structPassInRegDescPtr->eightByteClassifications1; + value.eightByteSizes[0] = (uint)structPassInRegDescPtr->eightByteSizes0; + value.eightByteSizes[1] = (uint)structPassInRegDescPtr->eightByteSizes1; + value.eightByteOffsets[0] = (uint)structPassInRegDescPtr->eightByteOffsets0; + value.eightByteOffsets[1] = (uint)structPassInRegDescPtr->eightByteOffsets1; + value.result = result ? 1u : 0u; + + GetSystemVAmd64PassStructInRegisterDescriptor.Add(key, value); + } + + public void recGetSwiftLowering(CORINFO_CLASS_STRUCT_* structHnd, CORINFO_SWIFT_LOWERING* pLowering) + { + GetSwiftLowering ??= new(); + + ulong key = CastHandle(structHnd); + + Agnostic_GetSwiftLowering value = default; + value.byReference = pLowering->byReference ? 1u : 0u; + if (!pLowering->byReference) + { + value.numLoweredElements = (uint)pLowering->numLoweredElements; + for (int i = 0; i < pLowering->numLoweredElements; i++) + { + value.loweredElements[i] = (uint)pLowering->LoweredElements[i]; + value.offsets[i] = pLowering->Offsets[i]; + } + } + + GetSwiftLowering.Add(key, value); + } + + public void recGetFpStructLowering(CORINFO_CLASS_STRUCT_* structHnd, CORINFO_FPSTRUCT_LOWERING* pLowering) + { + GetFpStructLowering ??= new(); + + ulong key = CastHandle(structHnd); + + Agnostic_GetFpStructLowering value = default; + value.byIntegerCallConv = pLowering->byIntegerCallConv ? 1u : 0u; + if (!pLowering->byIntegerCallConv) + { + value.numLoweredElements = (uint)pLowering->numLoweredElements; + for (int i = 0; i < pLowering->numLoweredElements; i++) + { + value.loweredElements[i] = (uint)pLowering->LoweredElements[i]; + value.offsets[i] = pLowering->Offsets[i]; + } + } + + GetFpStructLowering.Add(key, value); + } + + public void recGetWasmLowering(CORINFO_CLASS_STRUCT_* structHnd, CorInfoWasmType value) + { + GetWasmLowering ??= new(); + ulong key = CastHandle(structHnd); + GetWasmLowering.Add(key, (uint) value); + } + + public void recGetRelocTypeHint(void* target, CorInfoReloc result) + { + GetRelocTypeHint ??= new(); + + ulong key = CastPointer(target); + uint value = (uint)result; + GetRelocTypeHint.Add(key, value); + } + + public void recGetAddressAlignment(void* address, uint result) + { + GetAddressAlignment ??= new(); + + ulong key = CastPointer(address); + uint value = (uint)result; + GetAddressAlignment.Add(key, value); + } + + public void recGetExpectedTargetArchitecture(uint result) + { + GetExpectedTargetArchitecture ??= new(); + + uint key = 0; // There is only ever a single entry to this map + GetExpectedTargetArchitecture.Add(key, result); + } + + public void recDoesFieldBelongToClass(CORINFO_FIELD_STRUCT_* fld, CORINFO_CLASS_STRUCT_* cls, bool result) + { + DoesFieldBelongToClass ??= new(); + + DLDL key = default; + key.A = CastHandle(fld); + key.B = CastHandle(cls); + + uint value = (result ? 1u : 0u); + DoesFieldBelongToClass.Add(key, value); + } + + public void recGetClassNameFromMetadata(CORINFO_CLASS_STRUCT_* cls, byte* className, byte** namespaceName) + { + GetClassNameFromMetadata ??= new(); + + DLD key = default; + key.A = CastHandle(cls); + key.B = (namespaceName != null) ? 1u : 0u; + + DD value = default; + if (className != null) + value.A = GetClassNameFromMetadata.AddBuffer(Bytes(className, strlen(className) + 1)); + else + value.A = uint.MaxValue; + + if ((namespaceName != null) && (*namespaceName != null)) + value.B = + GetClassNameFromMetadata.AddBuffer(Bytes(*namespaceName, strlen(*namespaceName) + 1)); + else + value.B = uint.MaxValue; + + GetClassNameFromMetadata.Add(key, value); + } + + public void recGetTypeInstantiationArgument(CORINFO_CLASS_STRUCT_* cls, uint index, CORINFO_CLASS_STRUCT_* result) + { + GetTypeInstantiationArgument ??= new(); + + DLD key = default; + key.A = CastHandle(cls); + key.B = index; + ulong value = CastHandle(result); + GetTypeInstantiationArgument.Add(key, value); + } + + public void recGetMethodInstantiationArgument(CORINFO_METHOD_STRUCT_* ftn, uint index, CORINFO_CLASS_STRUCT_* result) + { + GetMethodInstantiationArgument ??= new(); + + DLD key = default; + key.A = CastHandle(ftn); + key.B = index; + ulong value = CastHandle(result); + GetMethodInstantiationArgument.Add(key, value); + } + + private static void recPrint(LightWeightMap map, ulong handle, byte* buffer, nuint bufferSize, nuint* pRequiredBufferSize, nuint bytesWritten) + { + // Required size of a buffer that contains all data and null terminator. + uint requiredBufferSize = uint.MaxValue; + if (pRequiredBufferSize != null) + { + requiredBufferSize = (uint)(*pRequiredBufferSize); + } + else if (bytesWritten + 1 < bufferSize) + { + requiredBufferSize = (uint)(bytesWritten + 1); + } + + Agnostic_PrintResult res = default; + int index = map.GetIndex(handle); + if (index != -1) + { + // Merge with existing entry + + res = map.GetItem(index); + + if (requiredBufferSize != uint.MaxValue) + { + res.requiredBufferSize = requiredBufferSize; + } + + if (bytesWritten > res.stringBufferSize) + { + // Always stored without null terminator. + res.stringBuffer = map.AddBuffer(Bytes(buffer, (uint)bytesWritten)); + res.stringBufferSize = (uint)bytesWritten; + } + + map.Update(index, res); + + return; + } + + if (buffer != null) + { + res.stringBuffer = map.AddBuffer(Bytes(buffer, (uint)bytesWritten)); + } + else + { + res.stringBuffer = uint.MaxValue; + } + + res.stringBufferSize = (uint)bytesWritten; + res.requiredBufferSize = requiredBufferSize; + + map.Add(handle, res); + } + + public void recPrintObjectDescription(CORINFO_OBJECT_STRUCT_* handle, byte* buffer, nuint bufferSize, nuint* pRequiredBufferSize, nuint bytesWritten) + { + recPrint(PrintObjectDescription ??= new(), CastHandle(handle), buffer, bufferSize, pRequiredBufferSize, bytesWritten); + } + + public void recPrintClassName(CORINFO_CLASS_STRUCT_* cls, byte* buffer, nuint bufferSize, nuint* pRequiredBufferSize, nuint bytesWritten) + { + recPrint(PrintClassName ??= new(), CastHandle(cls), buffer, bufferSize, pRequiredBufferSize, bytesWritten); + } + + public void recPrintFieldName(CORINFO_FIELD_STRUCT_* fld, byte* buffer, nuint bufferSize, nuint* pRequiredBufferSize, nuint bytesWritten) + { + recPrint(PrintFieldName ??= new(), CastHandle(fld), buffer, bufferSize, pRequiredBufferSize, bytesWritten); + } + + public void recPrintMethodName(CORINFO_METHOD_STRUCT_* meth, byte* buffer, nuint bufferSize, nuint* pRequiredBufferSize, nuint bytesWritten) + { + recPrint(PrintMethodName ??= new(), CastHandle(meth), buffer, bufferSize, pRequiredBufferSize, bytesWritten); + } + + public void recGetTailCallHelpers(CORINFO_RESOLVED_TOKEN* callToken, CORINFO_SIG_INFO* sig, CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, CORINFO_TAILCALL_HELPERS* pResult) + { + GetTailCallHelpers ??= new(); + + Agnostic_GetTailCallHelpers key = default; + key.callToken = StoreAgnostic_CORINFO_RESOLVED_TOKEN(callToken, GetTailCallHelpers); + key.sig = StoreSig(*sig, GetTailCallHelpers); + key.flags = (uint)flags; + + Agnostic_CORINFO_TAILCALL_HELPERS value = default; + value.result = pResult != null ? (byte)1 : (byte)0; + if (pResult != null) + { + value.flags = (uint)pResult->flags; + value.hStoreArgs = CastHandle(pResult->hStoreArgs); + value.hCallTarget = CastHandle(pResult->hCallTarget); + value.hDispatcher = CastHandle(pResult->hDispatcher); + } + + GetTailCallHelpers.Add(key, value); + } + + public void recGetAsyncResumptionStub(CORINFO_METHOD_STRUCT_* hnd, void* entryPoint) + { + GetAsyncResumptionStub ??= new(); + + DLDL result = default; + result.A = CastHandle(hnd); + result.B = CastPointer(entryPoint); + GetAsyncResumptionStub.Add(0, result); + } + + public void recGetContinuationType(nuint dataSize, bool* objRefs, nuint objRefsSize, CORINFO_CLASS_STRUCT_* result) + { + if (GetContinuationType == null) + { + GetContinuationType = new LightWeightMap(); + } + + Agnostic_GetContinuationTypeIn key = default; + key.dataSize = (ulong)dataSize; + key.objRefs = GetContinuationType.AddBuffer(Bytes(objRefs, (uint)objRefsSize)); + key.objRefsSize = (uint)objRefsSize; + + ulong value = CastHandle(result); + + GetContinuationType.Add(key, value); + } + + public void recUpdateEntryPointForTailCall(CORINFO_CONST_LOOKUP origEntryPoint, CORINFO_CONST_LOOKUP newEntryPoint) + { + UpdateEntryPointForTailCall ??= new(); + + Agnostic_CORINFO_CONST_LOOKUP key = StoreAgnostic_CORINFO_CONST_LOOKUP(&origEntryPoint); + Agnostic_CORINFO_CONST_LOOKUP value = StoreAgnostic_CORINFO_CONST_LOOKUP(&newEntryPoint); + UpdateEntryPointForTailCall.Add(key, value); + } + + public void recGetMethodDefFromMethod(CORINFO_METHOD_STRUCT_* hMethod, uint result) + { + GetMethodDefFromMethod ??= new(); + + ulong key = CastHandle(hMethod); + uint value = (uint)result; + GetMethodDefFromMethod.Add(key, value); + } + + public void recCheckMethodModifier(CORINFO_METHOD_STRUCT_* hMethod, byte* modifier, bool fOptional, bool result) + { + CheckMethodModifier ??= new(); + + Agnostic_CheckMethodModifier key = default; + key.hMethod = CastHandle(hMethod); + // If the input matches something already in the buffer, just re-use that slot.. easier than searching for a soft + // key on rep. + if (modifier != null) + key.modifier = + (uint)CheckMethodModifier.AddBuffer(Bytes(modifier, strlen(modifier) + 1)); + else + key.modifier = uint.MaxValue; + + key.fOptional = (fOptional ? 1u : 0u); + + uint value = result ? 1u : 0u; + CheckMethodModifier.Add(key, value); + } + + public void recGetArrayRank(CORINFO_CLASS_STRUCT_* cls, uint result) + { + GetArrayRank ??= new(); + + ulong key = CastHandle(cls); + uint value = (uint)result; + GetArrayRank.Add(key, value); + } + + public void recGetArrayIntrinsicID(CORINFO_METHOD_STRUCT_* hMethod, CorInfoArrayIntrinsic result) + { + GetArrayIntrinsicID ??= new(); + + ulong key = CastHandle(hMethod); + uint value = (uint)result; + GetArrayIntrinsicID.Add(key, value); + } + + public void recIsFieldStatic(CORINFO_FIELD_STRUCT_* fhld, bool result) + { + IsFieldStatic ??= new(); + + ulong key = CastHandle(fhld); + uint value = result ? 1u : 0u; + IsFieldStatic.Add(key, value); + } + + public void recGetArrayOrStringLength(CORINFO_OBJECT_STRUCT_* objHandle, int result) + { + GetArrayOrStringLength ??= new(); + + ulong key = CastHandle(objHandle); + uint value = (uint)result; + GetArrayOrStringLength.Add(key, value); + } + + public void recGetIntConfigValue(byte* name, int defaultValue, int result) + { + GetIntConfigValue ??= new(); + + ErrorHandling.AssertCodeMsg(name != null, ExceptionCodes.MC, "name != null", "Name can not be null"); + + Agnostic_ConfigIntInfo key = default; + + uint index = + (uint)GetIntConfigValue.AddBuffer(Bytes(name, strlen(name) + 1)); + + key.nameIndex = index; + key.defaultValue = (uint)defaultValue; + + GetIntConfigValue.Add(key, (uint)result); + } + + public void recGetStringConfigValue(byte* name, byte* result) + { + GetStringConfigValue ??= new(); + + ErrorHandling.AssertCodeMsg(name != null, ExceptionCodes.MC, "name != null", "Name can not be null"); + + uint nameIndex = (uint)GetStringConfigValue.AddBuffer(Bytes(name, strlen(name) + 1)); + + uint resultIndex = uint.MaxValue; + if (result != null) + resultIndex = (uint)GetStringConfigValue.AddBuffer(Bytes(result, strlen(result) + 1)); + + GetStringConfigValue.Add(nameIndex, resultIndex); + } + + public void recGetSpecialCopyHelper(CORINFO_CLASS_STRUCT_* type, CORINFO_METHOD_STRUCT_* helper) + { + GetSpecialCopyHelper ??= new(); + + ulong key; + key = CastHandle(type); + + ulong value = CastHandle(helper); + GetSpecialCopyHelper.Add(key, value); + } + + public void recGetWasmTypeSymbol(CorInfoWasmType* types, nuint typesSize, CORINFO_WASM_TYPE_SYMBOL_STRUCT_* result) + { + GetWasmTypeSymbol ??= new(); + + Agnostic_GetWasmTypeSymbol key = default; + key.types = (uint)GetWasmTypeSymbol.AddBuffer(Bytes(types, (uint)(sizeof(CorInfoWasmType) * typesSize))); + key.typesSize = (uint)typesSize; + + ulong value = CastHandle(result); + GetWasmTypeSymbol.Add(key, value); + } + + public void recCanValueClassInstancePointerEscape(CORINFO_METHOD_STRUCT_* ftn, bool result) + { + CanValueClassInstancePointerEscape ??= new(); + + ulong key = CastHandle(ftn); + uint value = result ? 1u : 0u; + CanValueClassInstancePointerEscape.Add(key, value); + } +} diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Replay.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Replay.cs new file mode 100644 index 00000000000000..adbe3151c06cb8 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Replay.cs @@ -0,0 +1,1780 @@ +// 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.Runtime.InteropServices; +using Internal.JitInterface; +using Internal.Pgo; + +using static SuperPmi.SpmiRecordsHelper; + +namespace SuperPmi; + +// The replay side of the JIT-EE interface: answers the JIT's queries from the recorded data, and throws +// an SPMI exception (ExceptionCodes.MC) for data that wasn't recorded. Some queries fabricate plausible +// answers instead (marked "Sparse"), where a guess still generates good code. +public sealed unsafe partial class MethodContext +{ + public const ulong CONTINUATION_TYPE_PSEUDO_CLASS_HANDLE = 0x12345678beef0000; + + private PinnedArena tempAllocations; + + private void* AllocJitTempBuffer(nuint size) => (tempAllocations ??= new PinnedArena()).Allocate(size); + + public void Reset() + { + cr = new CompileResult(); + tempAllocations = null; + } + + // 'keyFormat' describes the key for the failure message, printf-style. + private static TItem LookupByKeyOrMiss(LightWeightMap map, TKey key, string keyFormat = "", + ulong a = 0, ulong b = 0, ulong c = 0, ulong d = 0, + [CallerArgumentExpression(nameof(map))] string mapName = "", [CallerArgumentExpression(nameof(key))] string keyName = "") + where TKey : unmanaged + where TItem : unmanaged + { + if (map == null) + ErrorHandling.LogException(ExceptionCodes.MC, $"SuperPMI assertion failed (missing map {mapName}){CFormat.Sprintf(keyFormat, a, b, c, d)}"); + + int index = map.GetIndex(key); + if (index == -1) + { + ErrorHandling.LogException(ExceptionCodes.MC, + $"SuperPMI assertion failed (missing key \"{(keyName == "0u" ? "0" : keyName)}\" in map {mapName}){CFormat.Sprintf(keyFormat, a, b, c, d)}"); + } + + return map.GetItem(index); + } + + private static TItem LookupByKeyOrMiss(DenseLightWeightMap map, uint key, + [CallerArgumentExpression(nameof(map))] string mapName = "", [CallerArgumentExpression(nameof(key))] string keyName = "") + where TItem : unmanaged + { + if (map == null) + ErrorHandling.LogException(ExceptionCodes.MC, $"SuperPMI assertion failed (missing map {mapName})"); + + int index = map.GetIndex(key); + if (index == -1) + ErrorHandling.LogException(ExceptionCodes.MC, $"SuperPMI assertion failed (missing key \"{(keyName == "0u" ? "0" : keyName)}\" in map {mapName})"); + + return map.GetItem(index); + } + + private static TItem LookupByHandle(LightWeightMap map, void* handle, [CallerArgumentExpression(nameof(map))] string mapName = "") + where TItem : unmanaged + { + ulong key = CastHandle(handle); + return LookupByKeyOrMiss(map, key, ": key %016llX", key, mapName: mapName); + } + + private static void AssertMapExists(LightWeightMapBuffer map, string keyFormat = "", ulong a = 0, ulong b = 0, + [CallerArgumentExpression(nameof(map))] string mapName = "") + { + if (map == null) + ErrorHandling.LogException(ExceptionCodes.MC, $"SuperPMI assertion failed (missing map {mapName}){CFormat.Sprintf(keyFormat, a, b)}"); + } + + private static ReadOnlySpan Bytes(void* data, nuint length) => data == null ? default : new ReadOnlySpan(data, (int)length); + + // A null-terminated string, including the terminator. + private static ReadOnlySpan CString(byte* s) => new(s, MemoryMarshal.CreateReadOnlySpanFromNullTerminated(s).Length + 1); + + private void Restore_CORINFO_METHOD_INFO(CORINFO_METHOD_INFO* info, in Agnostic_CORINFO_METHOD_INFO value, LightWeightMapBuffer buffers) + { + info->ftn = (CORINFO_METHOD_STRUCT_*)value.ftn; + info->scope = (CORINFO_MODULE_STRUCT_*)value.scope; + info->ILCode = buffers.GetBufferPointer(value.ILCode_offset); + info->ILCodeSize = value.ILCodeSize; + info->maxStack = value.maxStack; + info->EHcount = value.EHcount; + info->options = (CorInfoOptions)value.options; + info->regionKind = (CorInfoRegionKind)value.regionKind; + info->args = Restore_CORINFO_SIG_INFO(value.args, buffers, SigInstHandleMap, cr.MemoryTracker); + info->locals = Restore_CORINFO_SIG_INFO(value.locals, buffers, SigInstHandleMap, cr.MemoryTracker); + } + + private static void Restore_CORINFO_GENERICHANDLE_RESULT(CORINFO_GENERICHANDLE_RESULT* pResult, in Agnostic_CORINFO_GENERICHANDLE_RESULT value) + { + pResult->lookup = RestoreCORINFO_LOOKUP(value.lookup); + pResult->compileTimeHandle = (CORINFO_GENERIC_STRUCT_*)value.compileTimeHandle; + pResult->handleType = (CorInfoGenericHandleType)value.handleType; + } + + private static CORINFO_RESOLVED_TOKEN TokenWithInValues(in Agnostic_CORINFO_RESOLVED_TOKENin inValue) => new() + { + tokenContext = (CORINFO_CONTEXT_STRUCT*)inValue.tokenContext, + tokenScope = (CORINFO_MODULE_STRUCT_*)inValue.tokenScope, + token = (mdToken)inValue.token, + tokenType = (CorInfoTokenKind)inValue.tokenType, + }; + + public void repCompileMethod(CORINFO_METHOD_INFO* info, uint* flags, CORINFO_OS* os) + { + // The only item in this map is the single group of inputs to compileMethod. + Agnostic_CompileMethod value = LookupByKeyOrMiss(CompileMethod, 0u); + Restore_CORINFO_METHOD_INFO(info, value.info, CompileMethod); + methodSize = info->ILCodeSize; + *flags = value.flags; + *os = (CORINFO_OS)value.os; + } + + public CORINFO_CLASS_STRUCT_* repGetMethodClass(CORINFO_METHOD_STRUCT_* methodHandle) => (CORINFO_CLASS_STRUCT_*)LookupByHandle(GetMethodClass, methodHandle); + + public uint repGetClassAttribs(CORINFO_CLASS_STRUCT_* classHandle) => LookupByHandle(GetClassAttribs, classHandle); + + public bool repIsIntrinsic(CORINFO_METHOD_STRUCT_* ftn) => LookupByHandle(IsIntrinsic, ftn) != 0; + + public bool repNotifyMethodInfoUsage(CORINFO_METHOD_STRUCT_* ftn) => LookupByHandle(NotifyMethodInfoUsage, ftn) != 0; + + public bool repNotifyInstructionSetUsage(InstructionSet isa, bool supported, bool preserveNegativeDependency) + { + var key = new DD { A = (uint)isa, B = (supported ? 1u : 0u) | (preserveNegativeDependency ? 2u : 0u) }; + int index = NotifyInstructionSetUsage?.GetIndex(key) ?? -1; + + // Fall back to the most likely answer instead of a miss, since ISA usage changes are quite + // common with JIT changes. + return index == -1 ? supported : NotifyInstructionSetUsage.GetItem(index) != 0; + } + + public uint repGetMethodAttribs(CORINFO_METHOD_STRUCT_* methodHandle) + { + uint value = LookupByHandle(GetMethodAttribs, methodHandle); + if ((cr.repSetMethodAttribs(methodHandle) & CorInfoMethodRuntimeFlags.CORINFO_FLG_BAD_INLINEE) != 0) + value |= (uint)CorInfoFlag.CORINFO_FLG_DONT_INLINE; + return value; + } + + public byte* repGetClassAssemblyName(CORINFO_CLASS_STRUCT_* cls) => GetClassAssemblyName.GetBufferPointer(LookupByHandle(GetClassAssemblyName, cls)); + + public void repGetVars(CORINFO_METHOD_STRUCT_* ftn, uint* cVars, ILVarInfo** vars_in, bool* extendOthers) + { + if (GetVars == null) + { + *cVars = 0; + return; + } + + Agnostic_GetVars value = GetVars.Get(CastHandle(ftn)); + *cVars = value.cVars; + if (*cVars > 0) + *vars_in = (ILVarInfo*)GetVars.GetBufferPointer(value.vars_offset); + *extendOthers = value.extendOthers != 0; + } + + public void repGetBoundaries(CORINFO_METHOD_STRUCT_* ftn, uint* cILOffsets, uint** pILOffsets, BoundaryTypes* implicitBoundaries) + { + Agnostic_GetBoundaries value = LookupByHandle(GetBoundaries, ftn); + *cILOffsets = value.cILOffsets; + if (*cILOffsets > 0) + *pILOffsets = (uint*)GetBoundaries.GetBufferPointer(value.pILOffset_offset); + *implicitBoundaries = (BoundaryTypes)value.implicitBoundaries; + } + + public CorInfoInitClassResult repInitClass(CORINFO_FIELD_STRUCT_* field, CORINFO_METHOD_STRUCT_* method, CORINFO_CONTEXT_STRUCT* context) + { + var key = new Agnostic_InitClass { field = CastHandle(field), method = CastHandle(method), context = CastHandle(context) }; + return (CorInfoInitClassResult)LookupByKeyOrMiss(InitClass, key, ": fld-%016llX meth-%016llX con-%016llX", key.field, key.method, key.context); + } + + public byte* repGetMethodNameFromMetadata(CORINFO_METHOD_STRUCT_* ftn, byte** moduleName, byte** namespaceName, byte** enclosingClassNames, + nuint maxEnclosingClassNames) + { + var key = new Agnostic_CORINFO_METHODNAME_TOKENin + { + ftn = CastHandle(ftn), + className = moduleName != null ? 1u : 0u, + namespaceName = namespaceName != null ? 1u : 0u, + maxEnclosingClassNames = (uint)maxEnclosingClassNames, + }; + + Agnostic_CORINFO_METHODNAME_TOKENout value = LookupByKeyOrMiss(GetMethodNameFromMetadata, key, + ": ftn-%016llX className-%u namespaceName-%u maxEnclosingClassNames-%u", key.ftn, key.className, key.namespaceName, key.maxEnclosingClassNames); + + byte* result = GetMethodNameFromMetadata.GetBufferPointer(value.methodName); + if (moduleName != null) + *moduleName = GetMethodNameFromMetadata.GetBufferPointer(value.className); + if (namespaceName != null) + *namespaceName = GetMethodNameFromMetadata.GetBufferPointer(value.namespaceName); + + byte* enclosingClassNameIndices = GetMethodNameFromMetadata.GetBufferPointer(value.enclosingClassNames); + for (nuint i = 0; i < maxEnclosingClassNames; i++) + enclosingClassNames[i] = GetMethodNameFromMetadata.GetBufferPointer(Unsafe.ReadUnaligned(enclosingClassNameIndices + i * sizeof(uint))); + + return result; + } + + public uint repGetJitFlags(CORJIT_FLAGS* jitFlags, uint sizeInBytes) + { + DD value = LookupByKeyOrMiss(GetJitFlags, 0u); + ErrorHandling.AssertCode(sizeInBytes >= value.B, ExceptionCodes.ASSERT, "sizeInBytes >= value.B"); + Buffer.MemoryCopy(GetJitFlags.GetBufferPointer(value.A), jitFlags, sizeInBytes, value.B); + return value.B; + } + + public CorInfoInline repCanInline(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* calleeHnd, ref uint exceptionCode) + { + var key = new DLDL { A = CastHandle(callerHnd), B = CastHandle(calleeHnd) }; + if (CanInline == null || CanInline.GetIndex(key) == -1) + { + Logger.LogDebug("Sparse - repCanInline saying INLINE_FAIL"); + return CorInfoInline.INLINE_FAIL; // if we have no info, it's pretty safe to say we can't inline it. + } + + Agnostic_CanInline value = CanInline.Get(key); + exceptionCode = value.exceptionCode; + return (CorInfoInline)value.result; + } + + public void repResolveToken(CORINFO_RESOLVED_TOKEN* pResolvedToken, out uint exceptionCode) + { + Agnostic_CORINFO_RESOLVED_TOKENin key = CreateAgnostic_CORINFO_RESOLVED_TOKENin(pResolvedToken); + ResolveTokenValue value = LookupByKeyOrMiss(ResolveToken, key, ": token %x", (uint)pResolvedToken->token); + Restore_CORINFO_RESOLVED_TOKENout(pResolvedToken, value.tokenOut, ResolveToken); + exceptionCode = value.exceptionCode; + } + + public void repGetCallInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, + CORINFO_CALLINFO_FLAGS flags, CORINFO_CALL_INFO* pResult, out uint exceptionCode) + { + AssertMapExists(GetCallInfo); + + var key = new Agnostic_GetCallInfo + { + ResolvedToken = RestoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, GetCallInfo), + callerHandle = CastHandle(callerHandle), + flags = (uint)flags, + }; + if (pConstrainedResolvedToken != null) + key.ConstrainedResolvedToken = RestoreAgnostic_CORINFO_RESOLVED_TOKEN(pConstrainedResolvedToken, GetCallInfo); + + Agnostic_CORINFO_CALL_INFO value = LookupByKeyOrMiss(GetCallInfo, key, ": key %08x, %016llx", key.ResolvedToken.inValue.token, key.ResolvedToken.outValue.hClass); + + if (value.exceptionCode != 0) + { + // If there was an exception, the stored data is ignored. + *pResult = default; + } + else + { + pResult->hMethod = (CORINFO_METHOD_STRUCT_*)value.hMethod; + pResult->methodFlags = value.methodFlags; + + // getCallInfo may have been recorded earlier in this context without CORINFO_FLG_DONT_INLINE. + // If the JIT later realized the method is never inlined, it would call setMethodAttribs, but + // a later getCallInfo wouldn't update the recorded entry. Mimic the runtime by computing this + // dynamic flag here (as repGetMethodAttribs does). This doesn't handle all cases; for example, + // parallelism could still record these flags without CORINFO_FLG_DONT_INLINE. + if ((cr.repSetMethodAttribs(pResult->hMethod) & CorInfoMethodRuntimeFlags.CORINFO_FLG_BAD_INLINEE) != 0) + pResult->methodFlags |= (uint)CorInfoFlag.CORINFO_FLG_DONT_INLINE; + + pResult->classFlags = value.classFlags; + pResult->sig = Restore_CORINFO_SIG_INFO(value.sig, GetCallInfo, SigInstHandleMap, cr.MemoryTracker); + pResult->accessAllowed = (CorInfoIsAccessAllowedResult)value.accessAllowed; + pResult->callsiteCalloutHelper = RestoreCORINFO_HELPER_DESC(value.callsiteCalloutHelper); + pResult->thisTransform = (CORINFO_THIS_TRANSFORM)value.thisTransform; + pResult->kind = (CORINFO_CALL_KIND)value.kind; + pResult->nullInstanceCheck = value.nullInstanceCheck != 0; + pResult->contextHandle = (CORINFO_CONTEXT_STRUCT*)value.contextHandle; + pResult->exactContextNeedsRuntimeLookup = value.exactContextNeedsRuntimeLookup != 0; + pResult->codePointerOrStubLookup = RestoreCORINFO_LOOKUP(value.stubLookup); + + if (pResult->kind == CORINFO_CALL_KIND.CORINFO_VIRTUALCALL_STUB) + cr.CallTargetTypes.Add(CastHandle(pResult->codePointerOrStubLookup.constLookup.addr), (uint)CORINFO_CALL_KIND.CORINFO_VIRTUALCALL_STUB); + + pResult->instParamLookup = RestoreCORINFO_CONST_LOOKUP(value.instParamLookup); + } + + exceptionCode = value.exceptionCode; + } + + public void repGetCallInfoFromMethodHandle(CORINFO_METHOD_STRUCT_* methodHandle, CORINFO_CALL_INFO* pResult) + { + if (GetCallInfo != null) + { + for (int i = 0; i < GetCallInfo.GetCount(); i++) + { + Agnostic_GetCallInfo key = GetCallInfo.GetKey(i); + if ((CORINFO_METHOD_STRUCT_*)GetCallInfo.GetItem(i).hMethod != methodHandle) + continue; + + CORINFO_RESOLVED_TOKEN resolvedToken = TokenWithInValues(key.ResolvedToken.inValue); + repResolveToken(&resolvedToken, out _); + + // If the original call passed a null constrainedResolvedToken, it can only be replayed with + // a null one too, not with the address of a local (but meaningless) token. + CORINFO_RESOLVED_TOKEN constrainedResolvedToken; + CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken = null; + if (key.ConstrainedResolvedToken.inValue.tokenContext != 0 && key.ConstrainedResolvedToken.inValue.tokenScope != 0) + { + constrainedResolvedToken = TokenWithInValues(key.ConstrainedResolvedToken.inValue); + pConstrainedResolvedToken = &constrainedResolvedToken; + repResolveToken(pConstrainedResolvedToken, out _); + } + + repGetCallInfo(&resolvedToken, pConstrainedResolvedToken, (CORINFO_METHOD_STRUCT_*)key.callerHandle, + (CORINFO_CALLINFO_FLAGS)key.flags, pResult, out _); + return; + } + } + + ErrorHandling.LogException(ExceptionCodes.MC, CFormat.Sprintf("Didn't find key %016llX.", CastHandle(methodHandle))); + } + + public void repExpandRawHandleIntrinsic(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_GENERICHANDLE_RESULT* pResult) + { + var key = new Agnostic_ExpandRawHandleIntrinsic + { + ResolvedToken = CreateAgnostic_CORINFO_RESOLVED_TOKENin(pResolvedToken), + hCallerHandle = CastHandle(callerHandle), + }; + Agnostic_CORINFO_GENERICHANDLE_RESULT value = LookupByKeyOrMiss(ExpandRawHandleIntrinsic, key, ": key %x", (uint)pResolvedToken->token); + Restore_CORINFO_GENERICHANDLE_RESULT(pResult, value); + } + + public bool repIsIntrinsicType(CORINFO_CLASS_STRUCT_* cls) => LookupByHandle(IsIntrinsicType, cls) != 0; + + public CorInfoType repAsCorInfoType(CORINFO_CLASS_STRUCT_* cls) => (CorInfoType)LookupByHandle(AsCorInfoType, cls); + + public bool repIsValueClass(CORINFO_CLASS_STRUCT_* cls) => LookupByHandle(IsValueClass, cls) != 0; + + public bool repIsByRefLike(CORINFO_CLASS_STRUCT_* cls) => LookupByHandle(IsByRefLike, cls) != 0; + + public bool repIsSharedInst(CORINFO_CLASS_STRUCT_* cls) => LookupByHandle(IsSharedInst, cls) != 0; + + public uint repGetClassSize(CORINFO_CLASS_STRUCT_* cls) => LookupByHandle(GetClassSize, cls); + + public uint repGetHeapClassSize(CORINFO_CLASS_STRUCT_* cls) => LookupByHandle(GetHeapClassSize, cls); + + public bool repCanAllocateOnStack(CORINFO_CLASS_STRUCT_* cls) => LookupByHandle(CanAllocateOnStack, cls) != 0; + + public uint repGetClassNumInstanceFields(CORINFO_CLASS_STRUCT_* cls) => LookupByHandle(GetClassNumInstanceFields, cls); + + public CorInfoHelpFunc repGetNewArrHelper(CORINFO_CLASS_STRUCT_* arrayCls) => (CorInfoHelpFunc)LookupByHandle(GetNewArrHelper, arrayCls); + + public CorInfoHelpFunc repGetSharedCCtorHelper(CORINFO_CLASS_STRUCT_* clsHnd) => (CorInfoHelpFunc)LookupByHandle(GetSharedCCtorHelper, clsHnd); + + public CORINFO_CLASS_STRUCT_* repGetTypeForBox(CORINFO_CLASS_STRUCT_* cls) => (CORINFO_CLASS_STRUCT_*)LookupByHandle(GetTypeForBox, cls); + + public CorInfoHelpFunc repGetBoxHelper(CORINFO_CLASS_STRUCT_* cls) => (CorInfoHelpFunc)LookupByHandle(GetBoxHelper, cls); + + public CORINFO_CLASS_STRUCT_* repGetBuiltinClass(CorInfoClassId classId) + { + uint key = (uint)classId; + return (CORINFO_CLASS_STRUCT_*)LookupByKeyOrMiss(GetBuiltinClass, key, ": key %08X", key); + } + + public CorInfoType repGetTypeForPrimitiveValueClass(CORINFO_CLASS_STRUCT_* cls) => (CorInfoType)LookupByHandle(GetTypeForPrimitiveValueClass, cls); + + public CorInfoType repGetTypeForPrimitiveNumericClass(CORINFO_CLASS_STRUCT_* cls) => (CorInfoType)LookupByHandle(GetTypeForPrimitiveNumericClass, cls); + + public CORINFO_CLASS_STRUCT_* repGetParentType(CORINFO_CLASS_STRUCT_* cls) => (CORINFO_CLASS_STRUCT_*)LookupByHandle(GetParentType, cls); + + public bool repIsSDArray(CORINFO_CLASS_STRUCT_* cls) => LookupByHandle(IsSDArray, cls) != 0; + + public CORINFO_CLASS_STRUCT_* repGetFieldClass(CORINFO_FIELD_STRUCT_* field) => (CORINFO_CLASS_STRUCT_*)LookupByHandle(GetFieldClass, field); + + public uint repGetFieldOffset(CORINFO_FIELD_STRUCT_* field) => LookupByHandle(GetFieldOffset, field); + + public CorInfoHelpFunc repGetUnBoxHelper(CORINFO_CLASS_STRUCT_* cls) => (CorInfoHelpFunc)LookupByHandle(GetUnBoxHelper, cls); + + public CORINFO_OBJECT_STRUCT_* repGetRuntimeTypePointer(CORINFO_CLASS_STRUCT_* cls) => (CORINFO_OBJECT_STRUCT_*)LookupByHandle(GetRuntimeTypePointer, cls); + + public bool repIsObjectImmutable(CORINFO_OBJECT_STRUCT_* objPtr) => LookupByHandle(IsObjectImmutable, objPtr) != 0; + + public bool repGetStringChar(CORINFO_OBJECT_STRUCT_* strObj, int index, ushort* charValue) + { + var key = new DLD { A = CastHandle(strObj), B = (uint)index }; + DD value = LookupByKeyOrMiss(GetStringChar, key, ": key %016llX", key.A); + *charValue = (ushort)value.B; + return value.A != 0; + } + + public CORINFO_CLASS_STRUCT_* repGetObjectType(CORINFO_OBJECT_STRUCT_* objPtr) => (CORINFO_CLASS_STRUCT_*)LookupByHandle(GetObjectType, objPtr); + + public bool repGetReadyToRunHelper(CORINFO_RESOLVED_TOKEN* pResolvedToken, CorInfoHelpFunc id, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_CONST_LOOKUP* pLookup) + { + AssertMapExists(GetReadyToRunHelper); + + var key = new GetReadyToRunHelper_TOKENin + { + ResolvedToken = RestoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, GetReadyToRunHelper), + id = (uint)id, + callerHandle = CastHandle(callerHandle), + }; + GetReadyToRunHelper_TOKENout value = LookupByKeyOrMiss(GetReadyToRunHelper, key); + *pLookup = RestoreCORINFO_CONST_LOOKUP(value.Lookup); + return value.result != 0; + } + + public void repGetReadyToRunDelegateCtorHelper(CORINFO_RESOLVED_TOKEN* pTargetMethod, mdToken targetConstraint, CORINFO_CLASS_STRUCT_* delegateType, + CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_LOOKUP* pLookup) + { + AssertMapExists(GetReadyToRunDelegateCtorHelper); + + var key = new GetReadyToRunDelegateCtorHelper_TOKENIn + { + TargetMethod = RestoreAgnostic_CORINFO_RESOLVED_TOKEN(pTargetMethod, GetReadyToRunDelegateCtorHelper), + targetConstraint = (uint)targetConstraint, + delegateType = CastHandle(delegateType), + callerHandle = CastHandle(callerHandle), + }; + *pLookup = RestoreCORINFO_LOOKUP(LookupByKeyOrMiss(GetReadyToRunDelegateCtorHelper, key)); + } + + public void repGetHelperFtn(CorInfoHelpFunc ftnNum, CORINFO_CONST_LOOKUP* pNativeEntrypoint, CORINFO_METHOD_STRUCT_** pMethodHandle) + { + uint key = (uint)ftnNum; + Agnostic_GetHelperFtn value = LookupByKeyOrMiss(GetHelperFtn, key, ": key %u", key); + if (pNativeEntrypoint != null) + *pNativeEntrypoint = RestoreCORINFO_CONST_LOOKUP(value.helperLookup); + if (pMethodHandle != null) + *pMethodHandle = (CORINFO_METHOD_STRUCT_*)value.helperMethod; + } + + public bool fndGetHelperFtn(void* functionAddress, out CorInfoHelpFunc result) + { + if (GetHelperFtn != null) + { + for (int i = 0; i < GetHelperFtn.GetCount(); i++) + { + // TODO-Cleanup: this only compares the function addresses, and doesn't account for + // ppIndirection, which will break if the helper is a dynamic helper function. + if (GetHelperFtn.GetItem(i).helperLookup.handle == CastHandle(functionAddress)) + { + result = (CorInfoHelpFunc)GetHelperFtn.GetKey(i); + return true; + } + } + } + + Logger.LogDebug($"fndGetHelperFtn - didn't find value 0x{CastHandle(functionAddress):x}"); + result = default; + return false; + } + + public CORINFO_JUST_MY_CODE_HANDLE_* repGetJustMyCodeHandle(CORINFO_METHOD_STRUCT_* method, CORINFO_JUST_MY_CODE_HANDLE_** ppIndirection) + { + DLDL value = LookupByHandle(GetJustMyCodeHandle, method); + *ppIndirection = (CORINFO_JUST_MY_CODE_HANDLE_*)value.A; + return (CORINFO_JUST_MY_CODE_HANDLE_*)value.B; + } + + public void repGetFunctionEntryPoint(CORINFO_METHOD_STRUCT_* ftn, CORINFO_CONST_LOOKUP* pResult, CORINFO_ACCESS_FLAGS accessFlags) + { + var key = new DLD { A = CastHandle(ftn), B = (uint)accessFlags }; + + if (GetFunctionEntryPoint == null || GetFunctionEntryPoint.GetIndex(key) == -1) + { + key.B ^= (uint)CORINFO_ACCESS_FLAGS.CORINFO_ACCESS_NONNULL; + if (GetFunctionEntryPoint != null && GetFunctionEntryPoint.GetIndex(key) != -1) + { + Logger.LogDebug("Sparse - repGetFunctionEntryPoint found result with inverted CORINFO_ACCESS_NONNULL"); + } + else + { + Logger.LogDebug("Sparse - repGetFunctionEntryPoint fabricated result for request."); + pResult->accessType = InfoAccessType.IAT_PVALUE; + pResult->addr = (void*)(CastHandle(ftn) + 0x1c); + return; + } + } + + DLD value = GetFunctionEntryPoint.Get(key); + pResult->accessType = (InfoAccessType)value.B; + pResult->addr = (void*)value.A; + } + + public bool fndGetFunctionEntryPoint(DLD value, out CORINFO_METHOD_STRUCT_* result) + { + if (GetFunctionEntryPoint != null) + { + for (int i = 0; i < GetFunctionEntryPoint.GetCount(); i++) + { + // TODO-Cleanup: we should be more conscious of the rest of the information in CORINFO_CONST_LOOKUP + if ((uint)GetFunctionEntryPoint.GetItem(i).A == (uint)value.A) + { + result = (CORINFO_METHOD_STRUCT_*)GetFunctionEntryPoint.GetKey(i).A; + return true; + } + } + } + + Logger.LogDebug($"fndGetFunctionEntryPoint - didn't find value {value.A:X16}"); + result = null; + return false; + } + + public InfoAccessType repConstructStringLiteral(CORINFO_MODULE_STRUCT_* moduleHandle, mdToken metaTok, void** ppValue) + { + var key = new DLD { A = CastHandle(moduleHandle), B = (uint)metaTok }; + DLD value = LookupByKeyOrMiss(ConstructStringLiteral, key, ": key %016llX", CastHandle(moduleHandle)); + *ppValue = (void*)value.A; + return (InfoAccessType)value.B; + } + + public bool repConvertPInvokeCalliToCall(CORINFO_RESOLVED_TOKEN* pResolvedToken, bool fMustConvert) + { + AssertMapExists(ConvertPInvokeCalliToCall); + + var key = new DLD { A = CastHandle(pResolvedToken->tokenScope), B = (uint)pResolvedToken->token }; + DLDL value = LookupByKeyOrMiss(ConvertPInvokeCalliToCall, key); + pResolvedToken->hClass = (CORINFO_CLASS_STRUCT_*)value.A; + pResolvedToken->hMethod = (CORINFO_METHOD_STRUCT_*)value.B; + return value.B != 0; + } + + public InfoAccessType repEmptyStringLiteral(void** ppValue) + { + // TODO-Cleanup: sketchy if someone calls this twice + DLD temp2 = LookupByKeyOrMiss(EmptyStringLiteral, 0u); + *ppValue = (void*)temp2.A; + return (InfoAccessType)temp2.B; + } + + public CorInfoTypeWithMod repGetArgType(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_STRUCT_* args, CORINFO_CLASS_STRUCT_** vcTypeRet, out uint exceptionCode) + { + AssertMapExists(GetArgType, ": key %016llX %016llX", CastHandle(sig->scope), CastHandle(args)); + + var key = new Agnostic_GetArgType_Key + { + flags = (uint)sig->flags, + numArgs = sig->numArgs, + sigInst_classInstCount = sig->sigInst.classInstCount, + sigInst_methInstCount = sig->sigInst.methInstCount, + methodSignature = CastHandle(sig->methodSignature), + scope = CastHandle(sig->scope), + args = CastHandle(args), + sigInst_classInst_Index = ContainsHandleMap(sig->sigInst.classInstCount, sig->sigInst.classInst, SigInstHandleMap), + sigInst_methInst_Index = ContainsHandleMap(sig->sigInst.methInstCount, sig->sigInst.methInst, SigInstHandleMap), + }; + + Agnostic_GetArgType_Value value = LookupByKeyOrMiss(GetArgType, key, ": key %016llX %016llX", key.scope, key.args); + *vcTypeRet = (CORINFO_CLASS_STRUCT_*)value.vcTypeRet; + exceptionCode = value.exceptionCode; + return (CorInfoTypeWithMod)value.result; + } + + public int repGetExactClasses(CORINFO_CLASS_STRUCT_* baseType, int maxExactClasses, CORINFO_CLASS_STRUCT_** exactClsRet) + { + var key = new DLD { A = CastHandle(baseType), B = (uint)maxExactClasses }; + Agnostic_GetExactClassesResult value = LookupByKeyOrMiss(GetExactClasses, key, ": key %016llX %08X", key.A, key.B); + ErrorHandling.AssertCode(maxExactClasses >= value.numClasses, ExceptionCodes.ASSERT, "maxExactClasses >= value.numClasses"); + + byte* buffer = GetExactClasses.GetBufferPointer(value.classes); + for (int i = 0; i < value.numClasses; i++) + exactClsRet[i] = (CORINFO_CLASS_STRUCT_*)Unsafe.ReadUnaligned(buffer + i * sizeof(ulong)); + return value.numClasses; + } + + public CORINFO_ARG_LIST_STRUCT_* repGetArgNext(CORINFO_ARG_LIST_STRUCT_* args) => (CORINFO_ARG_LIST_STRUCT_*)LookupByHandle(GetArgNext, args); + + public void repGetMethodSig(CORINFO_METHOD_STRUCT_* ftn, CORINFO_SIG_INFO* sig, CORINFO_CLASS_STRUCT_* memberParent) + { + var key = new DLDL { A = CastHandle(ftn), B = CastHandle(memberParent) }; + Agnostic_CORINFO_SIG_INFO value = LookupByKeyOrMiss(GetMethodSig, key, ": key ftn-%016llX prt-%016llX", key.A, key.B); + *sig = Restore_CORINFO_SIG_INFO(value, GetMethodSig, SigInstHandleMap, cr.MemoryTracker); + } + + public CORINFO_CLASS_STRUCT_* repGetArgClass(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_STRUCT_* args, out uint exceptionCode) + { + var key = new Agnostic_GetArgClass_Key + { + sigInst_classInstCount = sig->sigInst.classInstCount, + sigInst_methInstCount = sig->sigInst.methInstCount, + methodSignature = CastHandle(sig->methodSignature), + scope = CastHandle(sig->scope), + args = CastHandle(args), + sigInst_classInst_Index = ContainsHandleMap(sig->sigInst.classInstCount, sig->sigInst.classInst, SigInstHandleMap), + sigInst_methInst_Index = ContainsHandleMap(sig->sigInst.methInstCount, sig->sigInst.methInst, SigInstHandleMap), + }; + + Agnostic_GetArgClass_Value value = LookupByKeyOrMiss(GetArgClass, key, ": key %016llX %016llX", key.scope, key.args); + exceptionCode = value.exceptionCode; + return (CORINFO_CLASS_STRUCT_*)value.result; + } + + public CorInfoHFAElemType repGetHFAType(CORINFO_CLASS_STRUCT_* clsHnd) => (CorInfoHFAElemType)LookupByHandle(GetHFAType, clsHnd); + + public bool repGetMethodInfo(CORINFO_METHOD_STRUCT_* ftn, CORINFO_METHOD_INFO* info, CORINFO_CONTEXT_STRUCT* context, out uint exceptionCode) + { + var key = new DLDL { A = CastHandle(ftn), B = CastHandle(context) }; + Agnostic_GetMethodInfo value = LookupByKeyOrMiss(GetMethodInfo, key, ": key %016llX", key.A); + if (value.result != 0) + Restore_CORINFO_METHOD_INFO(info, value.info, GetMethodInfo); + exceptionCode = value.exceptionCode; + return value.result != 0; + } + + public bool repHaveSameMethodDefinition(CORINFO_METHOD_STRUCT_* methHnd1, CORINFO_METHOD_STRUCT_* methHnd2) + { + var key = new DLDL { A = CastHandle(methHnd1), B = CastHandle(methHnd2) }; + return LookupByKeyOrMiss(HaveSameMethodDefinition, key, "key %016llX, %016llX", key.A, key.B) != 0; + } + + public CORINFO_CLASS_STRUCT_* repGetTypeDefinition(CORINFO_CLASS_STRUCT_* cls) => (CORINFO_CLASS_STRUCT_*)LookupByHandle(GetTypeDefinition, cls); + + public CorInfoHelpFunc repGetNewHelper(CORINFO_CLASS_STRUCT_* classHandle, bool* pHasSideEffects, out uint exceptionCode) + { + DDD value = LookupByHandle(GetNewHelper, classHandle); + if (pHasSideEffects != null) + *pHasSideEffects = value.A != 0; + exceptionCode = value.C; + return (CorInfoHelpFunc)value.B; + } + + public void repEmbedGenericHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken, bool fEmbedParent, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_GENERICHANDLE_RESULT* pResult) + { + AssertMapExists(EmbedGenericHandle); + + var key = new Agnostic_EmbedGenericHandle + { + ResolvedToken = RestoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, EmbedGenericHandle), + fEmbedParent = fEmbedParent ? 1u : 0u, + hCallerHandle = CastHandle(callerHandle), + }; + Restore_CORINFO_GENERICHANDLE_RESULT(pResult, LookupByKeyOrMiss(EmbedGenericHandle, key)); + } + + public void repGetEHinfo(CORINFO_METHOD_STRUCT_* ftn, uint EHnumber, CORINFO_EH_CLAUSE* clause) + { + AssertMapExists(GetEHinfo, ": key %016llX", CastHandle(ftn)); + + var key = new DLD { A = CastHandle(ftn), B = EHnumber }; + Agnostic_CORINFO_EH_CLAUSE value = LookupByKeyOrMiss(GetEHinfo, key, ": key %016llX", CastHandle(ftn)); + clause->Flags = (CORINFO_EH_CLAUSE_FLAGS)value.Flags; + clause->TryOffset = value.TryOffset; + clause->TryLength = value.TryLength; + clause->HandlerOffset = value.HandlerOffset; + clause->HandlerLength = value.HandlerLength; + clause->ClassTokenOrOffset = value.ClassToken; + } + + public void repGetMethodVTableOffset(CORINFO_METHOD_STRUCT_* method, uint* offsetOfIndirection, uint* offsetAfterIndirection, bool* isRelative) + { + DDD value = LookupByHandle(GetMethodVTableOffset, method); + *offsetOfIndirection = value.A; + *offsetAfterIndirection = value.B; + *isRelative = value.C != 0; + } + + public bool repResolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) + { + var key = new Agnostic_ResolveVirtualMethodKey + { + virtualMethod = CastHandle(info->virtualMethod), + objClass = CastHandle(info->objClass), + context = CastHandle(info->context), + pResolvedTokenVirtualMethodNonNull = info->pResolvedTokenVirtualMethod != null ? 1u : 0u, + }; + if (key.pResolvedTokenVirtualMethodNonNull != 0) + key.pResolvedTokenVirtualMethod = StoreAgnostic_CORINFO_RESOLVED_TOKEN(info->pResolvedTokenVirtualMethod, ResolveToken); + + Agnostic_ResolveVirtualMethodResult result = LookupByKeyOrMiss(ResolveVirtualMethod, key, ": %016llX-%016llX-%016llX-%08X", + key.virtualMethod, key.objClass, key.context, key.pResolvedTokenVirtualMethodNonNull); + + info->devirtualizedMethod = (CORINFO_METHOD_STRUCT_*)result.devirtualizedMethod; + info->tokenLookupContext = (CORINFO_CONTEXT_STRUCT*)result.tokenLookupContext; + info->detail = (CORINFO_DEVIRTUALIZATION_DETAIL)result.detail; + info->instParamLookup = RestoreCORINFO_LOOKUP(result.instParamLookup); + if (result.returnValue != 0) + { + info->resolvedTokenDevirtualizedMethod = Restore_CORINFO_RESOLVED_TOKEN(result.resolvedTokenDevirtualizedMethod, ResolveToken); + info->resolvedTokenDevirtualizedUnboxedMethod = Restore_CORINFO_RESOLVED_TOKEN(result.resolvedTokenDevirtualizedUnboxedMethod, ResolveToken); + } + return result.returnValue != 0; + } + + public CORINFO_METHOD_STRUCT_* repGetAsyncOtherVariant(CORINFO_METHOD_STRUCT_* ftn, bool* variantIsThunk) + { + DLD value = LookupByHandle(GetAsyncOtherVariant, ftn); + *variantIsThunk = value.B != 0; + return (CORINFO_METHOD_STRUCT_*)value.A; + } + + public CORINFO_CLASS_STRUCT_* repGetDefaultComparerClass(CORINFO_CLASS_STRUCT_* cls) => (CORINFO_CLASS_STRUCT_*)LookupByHandle(GetDefaultComparerClass, cls); + + public CORINFO_CLASS_STRUCT_* repGetDefaultEqualityComparerClass(CORINFO_CLASS_STRUCT_* cls) => (CORINFO_CLASS_STRUCT_*)LookupByHandle(GetDefaultEqualityComparerClass, cls); + + public CORINFO_CLASS_STRUCT_* repGetSZArrayHelperEnumeratorClass(CORINFO_CLASS_STRUCT_* cls) => (CORINFO_CLASS_STRUCT_*)LookupByHandle(GetSZArrayHelperEnumeratorClass, cls); + + public CORINFO_CLASS_STRUCT_* repGetTokenTypeAsHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken) + { + var key = new GetTokenTypeAsHandleValue { hMethod = CastHandle(pResolvedToken->hMethod), hField = CastHandle(pResolvedToken->hField) }; + return (CORINFO_CLASS_STRUCT_*)LookupByKeyOrMiss(GetTokenTypeAsHandle, key); + } + + public void repGetFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult) + { + AssertMapExists(GetFieldInfo, ": key %x", (uint)pResolvedToken->token); + + var key = new Agnostic_GetFieldInfo + { + ResolvedToken = RestoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, GetFieldInfo), + callerHandle = CastHandle(callerHandle), + flags = (uint)flags, + }; + + uint origFlag = key.flags; + int keyIndex = GetFieldInfo.GetIndex(key); + if (keyIndex == -1) + { + key.flags = origFlag ^ (uint)CORINFO_ACCESS_FLAGS.CORINFO_ACCESS_THIS; + keyIndex = GetFieldInfo.GetIndex(key); + if (keyIndex != -1) + { + Logger.LogDebug("Sparse - repGetFieldInfo found value with inverted CORINFO_ACCESS_THIS"); + } + else + { + key.flags = origFlag ^ (uint)CORINFO_ACCESS_FLAGS.CORINFO_ACCESS_INLINECHECK; + keyIndex = GetFieldInfo.GetIndex(key); + if (keyIndex != -1) + Logger.LogDebug("Sparse - repGetFieldInfo found value with inverted CORINFO_ACCESS_INLINECHECK"); + else + ErrorHandling.LogException(ExceptionCodes.MC, CFormat.Sprintf("repGetFieldInfo: didn't find %x", (uint)pResolvedToken->token)); + } + } + + Agnostic_CORINFO_FIELD_INFO value = GetFieldInfo.GetItem(keyIndex); + pResult->fieldAccessor = (CORINFO_FIELD_ACCESSOR)value.fieldAccessor; + pResult->fieldFlags = (CORINFO_FIELD_FLAGS)value.fieldFlags; + pResult->helper = (CorInfoHelpFunc)value.helper; + pResult->offset = value.offset; + pResult->fieldType = (CorInfoType)value.fieldType; + pResult->structType = (CORINFO_CLASS_STRUCT_*)value.structType; + pResult->accessAllowed = (CorInfoIsAccessAllowedResult)value.accessAllowed; + pResult->accessCalloutHelper = RestoreCORINFO_HELPER_DESC(value.accessCalloutHelper); + pResult->fieldLookup = RestoreCORINFO_CONST_LOOKUP(value.fieldLookup); + } + + public uint repGetThreadLocalFieldInfo(CORINFO_FIELD_STRUCT_* field, bool isGCType) + { + var key = new DLD { A = CastHandle(field), B = isGCType ? 0u : 1u }; + return LookupByKeyOrMiss(GetThreadLocalFieldInfo, key, ": key hnd-%016llX, gctype-%u", key.A, key.B); + } + + public void repGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) + { + uint key = 0; + Agnostic_GetThreadLocalStaticBlocksInfo value = LookupByKeyOrMiss(GetThreadLocalStaticBlocksInfo, key, ": key %u", key); + pInfo->tlsIndex = RestoreCORINFO_CONST_LOOKUP(value.tlsIndex); + pInfo->tlsGetAddrFtnPtr = (nuint)value.tlsGetAddrFtnPtr; + pInfo->tlsIndexObject = (nuint)value.tlsIndexObject; + pInfo->threadVarsSection = (nuint)value.threadVarsSection; + pInfo->offsetOfThreadLocalStoragePointer = value.offsetOfThreadLocalStoragePointer; + pInfo->offsetOfMaxThreadStaticBlocks = value.offsetOfMaxThreadStaticBlocks; + pInfo->offsetOfThreadStaticBlocks = value.offsetOfThreadStaticBlocks; + pInfo->offsetOfBaseOfThreadLocalData = value.offsetOfBaseOfThreadLocalData; + } + + public void repGetThreadLocalStaticInfo_NativeAOT(CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo) + { + ulong key = 1; + Agnostic_GetThreadStaticInfo_NativeAOT value = LookupByKeyOrMiss(GetThreadLocalStaticInfo_NativeAOT, key, ": key %016llX", key); + pInfo->tlsRootObject = RestoreCORINFO_CONST_LOOKUP(value.tlsRootObject); + pInfo->tlsIndexObject = RestoreCORINFO_CONST_LOOKUP(value.tlsIndexObject); + pInfo->offsetOfThreadLocalStoragePointer = value.offsetOfThreadLocalStoragePointer; + pInfo->threadStaticBaseSlow = RestoreCORINFO_CONST_LOOKUP(value.threadStaticBaseSlow); + pInfo->tlsGetAddrFtnPtr = RestoreCORINFO_CONST_LOOKUP(value.tlsGetAddrFtnPtr); + } + + public CORINFO_METHOD_STRUCT_* repEmbedMethodHandle(CORINFO_METHOD_STRUCT_* handle, void** ppIndirection) + { + DLDL value = LookupByHandle(EmbedMethodHandle, handle); + if (ppIndirection != null) + *ppIndirection = (void*)value.A; + return (CORINFO_METHOD_STRUCT_*)value.B; + } + + public bool repGetStaticFieldContent(CORINFO_FIELD_STRUCT_* field, byte* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects) + { + var key = new DLDDD { A = CastHandle(field), B = (uint)bufferSize, C = ignoreMovableObjects ? 1u : 0u, D = (uint)valueOffset }; + DD value = LookupByKeyOrMiss(GetStaticFieldContent, key, ": key %016llX", key.A); + if (buffer != null && value.A != 0) + CopyContent(GetStaticFieldContent.GetBufferPointer(value.B), buffer, bufferSize); + return value.A != 0; + } + + public bool repGetObjectContent(CORINFO_OBJECT_STRUCT_* obj, byte* buffer, int bufferSize, int valueOffset) + { + var key = new DLDD { A = CastHandle(obj), B = (uint)bufferSize, C = (uint)valueOffset }; + DD value = LookupByKeyOrMiss(GetObjectContent, key, ": key %016llX", key.A); + if (buffer != null && value.A != 0) + CopyContent(GetObjectContent.GetBufferPointer(value.B), buffer, bufferSize); + return value.A != 0; + } + + private static void CopyContent(byte* srcBuffer, byte* buffer, int bufferSize) + { + ErrorHandling.AssertCode(srcBuffer != null, ExceptionCodes.ASSERT, "srcBuffer != nullptr"); + Buffer.MemoryCopy(srcBuffer, buffer, bufferSize, bufferSize); + } + + public CORINFO_CLASS_STRUCT_* repGetStaticFieldCurrentClass(CORINFO_FIELD_STRUCT_* field, byte* pIsSpeculative) + { + var key = new DLD { A = CastHandle(field), B = pIsSpeculative != null ? 1u : 0u }; + Agnostic_GetStaticFieldCurrentClass value = LookupByKeyOrMiss(GetStaticFieldCurrentClass, key, ": key %016llX", key.A); + if (pIsSpeculative != null) + *pIsSpeculative = value.isSpeculative; + return (CORINFO_CLASS_STRUCT_*)value.classHandle; + } + + public uint repGetClassGClayout(CORINFO_CLASS_STRUCT_* cls, byte* gcPtrs) + { + Agnostic_GetClassGClayout value = LookupByHandle(GetClassGClayout, cls); + if (value.gcPtrs_Index != uint.MaxValue) + Buffer.MemoryCopy(GetClassGClayout.GetBufferPointer(value.gcPtrs_Index), gcPtrs, value.len, value.len); + return value.valCount; + } + + public uint repGetClassAlignmentRequirement(CORINFO_CLASS_STRUCT_* cls, bool fDoubleAlignHint) + { + var key = new DLD { A = CastHandle(cls), B = fDoubleAlignHint ? 1u : 0u }; + return LookupByKeyOrMiss(GetClassAlignmentRequirement, key, ": key %016llX", key.A); + } + + public CorInfoIsAccessAllowedResult repCanAccessClass(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_HELPER_DESC* pAccessHelper) + { + AssertMapExists(CanAccessClass, ": key %016llX", CastHandle(pResolvedToken->hClass)); + + var key = new Agnostic_CanAccessClassIn + { + ResolvedToken = RestoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, CanAccessClass), + callerHandle = CastHandle(callerHandle), + }; + Agnostic_CanAccessClassOut value = LookupByKeyOrMiss(CanAccessClass, key, ": key %016llX", CastHandle(pResolvedToken->hClass)); + *pAccessHelper = RestoreCORINFO_HELPER_DESC(value.AccessHelper); + return (CorInfoIsAccessAllowedResult)value.result; + } + + public CorInfoHelpFunc repGetCastingHelper(CORINFO_RESOLVED_TOKEN* pResolvedToken, bool fThrowing) + { + var key = new Agnostic_GetCastingHelper { hClass = CastHandle(pResolvedToken->hClass), fThrowing = fThrowing ? 1u : 0u }; + return (CorInfoHelpFunc)LookupByKeyOrMiss(GetCastingHelper, key, ": key %016llX", key.hClass); + } + + public CORINFO_MODULE_STRUCT_* repEmbedModuleHandle(CORINFO_MODULE_STRUCT_* handle, void** ppIndirection) + { + DLDL value = LookupByHandle(EmbedModuleHandle, handle); + if (ppIndirection != null) + *ppIndirection = (void*)value.A; + return (CORINFO_MODULE_STRUCT_*)value.B; + } + + public CORINFO_CLASS_STRUCT_* repEmbedClassHandle(CORINFO_CLASS_STRUCT_* handle, void** ppIndirection) + { + ulong key = CastHandle(handle); + if (key == CONTINUATION_TYPE_PSEUDO_CLASS_HANDLE) + { + if (EmbedClassHandle.GetCount() > 0 && EmbedClassHandle.GetItem(0).A != 0) + { + // Some other embedded handle required an indirection, so do the same for the pseudo handle + // (avoids spurious improvements in R2R scenarios). + *ppIndirection = (void*)CONTINUATION_TYPE_PSEUDO_CLASS_HANDLE; + return null; + } + + *ppIndirection = null; + return handle; + } + + DLDL value = LookupByKeyOrMiss(EmbedClassHandle, key, ": key %016llX", key); + *ppIndirection = (void*)value.A; + return (CORINFO_CLASS_STRUCT_*)value.B; + } + + public bool repPInvokeMarshalingRequired(CORINFO_METHOD_STRUCT_* method, CORINFO_SIG_INFO* callSiteSig) + { + if (PInvokeMarshalingRequired == null) // so when we replay Checked on Release, we throw from lwm + return true; // TODO-Cleanup: hackish... + + var key = new MethodOrSigInfoValue + { + method = CastHandle(method), + pSig_Index = (uint)PInvokeMarshalingRequired.Contains(Bytes(callSiteSig->pSig, callSiteSig->cbSig)), + cbSig = callSiteSig->cbSig, + scope = CastHandle(callSiteSig->scope), + }; + return LookupByKeyOrMiss(PInvokeMarshalingRequired, key) != 0; + } + + public CorInfoCallConvExtension repGetUnmanagedCallConv(CORINFO_METHOD_STRUCT_* method, CORINFO_SIG_INFO* callSiteSig, bool* pSuppressGCTransition) + { + if (GetUnmanagedCallConv == null) + { + Logger.LogDebug("Sparse - repGetUnmanagedCallConv returning CorInfoCallConvExtension::Managed"); + return CorInfoCallConvExtension.Managed; + } + + var key = new MethodOrSigInfoValue { method = CastHandle(method) }; + if (callSiteSig != null) + { + key.pSig_Index = (uint)GetUnmanagedCallConv.Contains(Bytes(callSiteSig->pSig, callSiteSig->cbSig)); + key.cbSig = callSiteSig->cbSig; + key.scope = CastHandle(callSiteSig->scope); + } + + DD value = LookupByKeyOrMiss(GetUnmanagedCallConv, key); + *pSuppressGCTransition = value.B != 0; + return (CorInfoCallConvExtension)value.A; + } + + public void repFindSig(CORINFO_MODULE_STRUCT_* moduleHandle, uint sigTOK, CORINFO_CONTEXT_STRUCT* context, CORINFO_SIG_INFO* sig) + { + var key = new Agnostic_FindSig { module = CastHandle(moduleHandle), sigTOK = sigTOK, context = CastHandle(context) }; + Agnostic_CORINFO_SIG_INFO value = LookupByKeyOrMiss(FindSig, key); + *sig = Restore_CORINFO_SIG_INFO(value, FindSig, SigInstHandleMap, cr.MemoryTracker); + } + + public void repGetEEInfo(CORINFO_EE_INFO* pEEInfoOut) + { + Agnostic_CORINFO_EE_INFO value = LookupByKeyOrMiss(GetEEInfo, 0u); + pEEInfoOut->inlinedCallFrameInfo.size = value.inlinedCallFrameInfo.size; + pEEInfoOut->inlinedCallFrameInfo.sizeWithSecretStubArg = value.inlinedCallFrameInfo.sizeWithSecretStubArg; + pEEInfoOut->inlinedCallFrameInfo.offsetOfFrameLink = value.inlinedCallFrameInfo.offsetOfFrameLink; + pEEInfoOut->inlinedCallFrameInfo.offsetOfCallSiteSP = value.inlinedCallFrameInfo.offsetOfCallSiteSP; + pEEInfoOut->inlinedCallFrameInfo.offsetOfCalleeSavedFP = value.inlinedCallFrameInfo.offsetOfCalleeSavedFP; + pEEInfoOut->inlinedCallFrameInfo.offsetOfCallTarget = value.inlinedCallFrameInfo.offsetOfCallTarget; + pEEInfoOut->inlinedCallFrameInfo.offsetOfReturnAddress = value.inlinedCallFrameInfo.offsetOfReturnAddress; + pEEInfoOut->inlinedCallFrameInfo.offsetOfSecretStubArg = value.inlinedCallFrameInfo.offsetOfSecretStubArg; + pEEInfoOut->inlinedCallFrameInfo.offsetOfSPAfterProlog = value.inlinedCallFrameInfo.offsetOfSPAfterProlog; + pEEInfoOut->offsetOfThreadFrame = value.offsetOfThreadFrame; + pEEInfoOut->offsetOfGCState = value.offsetOfGCState; + pEEInfoOut->offsetOfDelegateInstance = value.offsetOfDelegateInstance; + pEEInfoOut->offsetOfDelegateFirstTarget = value.offsetOfDelegateFirstTarget; + pEEInfoOut->sizeOfReversePInvokeFrame = value.sizeOfReversePInvokeFrame; + pEEInfoOut->osPageSize = value.osPageSize; + pEEInfoOut->maxUncheckedOffsetForNullObject = value.maxUncheckedOffsetForNullObject; + pEEInfoOut->targetAbi = (CORINFO_RUNTIME_ABI)value.targetAbi; + pEEInfoOut->osType = (CORINFO_OS)value.osType; + } + + public void repGetAsyncInfo(CORINFO_ASYNC_INFO* pAsyncInfoOut) + { + Agnostic_CORINFO_ASYNC_INFO value = LookupByKeyOrMiss(GetAsyncInfo, 0u); + pAsyncInfoOut->continuationClsHnd = (CORINFO_CLASS_STRUCT_*)value.continuationClsHnd; + pAsyncInfoOut->continuationNextFldHnd = (CORINFO_FIELD_STRUCT_*)value.continuationNextFldHnd; + pAsyncInfoOut->continuationResumeInfoFldHnd = (CORINFO_FIELD_STRUCT_*)value.continuationResumeInfoFldHnd; + pAsyncInfoOut->continuationStateFldHnd = (CORINFO_FIELD_STRUCT_*)value.continuationStateFldHnd; + pAsyncInfoOut->continuationFlagsFldHnd = (CORINFO_FIELD_STRUCT_*)value.continuationFlagsFldHnd; + pAsyncInfoOut->captureExecutionContextMethHnd = (CORINFO_METHOD_STRUCT_*)value.captureExecutionContextMethHnd; + pAsyncInfoOut->captureContinuationContextMethHnd = (CORINFO_METHOD_STRUCT_*)value.captureContinuationContextMethHnd; + pAsyncInfoOut->captureContextsMethHnd = (CORINFO_METHOD_STRUCT_*)value.captureContextsMethHnd; + pAsyncInfoOut->restoreContextsMethHnd = (CORINFO_METHOD_STRUCT_*)value.restoreContextsMethHnd; + pAsyncInfoOut->restoreContextsOnSuspensionMethHnd = (CORINFO_METHOD_STRUCT_*)value.restoreContextsOnSuspensionMethHnd; + pAsyncInfoOut->restoreInlinedFrameContextsMethHnd = (CORINFO_METHOD_STRUCT_*)value.restoreInlinedFrameContextsMethHnd; + pAsyncInfoOut->captureInlinedFrameTransitionWithContinuationContextMethHnd = (CORINFO_METHOD_STRUCT_*)value.captureInlinedFrameTransitionWithContinuationContextMethHnd; + pAsyncInfoOut->captureInlinedFrameTransitionNoContinuationContextMethHnd = (CORINFO_METHOD_STRUCT_*)value.captureInlinedFrameTransitionNoContinuationContextMethHnd; + pAsyncInfoOut->captureInlinedFrameTransitionContinueOnThreadPoolMethHnd = (CORINFO_METHOD_STRUCT_*)value.captureInlinedFrameTransitionContinueOnThreadPoolMethHnd; + pAsyncInfoOut->finishSuspensionNoContinuationContextMethHnd = (CORINFO_METHOD_STRUCT_*)value.finishSuspensionNoContinuationContextMethHnd; + pAsyncInfoOut->finishSuspensionWithContinuationContextMethHnd = (CORINFO_METHOD_STRUCT_*)value.finishSuspensionWithContinuationContextMethHnd; + } + + public void repGetWasmWellKnownGlobals(CORINFO_WASM_WELLKNOWN_GLOBALS* pWellKnownGlobalsOut) + { + Agnostic_CORINFO_WASM_WELLKNOWN_GLOBALS value = LookupByKeyOrMiss(GetWasmWellKnownGlobals, 0u); + pWellKnownGlobalsOut->stackPointer = (CORINFO_WASM_GLOBAL_SYMBOL_STRUCT_*)value.stackPointer; + pWellKnownGlobalsOut->imageBase = (CORINFO_WASM_GLOBAL_SYMBOL_STRUCT_*)value.imageBase; + pWellKnownGlobalsOut->tableBase = (CORINFO_WASM_GLOBAL_SYMBOL_STRUCT_*)value.tableBase; + pWellKnownGlobalsOut->asyncContinuation = (CORINFO_WASM_GLOBAL_SYMBOL_STRUCT_*)value.asyncContinuation; + } + + public CORINFO_METHOD_STRUCT_* repGetAwaitReturnCall(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_CONTEXT_STRUCT** contextHandle, CORINFO_LOOKUP* instArg) + { + Agnostic_GetAwaitReturnCallResult result = LookupByKeyOrMiss(GetAwaitReturnCall, CastHandle(callerHnd)); + *contextHandle = (CORINFO_CONTEXT_STRUCT*)result.contextHandle; + *instArg = RestoreCORINFO_LOOKUP(result.instArg); + return (CORINFO_METHOD_STRUCT_*)result.methodHnd; + } + + public CORINFO_METHOD_STRUCT_* repGetAwaitAwaiterInContinuationCall(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_RESOLVED_TOKEN* pResolvedToken, bool isUnsafe, + CORINFO_CONTEXT_STRUCT** contextHandle, CORINFO_LOOKUP* instArg) + { + var key = new Agnostic_GetAwaitAwaiterInContinuationCall + { + callerHnd = CastHandle(callerHnd), + ResolvedToken = RestoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, GetAwaitAwaiterInContinuationCall), + isUnsafe = isUnsafe ? 1u : 0u, + }; + Agnostic_GetAwaitReturnCallResult value = LookupByKeyOrMiss(GetAwaitAwaiterInContinuationCall, key); + *contextHandle = (CORINFO_CONTEXT_STRUCT*)value.contextHandle; + *instArg = RestoreCORINFO_LOOKUP(value.instArg); + return (CORINFO_METHOD_STRUCT_*)value.methodHnd; + } + + public void repGetGSCookie(nint* pCookieVal, nint** ppCookieVal) + { + if (GetGSCookie == null) + { + // Fake the result, since for the codegen it is just a constant. + if (pCookieVal != null) + *pCookieVal = 0x06000000; + if (ppCookieVal != null) + *ppCookieVal = (nint*)0x06000001; + return; + } + + DLDL value = LookupByKeyOrMiss(GetGSCookie, 0u); + if (pCookieVal != null) + *pCookieVal = (nint)value.A; + if (ppCookieVal != null) + *ppCookieVal = (nint*)value.B; + } + + public PatchpointInfo* repGetOSRInfo(uint* ilOffset) + { + uint key = 0; + Agnostic_GetOSRInfo value = LookupByKeyOrMiss(GetOSRInfo, key); + *ilOffset = value.ilOffset; + return (PatchpointInfo*)GetOSRInfo.GetBufferPointer(value.index); + } + + public bool repGetIsClassInitedFlagAddress(CORINFO_CLASS_STRUCT_* cls, CORINFO_CONST_LOOKUP* addr, int* offset) + { + Agnostic_GetIsClassInitedFlagAddress value = LookupByHandle(GetIsClassInitedFlagAddress, cls); + *offset = (int)value.offset; + addr->accessType = (InfoAccessType)value.addr.accessType; + addr->addr = (void*)value.addr.handle; + return value.result != 0; + } + + public bool repGetStaticBaseAddress(CORINFO_CLASS_STRUCT_* cls, bool isGc, CORINFO_CONST_LOOKUP* addr) + { + var key = new DLD { A = CastHandle(cls), B = isGc ? 1u : 0u }; + Agnostic_GetStaticBaseAddress value = LookupByKeyOrMiss(GetStaticBaseAddress, key, ": key %016llX", key.A); + addr->accessType = (InfoAccessType)value.addr.accessType; + addr->addr = (void*)value.addr.handle; + return value.result != 0; + } + + public uint repGetThreadTLSIndex(void** ppIndirection) + { + DLD value = LookupByKeyOrMiss(GetThreadTLSIndex, 0u); + if (ppIndirection != null) + *ppIndirection = (void*)value.A; + return value.B; + } + + public int* repGetAddrOfCaptureThreadGlobal(void** ppIndirection) + { + if (GetAddrOfCaptureThreadGlobal == null || GetAddrOfCaptureThreadGlobal.GetIndex(0) == -1) + { + Logger.LogDebug("Sparse - repGetAddrOfCaptureThreadGlobal returning nullptr and 0xCAFE0001"); + if (ppIndirection != null) + *ppIndirection = null; + return (int*)0xCAFE0001; + } + + DLDL value = GetAddrOfCaptureThreadGlobal.Get(0); + if (ppIndirection != null) + *ppIndirection = (void*)value.A; + return (int*)value.B; + } + + public void* repGetClassStaticDynamicInfo(CORINFO_CLASS_STRUCT_* cls) => (void*)LookupByHandle(GetClassStaticDynamicInfo, cls).A; + + public void* repGetClassThreadStaticDynamicInfo(CORINFO_CLASS_STRUCT_* cls) => (void*)LookupByHandle(GetClassThreadStaticDynamicInfo, cls).A; + + public void repGetLocationOfThisType(CORINFO_METHOD_STRUCT_* context, CORINFO_LOOKUP_KIND* pLookupKind) + => *pLookupKind = RestoreCORINFO_LOOKUP_KIND(LookupByHandle(GetLocationOfThisType, context)); + + public CORINFO_METHOD_STRUCT_* repGetDelegateCtor(CORINFO_METHOD_STRUCT_* methHnd, CORINFO_CLASS_STRUCT_* clsHnd, CORINFO_METHOD_STRUCT_* targetMethodHnd, + DelegateCtorArgs* pCtorData) + { + var key = new Agnostic_GetDelegateCtorIn { methHnd = CastHandle(methHnd), clsHnd = CastHandle(clsHnd), targetMethodHnd = CastHandle(targetMethodHnd) }; + Agnostic_GetDelegateCtorOut value = LookupByKeyOrMiss(GetDelegateCtor, key, ": key %016llX", key.methHnd); + pCtorData->pMethod = (void*)value.CtorData.pMethod; + pCtorData->pArg3 = (void*)value.CtorData.pArg3; + pCtorData->pArg4 = (void*)value.CtorData.pArg4; + pCtorData->pArg5 = (void*)value.CtorData.pArg5; + return (CORINFO_METHOD_STRUCT_*)value.result; + } + + // The isUnsafeFunctionPointer has no impact on the resulting value; it only produces side effects in the runtime. + public void repGetFunctionFixedEntryPoint(CORINFO_METHOD_STRUCT_* ftn, bool isUnsafeFunctionPointer, CORINFO_CONST_LOOKUP* pResult) + => *pResult = RestoreCORINFO_CONST_LOOKUP(LookupByHandle(GetFunctionFixedEntryPoint, ftn)); + + public CORINFO_FIELD_STRUCT_* repGetFieldInClass(CORINFO_CLASS_STRUCT_* clsHnd, int num) + { + var key = new DLD { A = CastHandle(clsHnd), B = (uint)num }; + return (CORINFO_FIELD_STRUCT_*)LookupByKeyOrMiss(GetFieldInClass, key, ": key %016llX", key.A); + } + + public GetTypeLayoutResult repGetTypeLayout(CORINFO_CLASS_STRUCT_* typeHnd, CORINFO_TYPE_LAYOUT_NODE* nodes, nuint* numNodes) + { + ulong key = CastHandle(typeHnd); + Agnostic_GetTypeLayoutResult value = LookupByKeyOrMiss(GetTypeLayout, key, ": key type-%016llX", key); + + var result = (GetTypeLayoutResult)value.result; + if (result == GetTypeLayoutResult.Failure) + return result; + + byte* valueFields = GetTypeLayout.GetBufferPointer(value.nodesBuffer); + nuint nodesToWrite = Math.Min(value.numNodes, *numNodes); + for (nuint i = 0; i < nodesToWrite; i++) + nodes[i] = RestoreCORINFO_TYPE_LAYOUT_NODE(Unsafe.ReadUnaligned(valueFields + i * (nuint)sizeof(Agnostic_CORINFO_TYPE_LAYOUT_NODE))); + + *numNodes = nodesToWrite; + return result == GetTypeLayoutResult.Partial || value.numNodes > *numNodes ? GetTypeLayoutResult.Partial : GetTypeLayoutResult.Success; + } + + public CorInfoType repGetFieldType(CORINFO_FIELD_STRUCT_* field, CORINFO_CLASS_STRUCT_** structType, CORINFO_CLASS_STRUCT_* fieldOwnerHint) + { + var key = new DLDL { A = CastHandle(field), B = CastHandle(fieldOwnerHint) }; + DLD value = LookupByKeyOrMiss(GetFieldType, key, ": key %016llX", key.A); + if (structType != null) + *structType = (CORINFO_CLASS_STRUCT_*)value.A; + return (CorInfoType)value.B; + } + + public bool repSatisfiesMethodConstraints(CORINFO_CLASS_STRUCT_* parent, CORINFO_METHOD_STRUCT_* method) + { + var key = new DLDL { A = CastHandle(parent), B = CastHandle(method) }; + return LookupByKeyOrMiss(SatisfiesMethodConstraints, key) != 0; + } + + public int repGetStringLiteral(CORINFO_MODULE_STRUCT_* module, uint metaTOK, char* buffer, int bufferSize, int startIndex) + { + var key = new DLDDD { A = CastHandle(module), B = metaTOK, C = (uint)bufferSize, D = (uint)startIndex }; + DD value = LookupByKeyOrMiss(GetStringLiteral, key, ": key handle-%016llX token-%X bufferSize-%d startIndex-%d", key.A, key.B, key.C, key.D); + + int srcBufferLength = (int)value.A; + if (buffer != null && srcBufferLength > 0) + { + byte* srcBuffer = GetStringLiteral.GetBufferPointer(value.B); + ErrorHandling.AssertCode(srcBuffer != null, ExceptionCodes.ASSERT, "srcBuffer != nullptr"); + int bytes = Math.Min(srcBufferLength, bufferSize) * sizeof(char); + Buffer.MemoryCopy(srcBuffer, buffer, bytes, bytes); + } + return srcBufferLength; + } + + public bool repCanCast(CORINFO_CLASS_STRUCT_* child, CORINFO_CLASS_STRUCT_* parent) + { + var key = new DLDL { A = CastHandle(child), B = CastHandle(parent) }; + return LookupByKeyOrMiss(CanCast, key, ": key %016llX %016llX", key.A, key.B) != 0; + } + + public CorInfoType repGetChildType(CORINFO_CLASS_STRUCT_* clsHnd, CORINFO_CLASS_STRUCT_** clsRet) + { + DLD value = LookupByHandle(GetChildType, clsHnd); + *clsRet = (CORINFO_CLASS_STRUCT_*)value.A; + return (CorInfoType)value.B; + } + + public void* repGetArrayInitializationData(CORINFO_FIELD_STRUCT_* field, uint size) + { + var key = new DLD { A = CastHandle(field), B = size }; + return (void*)LookupByKeyOrMiss(GetArrayInitializationData, key); + } + + public void repGetAddressOfPInvokeTarget(CORINFO_METHOD_STRUCT_* method, CORINFO_CONST_LOOKUP* pLookup) + { + DLD value = LookupByHandle(GetAddressOfPInvokeTarget, method); + pLookup->addr = (void*)value.A; + pLookup->accessType = (InfoAccessType)value.B; + } + + public uint repGetMethodHash(CORINFO_METHOD_STRUCT_* ftn) + { + ulong key = CastHandle(ftn); + return GetMethodHash != null && GetMethodHash.GetIndex(key) >= 0 ? GetMethodHash.Get(key) : 0x43; + } + + public bool repCanTailCall(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* declaredCalleeHnd, CORINFO_METHOD_STRUCT_* exactCalleeHnd, bool fIsTailPrefix) + { + var key = new Agnostic_CanTailCall + { + callerHnd = CastHandle(callerHnd), + declaredCalleeHnd = CastHandle(declaredCalleeHnd), + exactCalleeHnd = CastHandle(exactCalleeHnd), + fIsTailPrefix = fIsTailPrefix ? (ushort)1 : (ushort)0, + }; + return LookupByKeyOrMiss(CanTailCall, key, ": key %016llX", key.callerHnd) != 0; + } + + public void repFindCallSiteSig(CORINFO_MODULE_STRUCT_* module, uint methTOK, CORINFO_CONTEXT_STRUCT* context, CORINFO_SIG_INFO* sig) + { + var key = new Agnostic_FindCallSiteSig { module = CastHandle(module), methTok = methTOK, context = CastHandle(context) }; + Agnostic_CORINFO_SIG_INFO value = LookupByKeyOrMiss(FindCallSiteSig, key, ": key %08X", key.methTok); + *sig = Restore_CORINFO_SIG_INFO(value, FindCallSiteSig, SigInstHandleMap, cr.MemoryTracker); + } + + public nint repGetVarArgsHandle(CORINFO_SIG_INFO* pSig, CORINFO_METHOD_STRUCT_* methHnd, void** ppIndirection) + { + var key = new GetVarArgsHandleValue + { + cbSig = pSig->cbSig, + pSig_Index = (uint)GetVarArgsHandle.Contains(Bytes(pSig->pSig, pSig->cbSig)), + scope = CastHandle(pSig->scope), + token = (uint)pSig->token, + methHnd = CastHandle(methHnd), + }; + DLDL value = LookupByKeyOrMiss(GetVarArgsHandle, key); + if (ppIndirection != null) + *ppIndirection = (void*)value.A; + return (nint)value.B; + } + + public uint repGetFieldThreadLocalStoreID(CORINFO_FIELD_STRUCT_* field, void** ppIndirection) + { + DLD value = LookupByHandle(GetFieldThreadLocalStoreID, field); + if (ppIndirection != null) + *ppIndirection = (void*)value.A; + return value.B; + } + + private static uint InstrumentationKindToSize(PgoInstrumentationKind kind) => (kind & PgoInstrumentationKind.MarshalMask) switch + { + PgoInstrumentationKind.None => 0, + PgoInstrumentationKind.FourByte => 4, + PgoInstrumentationKind.EightByte => 8, + PgoInstrumentationKind.TypeHandle or PgoInstrumentationKind.MethodHandle => (uint)sizeof(nint), + _ => 0, + }; + + private static uint InstrumentationKindToAlignment(PgoInstrumentationKind kind) => (kind & PgoInstrumentationKind.AlignMask) switch + { + PgoInstrumentationKind.Align4Byte => 4, + PgoInstrumentationKind.Align8Byte => 8, + PgoInstrumentationKind.AlignPointer => (uint)sizeof(nint), + _ => InstrumentationKindToSize(kind), + }; + + public HRESULT repAllocPgoInstrumentationBySchema(CORINFO_METHOD_STRUCT_* ftnHnd, PgoInstrumentationSchema* pSchema, uint countSchemaItems, byte** pInstrumentationData) + { + // Matching case: return the same layout as the recorded EE. + if (repAllocPgoInstrumentationBySchemaRecorded(ftnHnd, pSchema, countSchemaItems, pInstrumentationData, out HRESULT result)) + return result; + + // Do our own layout. + uint maxAlignment = 1; + uint offset = 0; + for (uint i = 0; i < countSchemaItems; i++) + { + uint size = InstrumentationKindToSize(pSchema[i].InstrumentationKind) * (uint)pSchema[i].Count; + if (size != 0) + { + uint alignment = InstrumentationKindToAlignment(pSchema[i].InstrumentationKind); + maxAlignment = Math.Max(maxAlignment, alignment); + offset = (offset + alignment - 1) & ~(alignment - 1); + pSchema[i].Offset = (nint)offset; + } + offset += size; + } + + // We assume the JIT doesn't write or read this buffer, only generates code that uses it. + *pInstrumentationData = (byte*)(0x12345678u & ~(maxAlignment - 1)); + return HRESULT.S_OK; + } + + private bool repAllocPgoInstrumentationBySchemaRecorded(CORINFO_METHOD_STRUCT_* ftnHnd, PgoInstrumentationSchema* pSchema, uint countSchemaItems, + byte** pInstrumentationData, out HRESULT result) + { + result = default; + int index = AllocPgoInstrumentationBySchema?.GetIndex(CastHandle(ftnHnd)) ?? -1; + if (index == -1) + return false; + + Agnostic_AllocPgoInstrumentationBySchema value = AllocPgoInstrumentationBySchema.GetItem(index); + if (value.countSchemaItems != countSchemaItems) + return false; + + byte* pAgnosticSchema = AllocPgoInstrumentationBySchema.GetBufferPointer(value.schema_index); + for (uint iSchema = 0; iSchema < value.countSchemaItems; iSchema++) + { + // Everything but Offset is an IN argument, so verify it against what was stored (since those + // IN arguments weren't part of the key). + var agnostic = Unsafe.ReadUnaligned(pAgnosticSchema + iSchema * (uint)sizeof(Agnostic_PgoInstrumentationSchema)); + if ((PgoInstrumentationKind)agnostic.InstrumentationKind != pSchema[iSchema].InstrumentationKind || + (int)agnostic.ILOffset != pSchema[iSchema].ILOffset || + (int)agnostic.Count != pSchema[iSchema].Count || + (int)agnostic.Other != pSchema[iSchema].Other) + { + return false; + } + + pSchema[iSchema].Offset = (nint)agnostic.Offset; + } + + // We assume the JIT doesn't write or read this buffer, only generates code that uses it. + *pInstrumentationData = (byte*)value.instrumentationDataAddress; + result = (HRESULT)value.result; + return true; + } + + public HRESULT repGetPgoInstrumentationResults(CORINFO_METHOD_STRUCT_* ftnHnd, PgoInstrumentationSchema** pSchema, uint* pCountSchemaItems, + byte** pInstrumentationData, PgoSource* pPgoSource, bool* pDynamicPgo) + { + Agnostic_GetPgoInstrumentationResults tempValue = LookupByHandle(GetPgoInstrumentationResults, ftnHnd); + + *pCountSchemaItems = tempValue.countSchemaItems; + *pInstrumentationData = GetPgoInstrumentationResults.GetBufferPointer(tempValue.data_index); + *pPgoSource = (PgoSource)tempValue.pgoSource; + *pDynamicPgo = tempValue.dynamicPgo != 0; + + var pOutSchema = (PgoInstrumentationSchema*)AllocJitTempBuffer(tempValue.countSchemaItems * (nuint)sizeof(PgoInstrumentationSchema)); + byte* pAgnosticSchema = GetPgoInstrumentationResults.GetBufferPointer(tempValue.schema_index); + for (uint iSchema = 0; iSchema < tempValue.countSchemaItems; iSchema++) + { + var agnostic = Unsafe.ReadUnaligned(pAgnosticSchema + iSchema * (uint)sizeof(Agnostic_PgoInstrumentationSchema)); + pOutSchema[iSchema] = new PgoInstrumentationSchema + { + Offset = (nint)agnostic.Offset, + InstrumentationKind = (PgoInstrumentationKind)agnostic.InstrumentationKind, + ILOffset = (int)agnostic.ILOffset, + Count = (int)agnostic.Count, + Other = (int)agnostic.Other, + }; + } + + *pSchema = pOutSchema; + return (HRESULT)tempValue.result; + } + + public bool repIsMoreSpecificType(CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2) + { + var key = new DLDL { A = CastHandle(cls1), B = CastHandle(cls2) }; + return LookupByKeyOrMiss(IsMoreSpecificType, key, ": key %016llX %016llX", key.A, key.B) != 0; + } + + public bool repIsExactType(CORINFO_CLASS_STRUCT_* cls) => LookupByHandle(IsExactType, cls) != 0; + + public TypeCompareState repIsGenericType(CORINFO_CLASS_STRUCT_* cls) => (TypeCompareState)LookupByHandle(IsGenericType, cls); + + public TypeCompareState repIsNullableType(CORINFO_CLASS_STRUCT_* cls) => (TypeCompareState)LookupByHandle(IsNullableType, cls); + + public TypeCompareState repIsEnum(CORINFO_CLASS_STRUCT_* cls, CORINFO_CLASS_STRUCT_** underlyingType) + { + DLD value = LookupByHandle(IsEnum, cls); + if (underlyingType != null) + *underlyingType = (CORINFO_CLASS_STRUCT_*)value.A; + return (TypeCompareState)value.B; + } + + public void* repGetCookieForInterpreterCalliSig(CORINFO_SIG_INFO* szMetaSig) + { + AssertMapExists(GetCookieForInterpreterCalliSig); + + var key = new GetCookieForInterpreterCalliSigValue + { + cbSig = szMetaSig->cbSig, + pSig_Index = (uint)GetCookieForInterpreterCalliSig.Contains(Bytes(szMetaSig->pSig, szMetaSig->cbSig)), + scope = CastHandle(szMetaSig->scope), + token = (uint)szMetaSig->token, + }; + return (void*)LookupByKeyOrMiss(GetCookieForInterpreterCalliSig, key).A; + } + + public void repGetProfilingHandle(bool* pbHookFunction, void** pProfilerHandle, bool* pbIndirectedHandles) + { + Agnostic_GetProfilingHandle value = LookupByKeyOrMiss(GetProfilingHandle, 0u); + *pbHookFunction = value.bHookFunction != 0; + *pProfilerHandle = (void*)value.ProfilerHandle; + *pbIndirectedHandles = value.bIndirectedHandles != 0; + } + + public CORINFO_FIELD_STRUCT_* repEmbedFieldHandle(CORINFO_FIELD_STRUCT_* handle, void** ppIndirection) + { + DLDL value = LookupByHandle(EmbedFieldHandle, handle); + if (ppIndirection != null) + *ppIndirection = (void*)value.A; + return (CORINFO_FIELD_STRUCT_*)value.B; + } + + public TypeCompareState repCompareTypesForCast(CORINFO_CLASS_STRUCT_* fromClass, CORINFO_CLASS_STRUCT_* toClass) + { + var key = new DLDL { A = CastHandle(fromClass), B = CastHandle(toClass) }; + return (TypeCompareState)LookupByKeyOrMiss(CompareTypesForCast, key, ": key %016llX %016llX", key.A, key.B); + } + + public TypeCompareState repCompareTypesForEquality(CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2) + { + var key = new DLDL { A = CastHandle(cls1), B = CastHandle(cls2) }; + return (TypeCompareState)LookupByKeyOrMiss(CompareTypesForEquality, key, ": key %016llX %016llX", key.A, key.B); + } + + public bool repGetSystemVAmd64PassStructInRegisterDescriptor(CORINFO_CLASS_STRUCT_* structHnd, SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr) + { + Agnostic_GetSystemVAmd64PassStructInRegisterDescriptor value = LookupByHandle(GetSystemVAmd64PassStructInRegisterDescriptor, structHnd); + structPassInRegDescPtr->passedInRegisters = value.passedInRegisters != 0; + structPassInRegDescPtr->eightByteCount = (byte)value.eightByteCount; + structPassInRegDescPtr->eightByteClassifications0 = (SystemVClassificationType)value.eightByteClassifications[0]; + structPassInRegDescPtr->eightByteClassifications1 = (SystemVClassificationType)value.eightByteClassifications[1]; + structPassInRegDescPtr->eightByteSizes0 = (byte)value.eightByteSizes[0]; + structPassInRegDescPtr->eightByteSizes1 = (byte)value.eightByteSizes[1]; + structPassInRegDescPtr->eightByteOffsets0 = (byte)value.eightByteOffsets[0]; + structPassInRegDescPtr->eightByteOffsets1 = (byte)value.eightByteOffsets[1]; + return value.result != 0; + } + + public void repGetSwiftLowering(CORINFO_CLASS_STRUCT_* structHnd, CORINFO_SWIFT_LOWERING* pLowering) + { + Agnostic_GetSwiftLowering value = LookupByHandle(GetSwiftLowering, structHnd); + pLowering->byReference = value.byReference != 0; + pLowering->numLoweredElements = (nint)value.numLoweredElements; + for (int i = 0; i < pLowering->numLoweredElements; i++) + { + pLowering->LoweredElements[i] = (CorInfoType)value.loweredElements[i]; + pLowering->Offsets[i] = value.offsets[i]; + } + } + + public void repGetFpStructLowering(CORINFO_CLASS_STRUCT_* structHnd, CORINFO_FPSTRUCT_LOWERING* pLowering) + { + Agnostic_GetFpStructLowering value = LookupByHandle(GetFpStructLowering, structHnd); + pLowering->byIntegerCallConv = value.byIntegerCallConv != 0; + pLowering->numLoweredElements = (nint)value.numLoweredElements; + for (int i = 0; i < pLowering->numLoweredElements; i++) + { + pLowering->LoweredElements[i] = (CorInfoType)value.loweredElements[i]; + pLowering->Offsets[i] = value.offsets[i]; + } + } + + public CorInfoWasmType repGetWasmLowering(CORINFO_CLASS_STRUCT_* structHnd) => (CorInfoWasmType)LookupByHandle(GetWasmLowering, structHnd); + + public CorInfoReloc repGetRelocTypeHint(void* target) + { + ulong key = CastHandle(target); + int index = GetRelocTypeHint?.GetIndex(key) ?? -1; + if (index == -1) + { + Logger.LogDebug("Sparse - repGetRelocTypeHint yielding fake answer..."); + return CorInfoReloc.NONE; + } + return (CorInfoReloc)GetRelocTypeHint.GetItem(index); + } + + public uint repGetAddressAlignment(void* address) + { + ulong key = CastHandle(address); + int index = GetAddressAlignment?.GetIndex(key) ?? -1; + if (index == -1) + { + Logger.LogDebug("Sparse - repGetAddressAlignment yielding fake answer..."); + return 1; + } + return GetAddressAlignment.GetItem(index); + } + + public uint repGetExpectedTargetArchitecture() + { + uint key = 0; + return LookupByKeyOrMiss(GetExpectedTargetArchitecture, key, ": key %08X", key); + } + + public byte* repGetClassNameFromMetadata(CORINFO_CLASS_STRUCT_* cls, byte** namespaceName) + { + var key = new DLD { A = CastHandle(cls), B = namespaceName != null ? 1u : 0u }; + DD value = LookupByKeyOrMiss(GetClassNameFromMetadata, key, " : key cls-%016llX hasNs-%u", key.A, key.B); + if (namespaceName != null) + *namespaceName = GetClassNameFromMetadata.GetBufferPointer(value.B); + return GetClassNameFromMetadata.GetBufferPointer(value.A); + } + + public CORINFO_CLASS_STRUCT_* repGetTypeInstantiationArgument(CORINFO_CLASS_STRUCT_* cls, uint index) + { + var key = new DLD { A = CastHandle(cls), B = index }; + return (CORINFO_CLASS_STRUCT_*)LookupByKeyOrMiss(GetTypeInstantiationArgument, key); + } + + public CORINFO_CLASS_STRUCT_* repGetMethodInstantiationArgument(CORINFO_METHOD_STRUCT_* ftn, uint index) + { + var key = new DLD { A = CastHandle(ftn), B = index }; + return (CORINFO_CLASS_STRUCT_*)LookupByKeyOrMiss(GetMethodInstantiationArgument, key); + } + + // Copies the recorded name into 'buffer' (null-terminated, truncated to fit), and returns the number of + // bytes written. Fails if the recorded data can't answer the query losslessly. + public nuint repPrint(string name, LightWeightMap map, ulong handle, byte* buffer, nuint bufferSize, nuint* pRequiredBufferSize) + { + int index = map?.GetIndex(handle) ?? -1; + if (index == -1) + LookupByKeyOrMiss(map, handle, ": map " + name + " key %016llx", handle, mapName: "map", keyName: "handle"); + Agnostic_PrintResult res = map.GetItem(index); + + if (pRequiredBufferSize != null) + { + if (res.requiredBufferSize == uint.MaxValue) + ErrorHandling.LogException(ExceptionCodes.MC, $"SuperPMI assertion failed (missing requiredBufferSize for {name} key {handle:x16})"); + *pRequiredBufferSize = res.requiredBufferSize; + } + + // requiredBufferSize includes the null terminator, but the buffer is stored without one. Determine + // whether there's enough data to answer the query losslessly. Note that the recorder always sets + // requiredBufferSize if it had enough information to determine it. + bool haveFullBuffer = res.requiredBufferSize != uint.MaxValue && unchecked(res.stringBufferSize + 1) >= res.requiredBufferSize; + if (!haveFullBuffer && bufferSize > (nuint)res.stringBufferSize + 1) + ErrorHandling.LogException(ExceptionCodes.MC, $"SuperPMI assertion failed (not enough buffer data for {name} key {handle:x16})"); + + nuint bytesWritten = 0; + if (buffer != null && bufferSize > 0) + { + bytesWritten = Math.Min(bufferSize - 1, res.stringBufferSize); + if (bytesWritten > 0) + { + // The "full buffer" check above ensures this, given that res.stringBuffer == UINT_MAX + // implies res.stringBufferSize == 0. + ErrorHandling.AssertCode(res.stringBuffer != uint.MaxValue, ExceptionCodes.ASSERT, "res.stringBuffer != UINT_MAX"); + Buffer.MemoryCopy(map.GetBufferPointer(res.stringBuffer), buffer, bytesWritten, bytesWritten); + } + buffer[bytesWritten] = 0; + } + + return bytesWritten; + } + + public nuint repPrintObjectDescription(CORINFO_OBJECT_STRUCT_* handle, byte* buffer, nuint bufferSize, nuint* pRequiredBufferSize) + => repPrint("PrintObjectDescription", PrintObjectDescription, CastHandle(handle), buffer, bufferSize, pRequiredBufferSize); + + public nuint repPrintClassName(CORINFO_CLASS_STRUCT_* cls, byte* buffer, nuint bufferSize, nuint* pRequiredBufferSize) + => repPrint("PrintClassName", PrintClassName, CastHandle(cls), buffer, bufferSize, pRequiredBufferSize); + + public nuint repPrintFieldName(CORINFO_FIELD_STRUCT_* fld, byte* buffer, nuint bufferSize, nuint* pRequiredBufferSize) + => repPrint("PrintFieldName", PrintFieldName, CastHandle(fld), buffer, bufferSize, pRequiredBufferSize); + + public nuint repPrintMethodName(CORINFO_METHOD_STRUCT_* meth, byte* buffer, nuint bufferSize, nuint* pRequiredBufferSize) + => repPrint("PrintMethodName", PrintMethodName, CastHandle(meth), buffer, bufferSize, pRequiredBufferSize); + + public bool repGetTailCallHelpers(CORINFO_RESOLVED_TOKEN* callToken, CORINFO_SIG_INFO* sig, CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, CORINFO_TAILCALL_HELPERS* pResult) + { + AssertMapExists(GetTailCallHelpers); + + var key = new Agnostic_GetTailCallHelpers + { + callToken = RestoreAgnostic_CORINFO_RESOLVED_TOKEN(callToken, GetTailCallHelpers), + sig = RestoreAgnostic_CORINFO_SIG_INFO(*sig, GetTailCallHelpers, SigInstHandleMap), + flags = (uint)flags, + }; + Agnostic_CORINFO_TAILCALL_HELPERS value = LookupByKeyOrMiss(GetTailCallHelpers, key); + if (value.result == 0) + return false; + + pResult->flags = (CORINFO_TAILCALL_HELPERS_FLAGS)value.flags; + pResult->hStoreArgs = (CORINFO_METHOD_STRUCT_*)value.hStoreArgs; + pResult->hCallTarget = (CORINFO_METHOD_STRUCT_*)value.hCallTarget; + pResult->hDispatcher = (CORINFO_METHOD_STRUCT_*)value.hDispatcher; + return true; + } + + public CORINFO_METHOD_STRUCT_* repGetAsyncResumptionStub(void** entryPoint) + { + DLDL value = LookupByKeyOrMiss(GetAsyncResumptionStub, 0u); + *entryPoint = (void*)value.B; + return (CORINFO_METHOD_STRUCT_*)value.A; + } + + public CORINFO_CLASS_STRUCT_* repGetContinuationType(nuint dataSize, bool* objRefs, nuint objRefsSize) + { + AssertMapExists(GetContinuationType); + + var key = new Agnostic_GetContinuationTypeIn + { + dataSize = dataSize, + objRefs = (uint)GetContinuationType.Contains(Bytes(objRefs, objRefsSize)), + objRefsSize = (uint)objRefsSize, + }; + + // This handle is more or less opaque, so tolerate a miss and fake up a handle. Otherwise SPMI + // would be useless for any async change that results in changes in live state. + int index = GetContinuationType.GetIndex(key); + return (CORINFO_CLASS_STRUCT_*)(index == -1 ? CONTINUATION_TYPE_PSEUDO_CLASS_HANDLE : GetContinuationType.GetItem(index)); + } + + public void repUpdateEntryPointForTailCall(CORINFO_CONST_LOOKUP* entryPoint) + { + AssertMapExists(UpdateEntryPointForTailCall); + + Agnostic_CORINFO_CONST_LOOKUP key = StoreAgnostic_CORINFO_CONST_LOOKUP(entryPoint); + *entryPoint = RestoreCORINFO_CONST_LOOKUP(LookupByKeyOrMiss(UpdateEntryPointForTailCall, key)); + } + + public mdToken repGetMethodDefFromMethod(CORINFO_METHOD_STRUCT_* hMethod) + { + // Since this is diagnostic, fake up a result if one wasn't recorded. + if (GetMethodDefFromMethod == null) + return (mdToken)0x06000000; + + int index = GetMethodDefFromMethod.GetIndex(CastHandle(hMethod)); + return index < 0 ? (mdToken)0x06000001 : (mdToken)GetMethodDefFromMethod.GetItem(index); + } + + public bool repCheckMethodModifier(CORINFO_METHOD_STRUCT_* hMethod, byte* modifier, bool fOptional) + { + var key = new Agnostic_CheckMethodModifier + { + hMethod = CastHandle(hMethod), + modifier = modifier != null ? (uint)CheckMethodModifier.Contains(CString(modifier)) : uint.MaxValue, + fOptional = fOptional ? 1u : 0u, + }; + return LookupByKeyOrMiss(CheckMethodModifier, key) != 0; + } + + public uint repGetArrayRank(CORINFO_CLASS_STRUCT_* cls) => LookupByHandle(GetArrayRank, cls); + + public CorInfoArrayIntrinsic repGetArrayIntrinsicID(CORINFO_METHOD_STRUCT_* hMethod) => (CorInfoArrayIntrinsic)LookupByHandle(GetArrayIntrinsicID, hMethod); + + public bool repIsFieldStatic(CORINFO_FIELD_STRUCT_* fhld) => LookupByHandle(IsFieldStatic, fhld) != 0; + + public int repGetArrayOrStringLength(CORINFO_OBJECT_STRUCT_* objHandle) => (int)LookupByHandle(GetArrayOrStringLength, objHandle); + + public int repGetIntConfigValue(byte* name, int defaultValue) + { + if (ignoreStoredConfig || GetIntConfigValue == null) + return defaultValue; + + ErrorHandling.AssertCodeMsg(name != null, ExceptionCodes.MC, "name != nullptr", "Name can not be nullptr"); + + int nameIndex = GetIntConfigValue.Contains(CString(name)); + if (nameIndex == -1) // config name not in map + return defaultValue; + + int index = GetIntConfigValue.GetIndex(new Agnostic_ConfigIntInfo { nameIndex = (uint)nameIndex, defaultValue = (uint)defaultValue }); + if (index == -1) // the default value has changed + return defaultValue; + + return (int)GetIntConfigValue.GetItem(index); + } + + public byte* repGetStringConfigValue(byte* name) + { + if (ignoreStoredConfig || GetStringConfigValue == null) + return null; + + ErrorHandling.AssertCodeMsg(name != null, ExceptionCodes.MC, "name != nullptr", "Name can not be nullptr"); + + int nameIndex = GetStringConfigValue.Contains(CString(name)); + if (nameIndex == -1) // config name not in map + return null; + + uint resultIndex = LookupByKeyOrMiss(GetStringConfigValue, (uint)nameIndex, keyName: "nameIndex"); + return GetStringConfigValue.GetBufferPointer(resultIndex); + } + + public CORINFO_METHOD_STRUCT_* repGetSpecialCopyHelper(CORINFO_CLASS_STRUCT_* type) => (CORINFO_METHOD_STRUCT_*)LookupByHandle(GetSpecialCopyHelper, type); + + public CORINFO_WASM_TYPE_SYMBOL_STRUCT_* repGetWasmTypeSymbol(CorInfoWasmType* types, nuint typesSize) + { + // Fake up a result so we can cross-replay onto wasm. + if (GetWasmTypeSymbol == null) + return (CORINFO_WASM_TYPE_SYMBOL_STRUCT_*)0xbadcab; + + var key = new Agnostic_GetWasmTypeSymbol + { + types = (uint)GetWasmTypeSymbol.Contains(Bytes(types, (nuint)sizeof(CorInfoWasmType) * typesSize)), + typesSize = (uint)typesSize, + }; + return (CORINFO_WASM_TYPE_SYMBOL_STRUCT_*)LookupByKeyOrMiss(GetWasmTypeSymbol, key, ": types %u, typesSize %u", key.types, key.typesSize); + } + + public bool repCanValueClassInstancePointerEscape(CORINFO_METHOD_STRUCT_* ftn) => LookupByHandle(CanValueClassInstancePointerEscape, ftn) != 0; + + public sealed class ConfigEnvironment + { + public LightWeightMap getIntConfigValue; + public LightWeightMap getStringConfigValue; + } + + public ConfigEnvironment cloneEnvironment() => new() + { + getIntConfigValue = GetIntConfigValue?.Clone(), + getStringConfigValue = GetStringConfigValue?.Clone(), + }; + + public bool WasEnvironmentChanged(ConfigEnvironment prevEnv) + => !AreLWMHeadersEqual(prevEnv.getIntConfigValue, GetIntConfigValue) || !AreLWMHeadersEqual(prevEnv.getStringConfigValue, GetStringConfigValue) || + !IsIntConfigContentEqual(prevEnv.getIntConfigValue, GetIntConfigValue) || !IsStringContentEqual(prevEnv.getStringConfigValue, GetStringConfigValue); + + private static bool AreLWMHeadersEqual(LightWeightMapBuffer prev, LightWeightMapBuffer curr) + => (prev == null && curr == null) || (prev != null && curr != null && prev.GetCount() == curr.GetCount()); + + private static bool IsIntConfigContentEqual(LightWeightMap prev, LightWeightMap curr) + { + if (prev == null || curr == null) + return prev == curr; + + if (prev.GetCount() != curr.GetCount()) + return false; + + for (int i = 0; i < prev.GetCount(); i++) + { + Agnostic_ConfigIntInfo currKey = curr.GetKey(i); + Agnostic_ConfigIntInfo prevKey = prev.GetKey(i); + + // The previous name is deliberately read at the current key's index: this decides when the JIT is reset. + if (curr.GetItem(i) != prev.GetItem(i) || currKey.defaultValue != prevKey.defaultValue || + curr.GetString(currKey.nameIndex) != prev.GetString(currKey.nameIndex)) + { + return false; + } + } + return true; + } + + private static bool IsStringContentEqual(LightWeightMap prev, LightWeightMap curr) + { + if (prev == null || curr == null) + return prev == curr; + + if (prev.GetCount() != curr.GetCount()) + return false; + + for (int i = 0; i < curr.GetCount(); i++) + { + if (curr.GetString(curr.GetKey(i)) != prev.GetString(prev.GetKey(i)) || + curr.GetString(curr.GetItem(i)) != prev.GetString(prev.GetItem(i))) + { + return false; + } + } + return true; + } + + public bool hasPgoData(out bool hasEdgeProfile, out bool hasClassProfile, out bool hasMethodProfile, out bool hasLikelyClass, + out bool hasLikelyMethod, out PgoSource pgoSource) + { + hasEdgeProfile = false; + hasClassProfile = false; + hasMethodProfile = false; + hasLikelyClass = false; + hasLikelyMethod = false; + pgoSource = PgoSource.Unknown; + + CORINFO_METHOD_INFO info; + uint flags; + CORINFO_OS os; + repCompileMethod(&info, &flags, &os); + + if (GetPgoInstrumentationResults == null || GetPgoInstrumentationResults.GetIndex(CastHandle(info.ftn)) == -1) + return false; + + PgoInstrumentationSchema* schema; + uint schemaCount; + byte* schemaData; + PgoSource source; + bool dynamicPgo; + HRESULT pgoHR = repGetPgoInstrumentationResults(info.ftn, &schema, &schemaCount, &schemaData, &source, &dynamicPgo); + pgoSource = source; + if (pgoHR < 0) + return false; + + for (uint i = 0; i < schemaCount; i++) + { + PgoInstrumentationKind kind = schema[i].InstrumentationKind; + hasEdgeProfile |= kind is PgoInstrumentationKind.EdgeIntCount or PgoInstrumentationKind.EdgeLongCount; + hasClassProfile |= kind == PgoInstrumentationKind.HandleHistogramTypes; + hasMethodProfile |= kind == PgoInstrumentationKind.HandleHistogramMethods; + hasLikelyClass |= kind == PgoInstrumentationKind.GetLikelyClass; + hasLikelyMethod |= kind == PgoInstrumentationKind.GetLikelyMethod; + + // Deliberately doesn't wait for hasMethodProfile. + if (hasEdgeProfile && hasClassProfile && hasLikelyClass && hasLikelyMethod) + break; + } + + return true; + } +} diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.cs new file mode 100644 index 00000000000000..3b1b39f5758583 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.cs @@ -0,0 +1,225 @@ +// 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.Buffers.Binary; +using System.IO; +using System.Text; + +namespace SuperPmi; + +// All the EE-JIT details required to replay the compilation of a method. The CompileResult +// holds what the compilation produced. +// +// Serialized form: 'm' 'c', a 4-byte length, the packets, then '4' '2'. Each packet is a 1-byte +// PacketId, a 4-byte size, the serialized map, and a 0x42 canary. +public sealed partial class MethodContext +{ + private const int HeaderSize = 2 /* 'm', 'c' */ + sizeof(uint) /* data length */; + private const int TrailerSize = 2; /* '4', '2' */ + private const int PacketOverhead = 1 /* packet id */ + sizeof(uint) /* size */ + 1 /* canary */; + private const byte PacketCanary = 0x42; + + private static readonly MapInfo[] s_mapByPacket; + + public int index = -1; + public CompileResult cr = new CompileResult(); + public bool ignoreStoredConfig; + + // Runs after the field initializers of all the partial declarations, including s_maps. + static MethodContext() + { + s_mapByPacket = BuildPacketTable(s_maps); + } + + internal static MapInfo[] BuildPacketTable(MapInfo[] maps) + { + var table = new MapInfo[256]; + foreach (MapInfo map in maps) + table[(byte)map.Packet] = map; + return table; + } + + // 'buff' holds the 'totalLen' bytes of packet data followed by the 2-byte end canary. + // Returns false (and logs) if the data is malformed. + public static bool Initialize(int mcIndex, ReadOnlySpan buff, uint totalLen, bool readCompileResults, out MethodContext mc) + { + mc = new MethodContext { index = mcIndex }; + try + { + mc.MethodInitHelper(buff, totalLen, readCompileResults); + return true; + } + catch (SpmiException e) when (e.Code is ExceptionCodes.MC or ExceptionCodes.LWM) + { + Logger.LogError($"Method {mcIndex} is of low integrity."); + return false; + } + } + + // Reads one method context (header, data and end canary) from the current position of 'stream'. + public static bool Initialize(int mcIndex, Stream stream, bool readCompileResults, out MethodContext mc) + { + mc = new MethodContext { index = mcIndex }; + try + { + Span header = stackalloc byte[HeaderSize]; + ErrorHandling.AssertCode(stream.ReadAtLeast(header, HeaderSize, throwOnEndOfStream: false) == HeaderSize, + ExceptionCodes.MC, "ReadFile(hFile, buff, 2 + sizeof(unsigned int), &bytesRead, NULL) == TRUE"); + ErrorHandling.AssertCodeMsg(header[0] == 'm' && header[1] == 'c', ExceptionCodes.MC, + "(buff[0] == 'm') && (buff[1] == 'c')", "Didn't find magic number"); + uint totalLen = BinaryPrimitives.ReadUInt32LittleEndian(header.Slice(2)); + + byte[] buff2 = new byte[(long)totalLen + TrailerSize]; + ErrorHandling.AssertCode(stream.ReadAtLeast(buff2, buff2.Length, throwOnEndOfStream: false) == buff2.Length, + ExceptionCodes.MC, "ReadFile(hFile, buff2, totalLen + 2, &bytesRead, NULL) == TRUE"); + ErrorHandling.AssertCodeMsg(buff2[totalLen] == '4' && buff2[totalLen + 1] == '2', ExceptionCodes.MC, + "(buff2[totalLen] == '4') && (buff2[totalLen + 1] == '2')", "Didn't find end canary"); + + mc.MethodInitHelper(buff2, totalLen, readCompileResults); + return true; + } + catch (SpmiException e) when (e.Code is ExceptionCodes.MC or ExceptionCodes.LWM) + { + Logger.LogError($"Method {mcIndex} is of low integrity."); + return false; + } + } + + private void MethodInitHelper(ReadOnlySpan buff2, uint totalLen, bool readCompileResults) + { + int buffIndex = 0; + while (buffIndex < totalLen) + { + ErrorHandling.AssertCodeMsg(buffIndex + 1 + sizeof(uint) <= buff2.Length, ExceptionCodes.MC, + "buffIndex + 5 <= totalLen", "Packet header runs past the end of the method context"); + byte packetType = buff2[buffIndex++]; + uint localsize = BinaryPrimitives.ReadUInt32LittleEndian(buff2.Slice(buffIndex)); + buffIndex += sizeof(uint); + ErrorHandling.AssertCodeMsg((long)buffIndex + localsize + 1 <= buff2.Length, ExceptionCodes.MC, + "buffIndex + localsize <= totalLen", "Packet runs past the end of the method context"); + ReadOnlySpan packetData = buff2.Slice(buffIndex, (int)localsize); + + MapInfo map = s_mapByPacket[packetType]; + if (map != null) + { + _maps[map.Index] = ReadMap(map, packetData); + } + else if ((map = CompileResult.s_mapByPacket[packetType]) != null) + { + if (readCompileResults) + cr.SetMap(map.Index, ReadMap(map, packetData)); + } + else + { + ErrorHandling.LogException(ExceptionCodes.MC, + $"Read ran into unknown packet type {packetType}. Are you using a newer recorder?"); + } + + buffIndex += (int)localsize; + byte canary = buff2[buffIndex++]; + ErrorHandling.AssertCodeMsg(canary == PacketCanary, ExceptionCodes.MC, "canary == 0x42", "Didn't find trailing canary for map"); + } + + ErrorHandling.AssertCodeMsg(buffIndex + 1 < buff2.Length && buff2[buffIndex] == '4' && buff2[buffIndex + 1] == '2', + ExceptionCodes.MC, "(buff2[buffIndex++] == '4') && (buff2[buffIndex++] == '2')", "Didn't find trailing canary for map"); + } + + private static LightWeightMapBuffer ReadMap(MapInfo map, ReadOnlySpan data) + { + LightWeightMapBuffer result = map.Create(); + result.ReadFromArray(data); + return result; + } + + public uint calculateFileSize() + { + uint totalLen = 0; + foreach (LightWeightMapBuffer map in _maps) + totalLen += PacketSize(map); + if (cr != null) + { + foreach (LightWeightMapBuffer map in cr.Maps) + totalLen += PacketSize(map); + } + return totalLen; + } + + private static uint PacketSize(LightWeightMapBuffer map) + => map != null && map.GetCount() != 0 ? map.CalculateArraySize() + PacketOverhead : 0; + + public uint calculateRawFileSize() => HeaderSize + calculateFileSize() + TrailerSize; + + public byte[] Serialize() + { + uint totalLen = calculateFileSize(); + byte[] buff2 = new byte[HeaderSize + totalLen + TrailerSize]; + int buffIndex = 0; + buff2[buffIndex++] = (byte)'m'; + buff2[buffIndex++] = (byte)'c'; + BinaryPrimitives.WriteUInt32LittleEndian(buff2.AsSpan(buffIndex), totalLen); + buffIndex += sizeof(uint); + + for (int i = 0; i < _maps.Length; i++) + buffIndex = WritePacket(buff2, buffIndex, s_maps[i].Packet, _maps[i]); + + if (cr != null) + { + LightWeightMapBuffer[] crMaps = cr.Maps; + for (int i = 0; i < crMaps.Length; i++) + buffIndex = WritePacket(buff2, buffIndex, CompileResult.s_maps[i].Packet, crMaps[i]); + } + + buff2[buffIndex++] = (byte)'4'; + buff2[buffIndex++] = (byte)'2'; + ErrorHandling.AssertCode(buffIndex == buff2.Length, ExceptionCodes.ASSERT, "buffIndex == totalFileSize"); + return buff2; + } + + private static int WritePacket(byte[] buff2, int buffIndex, PacketId packet, LightWeightMapBuffer map) + { + if (map == null || map.GetCount() == 0) + return buffIndex; + + buff2[buffIndex++] = (byte)packet; + uint loc = map.DumpToArray(buff2.AsSpan(buffIndex + sizeof(uint))); + BinaryPrimitives.WriteUInt32LittleEndian(buff2.AsSpan(buffIndex), loc); + buffIndex += sizeof(uint) + (int)loc; + buff2[buffIndex++] = PacketCanary; + return buffIndex; + } + + public uint saveToFile(Stream stream) + { + byte[] data = Serialize(); + stream.Write(data); + return (uint)data.Length; + } + + // Statistics about each map: count of elements and total serialized size, as CSV columns. + public void dumpStatToBuffer(StringBuilder sb) + { + foreach (LightWeightMapBuffer map in _maps) + DumpStat(sb, map); + foreach (LightWeightMapBuffer map in cr.Maps) + DumpStat(sb, map); + } + + private static void DumpStat(StringBuilder sb, LightWeightMapBuffer map) + { + if (map != null && map.GetCount() > 0) + sb.Append(map.GetCount()); + sb.Append(','); + if (map != null) + sb.Append(map.CalculateArraySize()); + sb.Append(','); + } + + public static void dumpStatTitleToBuffer(StringBuilder sb) + { + foreach (MapInfo map in s_maps) + sb.Append(map.Name).Append(',').Append(map.Name).Append(" SZ,"); + foreach (MapInfo map in CompileResult.s_maps) + sb.Append("CR_").Append(map.Name).Append(",CR_").Append(map.Name).Append(" SZ,"); + } +} diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContextIterator.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContextIterator.cs new file mode 100644 index 00000000000000..a007f87fa3020e --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContextIterator.cs @@ -0,0 +1,117 @@ +// 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.Diagnostics; +using System.IO; + +namespace SuperPmi; + +// Iterates sequentially over the method contexts of a file, optionally only the given sorted indexes. +public sealed class MethodContextIterator : IDisposable +{ + private const int ProgressRate = 1000; + + private readonly int[] m_indexes; // null means all method contexts + private readonly bool m_progressReport; + private readonly Stopwatch m_timer = new Stopwatch(); + private FileStream m_hFile; + private long m_fileSize; + private int m_index; + + public MethodContextIterator(bool progressReport = false) + : this(null, progressReport) + { + } + + public MethodContextIterator(int[] indexes, bool progressReport = false) + { + m_indexes = indexes; + m_progressReport = progressReport; + } + + public MethodContext Current { get; private set; } + + // The file offset of the current method context. + public long CurrentPos { get; private set; } + + public int MethodContextNumber { get; private set; } + + public bool Initialize(string fileName) + { + try + { + m_hFile = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read, 1 << 20, FileOptions.SequentialScan); + m_fileSize = m_hFile.Length; + } + catch (Exception e) when (e is IOException or UnauthorizedAccessException) + { + Logger.LogError($"Failed to open file '{fileName}'. GetLastError()={ErrorHandling.LastError(e)}"); + return false; + } + + if (m_progressReport) + m_timer.Start(); + return true; + } + + // Gives the current method context to the caller; the iterator no longer refers to it. + public MethodContext CurrentTakeOwnership() + { + MethodContext ret = Current; + Current = null; + return ret; + } + + public bool MoveNext() + { + Current = null; + + while (true) + { + CurrentPos = m_hFile.Position; + if (CurrentPos >= m_fileSize) + return false; + + MethodContextNumber++; + + if (m_progressReport && (MethodContextNumber % ProgressRate) == 0) + { + Logger.LogVerbose($"Loaded {MethodContextNumber} at {(int)(ProgressRate / m_timer.Elapsed.TotalSeconds)} per second"); + m_timer.Restart(); + } + + if (!MethodContext.Initialize(MethodContextNumber, m_hFile, readCompileResults: true, out MethodContext mc)) + return false; + Current = mc; + + if (m_indexes == null) + break; + if (m_index == m_indexes.Length) + return false; // beyond the list of indexes + if (m_indexes[m_index] == MethodContextNumber) + { + m_index++; + break; + } + } + + return true; + } + + // Returns false if closing the file failed. + public bool Destroy() + { + m_hFile?.Dispose(); + m_hFile = null; + Current = null; + + if (m_indexes != null && m_index < m_indexes.Length) + { + Logger.LogWarning($"Didn't use all of index count input: {m_index} < {m_indexes.Length} (i.e., didn't see MC #{m_indexes[m_index]})"); + } + return true; + } + + public void Dispose() => Destroy(); +} diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContextReader.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContextReader.cs new file mode 100644 index 00000000000000..1ebb1027b7ef42 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContextReader.cs @@ -0,0 +1,376 @@ +// 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.Buffers.Binary; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace SuperPmi; + +// The raw bytes of one method context: 'size' bytes of packet data followed by the 2-byte end canary. +// Without a buffer, the size is 0 for a skipped method context, Completed when all are done, or else an error code. +public readonly struct MethodContextBuffer +{ + private const int Completed = 0x1234abcd; + + public static MethodContextBuffer Done => new MethodContextBuffer(Completed); + + public readonly byte[] buff; + public readonly int size; + + public MethodContextBuffer(byte[] buff, int size) + { + this.buff = buff; + this.size = size; + } + + public MethodContextBuffer(int error) + { + buff = null; + size = error; + } + + public bool allDone() => size == Completed && buff == null; + + public bool Error() => size != 0 && size != Completed && buff == null; +} + +// Reads method contexts from an .mch file, optionally restricted to a list of indexes, a hash, +// or an offset/increment combination, using the paired .mct table of contents when there is one. +public sealed class MethodContextReader : IDisposable +{ + private readonly object _lock = new object(); + private readonly FileStream fileHandle; + private readonly long fileSize; + private readonly TOCFile tocFile = new TOCFile(); + private int[] Indexes; + private readonly string Hash; + private readonly int Offset; + private readonly int Increment; + private HashSet excludedMethods; + + private int curMCIndex; + private int curIndexPos; + private int curTOCIndex; + + public MethodContextReader(string inputFileName, int[] indexes = null, string hash = null, int offset = -1, int increment = -1) + { + Indexes = indexes; + Hash = hash; + Offset = offset; + Increment = increment; + + string mchFileName; + string tocFileName = CheckForPairedFile(inputFileName, ".mch", ".mct"); + if (tocFileName != null) + { + mchFileName = inputFileName; + } + else + { + mchFileName = CheckForPairedFile(inputFileName, ".mct", ".mch"); + if (mchFileName != null) + tocFileName = inputFileName; + else + mchFileName = inputFileName; + } + + if (tocFileName != null) + tocFile.LoadToc(tocFileName); + + try + { + FileOptions options = hasTOC() && hasIndex() ? FileOptions.None : FileOptions.SequentialScan; + fileHandle = new FileStream(mchFileName, FileMode.Open, FileAccess.Read, FileShare.Read, 1 << 16, options); + fileSize = fileHandle.Length; + } + catch (Exception e) when (e is IOException or UnauthorizedAccessException) + { + Logger.LogError($"Failed to open file '{mchFileName}'. GetLastError()={ErrorHandling.LastError(e)}"); + } + + ReadExcludedMethods(mchFileName); + } + + public void Dispose() => fileHandle?.Dispose(); + + public bool isValid() => fileHandle != null; + + public bool hasIndex() => Indexes != null && Indexes.Length > 0; + + public bool hasTOC() => tocFile.GetTocCount() > 0; + + public int GetMethodContextIndex() => curMCIndex; + + private static bool IsRegularFile(string path) => File.Exists(path); + + // Looks for foo.origSuffix.newSuffix or foo.newSuffix, but only if foo.origSuffix exists. + public static string CheckForPairedFile(string fileName, string origSuffix, string newSuffix) + { + int suffixOffset = fileName.LastIndexOf('.'); + if (suffixOffset <= 0 || !string.Equals(fileName.Substring(suffixOffset), origSuffix, StringComparison.OrdinalIgnoreCase)) + return null; + + if (!IsRegularFile(fileName)) + return null; + + string tmp = fileName + newSuffix; + if (IsRegularFile(tmp)) + return tmp; + + tmp = fileName.Substring(0, suffixOffset) + newSuffix; + if (IsRegularFile(tmp)) + return tmp; + + return null; + } + + private bool atEof() => fileHandle.Position == fileSize; + + private MethodContextBuffer ReadMethodContextNoLock(bool justSkip) + { + if (atEof()) + return MethodContextBuffer.Done; + + Span header = stackalloc byte[6]; + ErrorHandling.AssertMsg(fileHandle.ReadAtLeast(header, header.Length, throwOnEndOfStream: false) == header.Length, + "ReadFile(...) == TRUE", "Truncated method context header"); + ErrorHandling.AssertMsg(header[0] == 'm' && header[1] == 'c', "(buff[0] == 'm') && (buff[1] == 'c')", "Didn't find magic number"); + uint totalLen = BinaryPrimitives.ReadUInt32LittleEndian(header.Slice(2)); + + curMCIndex++; + if (justSkip) + { + fileHandle.Seek(totalLen + 2, SeekOrigin.Current); + return new MethodContextBuffer(0); + } + + byte[] buff2 = new byte[(long)totalLen + 2]; + fileHandle.ReadAtLeast(buff2, buff2.Length, throwOnEndOfStream: false); + return new MethodContextBuffer(buff2, (int)totalLen); + } + + private MethodContextBuffer ReadMethodContext(bool justSkip = false) + { + lock (_lock) + { + return ReadMethodContextNoLock(justSkip); + } + } + + public MethodContextBuffer GetNextMethodContext() + { + try + { + return GetNextMethodContextHelper(); + } + catch (SpmiException) + { + Logger.LogError($"Method {GetMethodContextIndex()} is of low integrity."); + return new MethodContextBuffer(-1); + } + } + + private MethodContextBuffer GetNextMethodContextHelper() + { + if (Offset > 0 && Increment > 0) + return GetNextMethodContextFromOffsetIncrement(); + + if (hasIndex()) + { + if (curIndexPos < Indexes.Length) + return GetNextMethodContextFromIndexes(); + return MethodContextBuffer.Done; + } + + if (Hash != null) + return GetNextMethodContextFromHash(); + + return ReadMethodContext(); + } + + private MethodContextBuffer GetNextMethodContextFromIndexes() + { + if (hasTOC()) + return GetSpecificMethodContext(Indexes[curIndexPos++]); + + int curMethod = curIndexPos != 0 ? Indexes[curIndexPos - 1] : 0; + int nextMethod = Indexes[curIndexPos++]; + while (++curMethod < nextMethod) + { + MethodContextBuffer mcb = ReadMethodContext(justSkip: true); + if (mcb.allDone() || mcb.Error()) + return mcb; + } + return ReadMethodContext(); + } + + private MethodContextBuffer GetNextMethodContextFromHash() + { + if (hasTOC()) + { + for (; curTOCIndex < tocFile.GetTocCount(); curTOCIndex++) + { + TOCElement element = tocFile.GetElement(curTOCIndex); + if (string.Equals(Hash, element.HashString, StringComparison.OrdinalIgnoreCase)) + { + curTOCIndex++; + return GetSpecificMethodContext(element.Number); + } + } + return MethodContextBuffer.Done; + } + + while (true) + { + MethodContextBuffer mcb = ReadMethodContext(); + if (mcb.allDone() || mcb.Error()) + return mcb; + + if (!MethodContext.Initialize(-1, mcb.buff, (uint)mcb.size, readCompileResults: true, out MethodContext mc)) + return new MethodContextBuffer(-1); + + if (string.Equals(Hash, mc.dumpMethodHashToBuffer(), StringComparison.OrdinalIgnoreCase)) + return mcb; + } + } + + private MethodContextBuffer GetNextMethodContextFromOffsetIncrement() + { + int methodNumber = curMCIndex > 0 ? curMCIndex + Increment : Offset; + + if (hasTOC()) + { + if (tocFile.GetTocCount() >= methodNumber) + return GetSpecificMethodContext(methodNumber); + return MethodContextBuffer.Done; + } + + while (curMCIndex + 1 < methodNumber) + { + MethodContextBuffer mcb = ReadMethodContext(justSkip: true); + if (mcb.allDone() || mcb.Error()) + return mcb; + } + return ReadMethodContext(); + } + + // Progress through the method contexts, compared against TotalWork(): the index position with + // an index list, the method context number with a TOC, or else the byte offset in the file. + public double Progress() + { + if (hasIndex()) + return curIndexPos; + if (hasTOC()) + return curMCIndex; + lock (_lock) + { + return fileHandle.Position; + } + } + + public double TotalWork() + { + if (hasIndex()) + return Indexes.Length; + if (hasTOC()) + return tocFile.GetTocCount(); + return fileSize; + } + + public double PercentComplete() => 100.0 * Progress() / TotalWork(); + + // Note that the TOC is 0-based and method context numbers are 1-based. + // Returns -1 for not found, or -2 for not indexed. + private long GetOffset(int methodNumber) + { + if (!hasTOC()) + return -2; + + int low = 0; + int high = tocFile.GetTocCount() - 1; + while (low <= high) + { + int pos = (high + low) / 2; + TOCElement element = tocFile.GetElement(pos); + if (element.Number == methodNumber) + return element.Offset; + if (element.Number > methodNumber) + high = pos - 1; + else + low = pos + 1; + } + return -1; + } + + public MethodContextBuffer GetSpecificMethodContext(int methodNumber) + { + long pos = GetOffset(methodNumber); + if (pos < 0) + return new MethodContextBuffer(-3); + + lock (_lock) + { + fileHandle.Seek(pos, SeekOrigin.Begin); + MethodContextBuffer mcb = ReadMethodContextNoLock(justSkip: false); + curMCIndex = methodNumber; + return mcb; + } + } + + // Reads the hashes of methods to exclude from a paired .exc file, if there is one. + private void ReadExcludedMethods(string mchFileName) + { + int suffixOffset = mchFileName.LastIndexOf('.'); + if (suffixOffset < 0) + { + Logger.LogError($"Failed to get file extension from {mchFileName}"); + return; + } + + string excludeFileName = CheckForPairedFile(mchFileName, mchFileName.Substring(suffixOffset), ".exc"); + if (excludeFileName == null) + return; + + string text; + try + { + text = File.ReadAllText(excludeFileName, Encoding.ASCII); + } + catch (Exception e) when (e is IOException or UnauthorizedAccessException) + { + Logger.LogError($"Failed to open file '{excludeFileName}'. GetLastError()={ErrorHandling.LastError(e)}"); + return; + } + + excludedMethods = new HashSet(StringComparer.Ordinal); + int counter = 0; + foreach (string hash in text.Split((char[])null, StringSplitOptions.RemoveEmptyEntries)) + { + if (hash.Length == SuperPmi.Hash.MM3_HASH_BUFFER_SIZE - 1) + { + excludedMethods.Add(hash); + counter++; + } + else + { + Logger.LogInfo($"The exclude file contains wrong values: {hash}."); + } + } + Logger.LogInfo($"Exclude file {excludeFileName} contains {counter} methods."); + } + + public bool IsMethodExcluded(MethodContext mc) + => excludedMethods != null && excludedMethods.Contains(mc.dumpMethodHashToBuffer()); + + public void Reset(int[] newIndexes) + { + fileHandle.Seek(0, SeekOrigin.Begin); + Indexes = newIndexes; + curIndexPos = 0; + curMCIndex = 0; + curTOCIndex = 0; + } +} diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/PacketId.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/PacketId.cs new file mode 100644 index 00000000000000..b3b63eae5fd4fe --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/PacketId.cs @@ -0,0 +1,200 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// The IDs of the packets of the .mc format. The values are part of the format: don't change or reuse them. + +namespace SuperPmi; + +public enum PacketId : byte +{ + AsCorInfoType = 2, + CanAccessClass = 3, + CanCast = 5, + PrintMethodName = 6, + CanGetCookieForPInvokeCalliSig = 7, + CanGetVarArgsHandle = 8, + CanInline = 9, + PrintFieldName = 10, + CanTailCall = 12, + ConstructStringLiteral = 15, + EmbedClassHandle = 16, + EmbedFieldHandle = 17, + EmbedGenericHandle = 18, + EmbedMethodHandle = 19, + EmbedModuleHandle = 20, + EmptyStringLiteral = 21, + ErrorList = 22, + FindCallSiteSig = 23, + FindSig = 25, + GetAddressOfPInvokeFixup = 26, + GetAddrOfCaptureThreadGlobal = 27, + GetArgNext = 29, + GetArrayInitializationData = 31, + GetArrayRank = 32, + GetBoundaries = 34, + GetBoxHelper = 35, + GetBuiltinClass = 36, + GetCallInfo = 37, + GetCastingHelper = 38, + GetChildType = 39, + GetClassAlignmentRequirement = 40, + GetClassAttribs = 41, + GetClassGClayout = 43, + GetClassModuleIdForStatics = 44, + GetClassName = 45, + GetClassNumInstanceFields = 46, + GetClassSize = 47, + GetCookieForPInvokeCalliSig = 48, + GetDelegateCtor = 49, + GetEEInfo = 50, + GetEHinfo = 51, + GetFieldClass = 53, + GetFieldInClass = 54, + GetFieldInfo = 55, + GetFieldOffset = 57, + GetFieldThreadLocalStoreID = 58, + GetFieldType = 59, + GetFunctionEntryPoint = 60, + GetFunctionFixedEntryPoint = 61, + GetGSCookie = 62, + GetArrayIntrinsicID = 66, + GetJustMyCodeHandle = 68, + GetLocationOfThisType = 69, + GetMethodAttribs = 70, + GetMethodClass = 71, + GetMethodDefFromMethod = 72, + GetMethodHash = 73, + GetMethodInfo = 74, + GetMethodSig = 76, + GetMethodVTableOffset = 78, + GetNewArrHelper = 79, + GetNewHelper = 80, + GetParentType = 81, + GetProfilingHandle = 83, + GetRelocTypeHint = 84, + GetSharedCCtorHelper = 86, + GetThreadTLSIndex = 88, + GetTokenTypeAsHandle = 89, + GetTypeForBox = 90, + GetTypeForPrimitiveValueClass = 91, + GetUnBoxHelper = 92, + GetUnmanagedCallConv = 94, + GetVarArgsHandle = 95, + GetVars = 96, + InitClass = 97, + IsSDArray = 101, + IsValidStringRef = 103, + IsValueClass = 105, + PInvokeMarshalingRequired = 108, + ResolveToken = 109, + SatisfiesMethodConstraints = 111, + DoesFieldBelongToClass = 112, + CR_AllocGCInfo = 114, + CR_AllocMem = 115, + CR_CallLog = 116, + CR_CompileMethod = 118, + CR_MessageLog = 119, + CR_ProcessName = 121, + CR_RecordRelocation = 122, + CR_ReportFatalError = 123, + CR_ReportInliningDecision = 124, + CR_ReportTailCallDecision = 125, + CR_SetBoundaries = 126, + CR_SetEHcount = 127, + CR_SetEHinfo = 128, + CR_SetMethodAttribs = 129, + CR_SetVars = 130, + CR_AllocUnwindInfo = 132, + CR_ReserveUnwindInfo = 133, + IsFieldStatic = 137, + CR_AssertLog = 138, + GetArgClass = 139, + GetArgType = 140, + CheckMethodModifier = 142, + CompileMethod = 143, + IsIntrinsicType = 148, + PrintClassName = 149, + GetReadyToRunHelper = 150, + GetIntConfigValue = 151, + GetStringConfigValue = 152, + GetAddressOfPInvokeTarget = 153, + GetJitFlags = 154, + IsDelegateCreationAllowed = 155, + GetSystemVAmd64PassStructInRegisterDescriptor = 156, + GetReadyToRunDelegateCtorHelper = 157, + GetHFAType = 159, + ResolveVirtualMethod = 160, + GetMethodNameFromMetadata = 161, + GetDefaultEqualityComparerClass = 162, + CompareTypesForCast = 163, + CompareTypesForEquality = 164, + GetClassNameFromMetadata = 166, + GetTypeInstantiationArgument = 167, + GetTypeForPrimitiveNumericClass = 168, + ConvertPInvokeCalliToCall = 169, + GetHeapClassSize = 170, + CanAllocateOnStack = 171, + GetStaticFieldCurrentClass = 172, + IsMoreSpecificType = 174, + GetStringLiteral = 175, + CR_SetPatchpointInfo = 176, + GetOSRInfo = 177, + GetTailCallHelpers = 178, + CR_RecordCallSiteWithSignature = 179, + CR_RecordCallSiteWithoutSignature = 180, + GetExpectedTargetArchitecture = 183, + SigInstHandleMap = 184, + CR_CrSigInstHandleMap = 185, + AllocPgoInstrumentationBySchema = 186, + GetPgoInstrumentationResults = 187, + GetDefaultComparerClass = 188, + IsIntrinsic = 192, + UpdateEntryPointForTailCall = 193, + GetExactClasses = 195, + GetRuntimeTypePointer = 196, + PrintObjectDescription = 197, + GetStaticFieldContent = 198, + GetObjectType = 199, + IsObjectImmutable = 200, + ExpandRawHandleIntrinsic = 201, + GetArrayOrStringLength = 202, + IsEnum = 203, + GetStringChar = 204, + GetIsClassInitedFlagAddress = 205, + GetStaticBaseAddress = 206, + GetThreadLocalFieldInfo = 207, + GetThreadLocalStaticBlocksInfo = 208, + GetThreadLocalStaticInfo_NativeAOT = 209, + GetObjectContent = 211, + GetTypeLayout = 212, + HaveSameMethodDefinition = 213, + NotifyMethodInfoUsage = 214, + IsExactType = 215, + GetSwiftLowering = 216, + IsNullableType = 217, + GetClassStaticDynamicInfo = 218, + GetClassThreadStaticDynamicInfo = 219, + IsGenericType = 220, + GetTypeDefinition = 222, + GetFpStructLowering = 223, + GetSpecialCopyHelper = 224, + GetClassAssemblyName = 225, + GetSZArrayHelperEnumeratorClass = 226, + GetMethodInstantiationArgument = 227, + NotifyInstructionSetUsage = 229, + GetAsyncInfo = 230, + GetAsyncResumptionStub = 231, + GetCookieForInterpreterCalliSig = 232, + GetHelperFtn = 233, + GetContinuationType = 234, + GetWasmTypeSymbol = 235, + GetWasmLowering = 236, + GetAsyncOtherVariant = 237, + GetAwaitReturnCall = 238, + GetAddressAlignment = 239, + GetWasmWellKnownGlobals = 240, + CanValueClassInstancePointerEscape = 241, + GetAwaitAwaiterInContinuationCall = 242, + IsByRefLike = 243, + IsSharedInst = 244, +} diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/PinnedArena.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/PinnedArena.cs new file mode 100644 index 00000000000000..f88d89c048f353 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/PinnedArena.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. + +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SuperPmi; + +// A bump allocator over pinned arrays, for memory that is handed to the JIT. The memory is zeroed, +// and stays valid for as long as the arena is alive. +public sealed unsafe class PinnedArena +{ + private const int ChunkSize = 64 * 1024; + + private readonly List _chunks = []; + private nuint _next; + private nuint _end; + + public void* Allocate(nuint size, nuint alignment = 8) + { + nuint start = AlignUp(_next, alignment); + if (_next == 0 || start + size > _end) + { + byte[] chunk = GC.AllocateArray((int)Math.Max(ChunkSize, size + alignment), pinned: true); + _chunks.Add(chunk); + _next = (nuint)Unsafe.AsPointer(ref MemoryMarshal.GetArrayDataReference(chunk)); + _end = _next + (nuint)chunk.Length; + start = AlignUp(_next, alignment); + } + + _next = start + size; + return (void*)start; + } + + public T* Allocate(nuint count = 1) where T : unmanaged => (T*)Allocate((nuint)sizeof(T) * count, (nuint)Math.Min(sizeof(T), 8)); + + public byte* Copy(ReadOnlySpan data) + { + byte* result = (byte*)Allocate((nuint)data.Length, 1); + data.CopyTo(new Span(result, data.Length)); + return result; + } + + private static nuint AlignUp(nuint value, nuint alignment) => (value + alignment - 1) & ~(alignment - 1); +} diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/SpmiDumpHelper.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/SpmiDumpHelper.cs new file mode 100644 index 00000000000000..1a2ab2f1e13de5 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/SpmiDumpHelper.cs @@ -0,0 +1,357 @@ +// 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.Text; +using Internal.JitInterface; +using Internal.Pgo; + +namespace SuperPmi; + +// Unused high JIT flag bits that the tools co-opt to note what PGO data a method context has. +public static class ExtraJitFlags +{ + public const int HAS_PGO = 63; + public const int HAS_EDGE_PROFILE = 62; + public const int HAS_CLASS_PROFILE = 61; + public const int HAS_LIKELY_CLASS = 60; + public const int HAS_STATIC_PROFILE = 59; + public const int HAS_DYNAMIC_PROFILE = 58; + public const int HAS_METHOD_PROFILE = 57; + public const int HAS_LIKELY_METHOD = 56; + + // The raw JIT flags plus the PGO pseudo-flags. + public static ulong GetFlagsWithPgo(MethodContext mc) + { + ulong rawFlags = mc.repGetJitFlags().JitFlags; + + if (mc.hasPgoData(out bool hasEdgeProfile, out bool hasClassProfile, out bool hasMethodProfile, out bool hasLikelyClass, + out bool hasLikelyMethod, out PgoSource pgoSource)) + { + rawFlags |= 1UL << HAS_PGO; + if (hasEdgeProfile) + rawFlags |= 1UL << HAS_EDGE_PROFILE; + if (hasClassProfile) + rawFlags |= 1UL << HAS_CLASS_PROFILE; + if (hasMethodProfile) + rawFlags |= 1UL << HAS_METHOD_PROFILE; + if (hasLikelyClass) + rawFlags |= 1UL << HAS_LIKELY_CLASS; + if (hasLikelyMethod) + rawFlags |= 1UL << HAS_LIKELY_METHOD; + if (pgoSource == PgoSource.Static) + rawFlags |= 1UL << HAS_STATIC_PROFILE; + if (pgoSource == PgoSource.Dynamic) + rawFlags |= 1UL << HAS_DYNAMIC_PROFILE; + } + + return rawFlags; + } +} + +// Formats the structs used in JIT-EE interface calls and SuperPMI collections. +public static class SpmiDumpHelper +{ + private const int MaxSigDisplayBytes = 25; + private const int MaxHandleArrayDisplayElems = 5; + + public static string DumpAgnostic_CORINFO_RESOLVED_TOKENin(in Agnostic_CORINFO_RESOLVED_TOKENin tokenIn) + => CFormat.Sprintf("tc-%016llX ts-%016llX tok-%08X tt-%u", tokenIn.tokenContext, tokenIn.tokenScope, tokenIn.token, tokenIn.tokenType); + + public static string DumpAgnostic_CORINFO_RESOLVED_TOKENout(in Agnostic_CORINFO_RESOLVED_TOKENout tokenOut) + => CFormat.Sprintf("cls-%016llX meth-%016llX fld-%016llX ti-%u ts-%u mi-%u ms-%u", tokenOut.hClass, tokenOut.hMethod, tokenOut.hField, + tokenOut.pTypeSpec_Index, tokenOut.cbTypeSpec, tokenOut.pMethodSpec_Index, tokenOut.cbMethodSpec); + + public static string DumpAgnostic_CORINFO_RESOLVED_TOKEN(in Agnostic_CORINFO_RESOLVED_TOKEN token) + => DumpAgnostic_CORINFO_RESOLVED_TOKENin(token.inValue) + " " + DumpAgnostic_CORINFO_RESOLVED_TOKENout(token.outValue); + + public static string DumpAgnostic_CORINFO_LOOKUP_KIND(in Agnostic_CORINFO_LOOKUP_KIND lookupKind) + => CFormat.Sprintf("nrl-%u rlk-%u", lookupKind.needsRuntimeLookup, lookupKind.runtimeLookupKind); + + public static string DumpAgnostic_CORINFO_CONST_LOOKUP(in Agnostic_CORINFO_CONST_LOOKUP constLookup) + => CFormat.Sprintf("at-%u handle/address-%016llX", constLookup.accessType, constLookup.handle); + + public static string DumpAgnostic_CORINFO_RUNTIME_LOOKUP(in Agnostic_CORINFO_RUNTIME_LOOKUP lookup) + { + var sb = new StringBuilder(CFormat.Sprintf(" sig-%016llX hlp-%u ind-%u tfn-%u so-%u { ", lookup.signature, lookup.helper, + lookup.indirections, lookup.testForNull, lookup.sizeOffset)); + foreach (ulong offset in lookup.offsets) + sb.Append(CFormat.Sprintf("%016llX ", offset)); + sb.Append('}'); + return sb.ToString(); + } + + public static string DumpAgnostic_CORINFO_LOOKUP(in Agnostic_CORINFO_LOOKUP lookup) + { + string kind = DumpAgnostic_CORINFO_LOOKUP_KIND(lookup.lookupKind); + string description = lookup.lookupKind.needsRuntimeLookup != 0 + ? DumpAgnostic_CORINFO_RUNTIME_LOOKUP(lookup.runtimeLookup) + : DumpAgnostic_CORINFO_CONST_LOOKUP(lookup.constLookup); + return kind + " " + description; + } + + public static string DumpPSig(uint pSig_Index, uint cbSig, LightWeightMap buffers) + where TKey : unmanaged + where TItem : unmanaged + { + var sb = new StringBuilder(CFormat.Sprintf("cbSig-%u, si-%08X", cbSig, pSig_Index)); + + // pSig_Index is usually -1 without a signature, but can be 0 in error cases where it is never + // consulted, so only look at the buffer when there is a size. + if (cbSig == 0) + { + sb.Append(" (SIG SIZE ZERO)"); + } + else + { + ReadOnlySpan pSig = buffers.GetBuffer(pSig_Index); + if (pSig_Index == uint.MaxValue) + { + sb.Append(" (NO SIG FOUND)"); + } + else + { + sb.Append(" sig-{"); + int displayBytes = (int)Math.Min(MaxSigDisplayBytes, cbSig); + for (int i = 0; i < displayBytes; i++) + { + if (i > 0) + sb.Append(' '); + sb.Append(pSig[i].ToString("X2")); + } + if (displayBytes < cbSig) + sb.Append("..."); + sb.Append('}'); + } + buffers.Unlock(); + } + + return sb.ToString(); + } + + public static string DumpAgnostic_CORINFO_SIG_INFO(in Agnostic_CORINFO_SIG_INFO sigInfo, LightWeightMap buffers, + DenseLightWeightMap handleMap) + where TKey : unmanaged + where TItem : unmanaged + { + var sb = new StringBuilder(CFormat.Sprintf("{callConv-%08X retTypeClass-%016llX retTypeSigClass-%016llX retType-%08X(%s) flg-%08X na-%u", + sigInfo.callConv, sigInfo.retTypeClass, sigInfo.retTypeSigClass, sigInfo.retType, DumpStrings.toString_CorInfoType(sigInfo.retType), + sigInfo.flags, sigInfo.numArgs)); + FormatAgnostic_CORINFO_SIG_INST_Element(sb, " ", "cc", "ci", sigInfo.sigInst_classInstCount, sigInfo.sigInst_classInst_Index, handleMap); + FormatAgnostic_CORINFO_SIG_INST_Element(sb, " ", "mc", "mi", sigInfo.sigInst_methInstCount, sigInfo.sigInst_methInst_Index, handleMap); + sb.Append(CFormat.Sprintf(" args-%016llX sig-%s msig-%016llX scp-%016llX tok-%08X}", sigInfo.args, + DumpPSig(sigInfo.pSig_Index, sigInfo.cbSig, buffers), sigInfo.methodSignature, sigInfo.scope, sigInfo.token)); + return sb.ToString(); + } + + public static string DumpAgnostic_CORINFO_SIG_INST_Element(string prefixStr, string instCountPrefixStr, string instIndexPrefixStr, + uint handleInstCount, uint handleInstIndex, DenseLightWeightMap handleMap) + { + var sb = new StringBuilder(); + FormatAgnostic_CORINFO_SIG_INST_Element(sb, prefixStr, instCountPrefixStr, instIndexPrefixStr, handleInstCount, handleInstIndex, handleMap); + return sb.ToString(); + } + + private static void FormatAgnostic_CORINFO_SIG_INST_Element(StringBuilder sb, string prefixStr, string instCountPrefixStr, + string instIndexPrefixStr, uint handleInstCount, uint handleInstIndex, DenseLightWeightMap handleMap) + { + sb.Append(CFormat.Sprintf("%s%s-%u %s-%u ", prefixStr, instCountPrefixStr, handleInstCount, instIndexPrefixStr, handleInstIndex)); + FormatHandleArray(sb, handleMap, handleInstCount, handleInstIndex); + } + + // The consecutive elements of a handle map, assumed to be an array of handles. + private static void FormatHandleArray(StringBuilder sb, DenseLightWeightMap map, uint count, uint startIndex) + { + sb.Append('{'); + uint displayElems = Math.Min(MaxHandleArrayDisplayElems, count); + for (uint i = startIndex; i < startIndex + displayElems; i++) + sb.Append(CFormat.Sprintf("%s%016llX", i == startIndex ? "" : " ", map.Get(i))); + if (displayElems < count) + sb.Append(" ..."); + sb.Append('}'); + } + + private static readonly (string Name, uint Value)[] s_corInfoFlags = + [ + ("CORINFO_FLG_STATIC", 0x00000008), + ("CORINFO_FLG_FINAL", 0x00000010), + ("CORINFO_FLG_SYNCH", 0x00000020), + ("CORINFO_FLG_VIRTUAL", 0x00000040), + ("CORINFO_FLG_INTRINSIC_TYPE", 0x00000200), + ("CORINFO_FLG_ABSTRACT", 0x00000400), + ("CORINFO_FLG_EnC", 0x00000800), + ("CORINFO_FLG_FORCEINLINE", 0x00010000), + ("CORINFO_FLG_SHAREDINST", 0x00020000), + ("CORINFO_FLG_DELEGATE_INVOKE", 0x00040000), + ("CORINFO_FLG_PINVOKE", 0x00080000), + ("CORINFO_FLG_NOGCCHECK", 0x00200000), + ("CORINFO_FLG_INTRINSIC", 0x00400000), + ("CORINFO_FLG_CONSTRUCTOR", 0x00800000), + ("CORINFO_FLG_AGGRESSIVE_OPT", 0x01000000), + ("CORINFO_FLG_DISABLE_TIER0_FOR_LOOPS", 0x02000000), + ("CORINFO_FLG_DONT_INLINE", 0x10000000), + ("CORINFO_FLG_DONT_INLINE_CALLER", 0x20000000), + ("CORINFO_FLG_VALUECLASS", 0x00010000), + ("CORINFO_FLG_VAROBJSIZE", 0x00040000), + ("CORINFO_FLG_ARRAY", 0x00080000), + ("CORINFO_FLG_OVERLAPPING_FIELDS", 0x00100000), + ("CORINFO_FLG_INTERFACE", 0x00200000), + ("CORINFO_FLG_CONTAINS_GC_PTR", 0x01000000), + ("CORINFO_FLG_DELEGATE", 0x02000000), + ("CORINFO_FLG_BYREF_LIKE", 0x08000000), + ("CORINFO_FLG_BEFOREFIELDINIT", 0x20000000), + ("CORINFO_FLG_GENERIC_TYPE_VARIABLE", 0x40000000), + ("CORINFO_FLG_UNSAFE_VALUECLASS", 0x80000000), + ]; + + // Method and class flags share bit values, so each set bit is named by its first entry. + public static string DumpCorInfoFlag(uint flags) + { + var s = new StringBuilder(); + foreach ((string name, uint value) in s_corInfoFlags) + { + if ((flags & value) != 0) + { + s.Append(' ').Append(name); + flags &= ~value; + } + } + if (flags != 0) + s.Append(CFormat.Sprintf(" Unknown flags-%08X", flags)); + return s.ToString(); + } + + // Flag names in the order they are printed. A few flags are target dependent, so they are named by + // bit number to stay target-agnostic. + private static readonly (string Name, int Bit)[] s_jitFlags = + [ + ("SPEED_OPT", 0), + ("SIZE_OPT", 1), + ("DEBUG_CODE", 2), + ("DEBUG_EnC", 3), + ("DEBUG_INFO", 4), + ("MIN_OPT", 5), + ("ENABLE_CFG", 6), + ("OSR", 7), + ("ALT_JIT", 8), + ("FROZEN_ALLOC_ALLOWED", 9), + ("PORTABLE_ENTRY_POINTS", 10), + ("AOT", 11), + ("PROF_ENTERLEAVE", 12), + ("PROF_NO_PINVOKE_INLINE", 13), + ("ASYNC", 14), + ("RELOC", 15), + ("IL_STUB", 16), + ("PROCSPLIT", 17), + ("BBINSTR", 18), + ("BBINSTR_IF_LOOPS", 19), + ("BBOPT", 20), + ("FRAMED", 21), + ("USE_PINVOKE_HELPERS", 23), + ("REVERSE_PINVOKE", 24), + ("TRACK_TRANSITIONS", 25), + ("TIER0", 26), + ("TIER1", 27), + ("NO_INLINING", 28), + ("RELATIVE_CODE_RELOCS", 29), // arm32 only + ("SOFTFP_ABI", 30), // arm32 only + ("USE_DISPATCH_HELPERS", 31), + ("WASM_MANAGED_HELPER", 33), + ("HAS_PGO", ExtraJitFlags.HAS_PGO), + ("HAS_EDGE_PROFILE", ExtraJitFlags.HAS_EDGE_PROFILE), + ("HAS_CLASS_PROFILE", ExtraJitFlags.HAS_CLASS_PROFILE), + ("HAS_METHOD_PROFILE", ExtraJitFlags.HAS_METHOD_PROFILE), + ("HAS_LIKELY_CLASS", ExtraJitFlags.HAS_LIKELY_CLASS), + ("HAS_LIKELY_METHOD", ExtraJitFlags.HAS_LIKELY_METHOD), + ("HAS_STATIC_PROFILE", ExtraJitFlags.HAS_STATIC_PROFILE), + ("HAS_DYNAMIC_PROFILE", ExtraJitFlags.HAS_DYNAMIC_PROFILE), + ]; + + public static string DumpJitFlags(ulong flags) + { + var s = new StringBuilder(); + foreach ((string name, int bit) in s_jitFlags) + { + if ((flags & (1UL << bit)) != 0) + { + s.Append(' ').Append(name); + flags &= ~(1UL << bit); + } + } + + if (flags != 0) + s.Append($" Unknown jit flags-{flags:X16}"); + + return s.ToString(); + } +} + +public static class DumpStrings +{ + public static string toString_InfoAccessType(uint iat) => iat switch + { + 0 => "VALUE", + 1 => "PVALUE", + 2 => "PPVALUE", + 3 => "RELPVALUE", + _ => "UNKNOWN", + }; + + public static string toString_CORINFO_CALL_KIND(uint kind) => kind switch + { + 0 => "CALL", + 1 => "CALL_CODE_POINTER", + 2 => "VIRTUALCALL_STUB", + 3 => "VIRTUALCALL_LDVIRTFTN", + 4 => "VIRTUALCALL_VTABLE", + _ => "UNKNOWN", + }; + + public static string toString_CorInfoType(uint type) => (CorInfoType)type switch + { + CorInfoType.CORINFO_TYPE_UNDEF => "undef", + CorInfoType.CORINFO_TYPE_VOID => "void", + CorInfoType.CORINFO_TYPE_BOOL => "bool", + CorInfoType.CORINFO_TYPE_CHAR => "char", + CorInfoType.CORINFO_TYPE_BYTE => "byte", + CorInfoType.CORINFO_TYPE_UBYTE => "ubyte", + CorInfoType.CORINFO_TYPE_SHORT => "short", + CorInfoType.CORINFO_TYPE_USHORT => "ushort", + CorInfoType.CORINFO_TYPE_INT => "int", + CorInfoType.CORINFO_TYPE_UINT => "uint", + CorInfoType.CORINFO_TYPE_LONG => "long", + CorInfoType.CORINFO_TYPE_ULONG => "ulong", + CorInfoType.CORINFO_TYPE_NATIVEINT => "nativeint", + CorInfoType.CORINFO_TYPE_NATIVEUINT => "nativeuint", + CorInfoType.CORINFO_TYPE_FLOAT => "float", + CorInfoType.CORINFO_TYPE_DOUBLE => "double", + CorInfoType.CORINFO_TYPE_CLASS => "class", + CorInfoType.CORINFO_TYPE_PTR => "ptr", + CorInfoType.CORINFO_TYPE_BYREF => "byref", + CorInfoType.CORINFO_TYPE_VALUECLASS => "valueclass", + _ => "UNKNOWN", + }; + + // Only these leading CorInfoReloc values have names in the dumps. + private static readonly string[] s_relocationTypes = + [ + "NONE", "DIRECT", "RELATIVE32", "ARM64_BRANCH26", "ARM64_PAGEBASE_REL21", "ARM64_PAGEOFFSET_12A", "ARM64_PAGEOFFSET_12L", + "ARM64_LIN_TLSDESC_ADR_PAGE21", "ARM64_LIN_TLSDESC_LD64_LO12", "ARM64_LIN_TLSDESC_ADD_LO12", "ARM64_LIN_TLSDESC_CALL", + "ARM64_WIN_TLS_SECREL_HIGH12A", "ARM64_WIN_TLS_SECREL_LOW12A", "AMD64_WIN_SECREL", "AMD64_LIN_TLSGD", "ARM32_THUMB_BRANCH24", + "ARM32_THUMB_MOV32", "ARM32_THUMB_MOV32_PCREL", "LOONGARCH64_PC", "LOONGARCH64_JIR", "RISCV64_CALL_PLT", "RISCV64_PCREL_I", + "RISCV64_PCREL_S", + ]; + + public static string relocationTypeToString(uint relocType) + => relocType < s_relocationTypes.Length ? s_relocationTypes[relocType] : "UNKNOWN"; + + public const uint CORINFO_EH_CLAUSE_NONE = 0; + public const uint CORINFO_EH_CLAUSE_FILTER = 1; + + public static string toString_CorInfoTypeWithMod(uint type) => type switch + { + (uint)CorInfoType.CORINFO_TYPE_BYREF | (uint)CorInfoTypeWithMod.CORINFO_TYPE_MOD_PINNED => "pinned byref", + (uint)CorInfoType.CORINFO_TYPE_CLASS | (uint)CorInfoTypeWithMod.CORINFO_TYPE_MOD_PINNED => "pinned class", + _ => toString_CorInfoType(type & (uint)CorInfoTypeWithMod.CORINFO_TYPE_MASK), + }; +} diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/SpmiRecordsHelper.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/SpmiRecordsHelper.cs new file mode 100644 index 00000000000000..a03d4a6792e6fe --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/SpmiRecordsHelper.cs @@ -0,0 +1,373 @@ +// 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 Internal.JitInterface; + +namespace SuperPmi; + +// Copies data between the JIT-EE interface types and their recorded (agnostic) forms. 'Store' records +// new buffers, 'Restore' finds the existing ones (for lookup keys) or turns recorded data back into +// JIT-EE types. +public static unsafe class SpmiRecordsHelper +{ + private const int CORINFO_MAXINDIRECTIONS = 4; + private const int CORINFO_ACCESS_ALLOWED_MAX_ARGS = 4; + + public static ulong CastHandle(void* h) => (ulong)h; + + public static Agnostic_CORINFO_RESOLVED_TOKENin CreateAgnostic_CORINFO_RESOLVED_TOKENin(CORINFO_RESOLVED_TOKEN* pResolvedToken) + { + var tokenIn = new Agnostic_CORINFO_RESOLVED_TOKENin(); + if (pResolvedToken != null) + { + tokenIn.tokenContext = CastHandle(pResolvedToken->tokenContext); + tokenIn.tokenScope = CastHandle(pResolvedToken->tokenScope); + tokenIn.token = (uint)pResolvedToken->token; + tokenIn.tokenType = (uint)pResolvedToken->tokenType; + } + return tokenIn; + } + + public static Agnostic_CORINFO_RESOLVED_TOKENout CreateAgnostic_CORINFO_RESOLVED_TOKENout_without_buffers(CORINFO_RESOLVED_TOKEN* pResolvedToken) + { + var tokenOut = new Agnostic_CORINFO_RESOLVED_TOKENout(); + if (pResolvedToken != null) + { + tokenOut.hClass = CastHandle(pResolvedToken->hClass); + tokenOut.hMethod = CastHandle(pResolvedToken->hMethod); + tokenOut.hField = CastHandle(pResolvedToken->hField); + tokenOut.cbTypeSpec = pResolvedToken->cbTypeSpec; + tokenOut.cbMethodSpec = pResolvedToken->cbMethodSpec; + } + tokenOut.pTypeSpec_Index = uint.MaxValue; + tokenOut.pMethodSpec_Index = uint.MaxValue; + return tokenOut; + } + + public static Agnostic_CORINFO_RESOLVED_TOKENout StoreAgnostic_CORINFO_RESOLVED_TOKENout(CORINFO_RESOLVED_TOKEN* pResolvedToken, LightWeightMapBuffer buffers) + { + Agnostic_CORINFO_RESOLVED_TOKENout tokenOut = CreateAgnostic_CORINFO_RESOLVED_TOKENout_without_buffers(pResolvedToken); + if (pResolvedToken != null) + { + tokenOut.pTypeSpec_Index = buffers.AddBuffer(Bytes(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec)); + tokenOut.pMethodSpec_Index = buffers.AddBuffer(Bytes(pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec)); + } + return tokenOut; + } + + public static Agnostic_CORINFO_RESOLVED_TOKENout RestoreAgnostic_CORINFO_RESOLVED_TOKENout(CORINFO_RESOLVED_TOKEN* pResolvedToken, LightWeightMapBuffer buffers) + { + Agnostic_CORINFO_RESOLVED_TOKENout tokenOut = CreateAgnostic_CORINFO_RESOLVED_TOKENout_without_buffers(pResolvedToken); + if (pResolvedToken != null) + { + tokenOut.pTypeSpec_Index = (uint)buffers.Contains(Bytes(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec)); + tokenOut.pMethodSpec_Index = (uint)buffers.Contains(Bytes(pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec)); + } + return tokenOut; + } + + public static Agnostic_CORINFO_RESOLVED_TOKEN StoreAgnostic_CORINFO_RESOLVED_TOKEN(CORINFO_RESOLVED_TOKEN* pResolvedToken, LightWeightMapBuffer buffers) + => new() { inValue = CreateAgnostic_CORINFO_RESOLVED_TOKENin(pResolvedToken), outValue = StoreAgnostic_CORINFO_RESOLVED_TOKENout(pResolvedToken, buffers) }; + + public static Agnostic_CORINFO_RESOLVED_TOKEN RestoreAgnostic_CORINFO_RESOLVED_TOKEN(CORINFO_RESOLVED_TOKEN* pResolvedToken, LightWeightMapBuffer buffers) + => new() { inValue = CreateAgnostic_CORINFO_RESOLVED_TOKENin(pResolvedToken), outValue = RestoreAgnostic_CORINFO_RESOLVED_TOKENout(pResolvedToken, buffers) }; + + public static CORINFO_RESOLVED_TOKEN Restore_CORINFO_RESOLVED_TOKEN(in Agnostic_CORINFO_RESOLVED_TOKEN pResolvedTokenAgnostic, LightWeightMapBuffer buffers) + { + var token = new CORINFO_RESOLVED_TOKEN + { + tokenContext = (CORINFO_CONTEXT_STRUCT*)pResolvedTokenAgnostic.inValue.tokenContext, + tokenScope = (CORINFO_MODULE_STRUCT_*)pResolvedTokenAgnostic.inValue.tokenScope, + token = (mdToken)pResolvedTokenAgnostic.inValue.token, + tokenType = (CorInfoTokenKind)pResolvedTokenAgnostic.inValue.tokenType, + }; + Restore_CORINFO_RESOLVED_TOKENout(&token, pResolvedTokenAgnostic.outValue, buffers); + return token; + } + + // Restores the out values of the token; the in values are left as they are. + public static void Restore_CORINFO_RESOLVED_TOKENout(CORINFO_RESOLVED_TOKEN* pResolvedToken, in Agnostic_CORINFO_RESOLVED_TOKENout tokenOut, LightWeightMapBuffer buffers) + { + if (pResolvedToken == null) + return; + + pResolvedToken->hClass = (CORINFO_CLASS_STRUCT_*)tokenOut.hClass; + pResolvedToken->hMethod = (CORINFO_METHOD_STRUCT_*)tokenOut.hMethod; + pResolvedToken->hField = (CORINFO_FIELD_STRUCT_*)tokenOut.hField; + pResolvedToken->pTypeSpec = buffers.GetBufferPointer(tokenOut.pTypeSpec_Index); + pResolvedToken->cbTypeSpec = tokenOut.cbTypeSpec; + pResolvedToken->pMethodSpec = buffers.GetBufferPointer(tokenOut.pMethodSpec_Index); + pResolvedToken->cbMethodSpec = tokenOut.cbMethodSpec; + } + + public static Agnostic_CORINFO_SIG_INFO CreateAgnostic_CORINFO_SIG_INFO_without_buffers(in CORINFO_SIG_INFO sigInfo) => new() + { + callConv = (uint)sigInfo.callConv, + retTypeClass = CastHandle(sigInfo.retTypeClass), + retTypeSigClass = CastHandle(sigInfo.retTypeSigClass), + retType = (uint)sigInfo.retType, + flags = (uint)sigInfo.flags, + numArgs = sigInfo.numArgs, + sigInst_classInstCount = sigInfo.sigInst.classInstCount, + sigInst_methInstCount = sigInfo.sigInst.methInstCount, + args = CastHandle(sigInfo.args), + cbSig = sigInfo.cbSig, + methodSignature = CastHandle(sigInfo.methodSignature), + scope = CastHandle(sigInfo.scope), + token = (uint)sigInfo.token, + }; + + // Appends the handles to 'handleMap' (creating it if needed), unless the same sequence is already there. + public static void StoreAgnostic_CORINFO_SIG_INST_HandleArray(uint handleInstCount, CORINFO_CLASS_STRUCT_** handleInstArray, + ref DenseLightWeightMap handleMap, out uint handleInstCountOut, out uint handleInstIndexOut) + { + uint handleInstIndex; + + // Checking handleInstArray shouldn't be needed, but crossgen2 often sets (leaves?) + // handleInstCount > 0 with handleInstArray == null. + if (handleInstCount > 0 && handleInstArray != null) + { + handleMap ??= new DenseLightWeightMap(); + + // Reuse an existing copy of the array, so that replay finds the same index. This also keeps the + // handle map small, since there are typically few unique handle arrays. + handleInstIndex = ContainsHandleMap(handleInstCount, handleInstArray, handleMap); + if (handleInstIndex == uint.MaxValue) + { + handleInstIndex = handleMap.GetCount(); + for (uint i = 0; i < handleInstCount; i++) + handleMap.Append(CastHandle(handleInstArray[i])); + ErrorHandling.AssertCodeMsg(handleInstIndex + handleInstCount == handleMap.GetCount(), ExceptionCodes.MC, + "handleInstIndex + handleInstCount == handleMap->GetCount()", "Unexpected size of handleMap"); + } + } + else + { + // A count without an array is a VM/crossgen2 bug (or a by-design crossgen2 feature to avoid + // creating an array the JIT doesn't look at). + handleInstCount = 0; + handleInstIndex = uint.MaxValue; + } + + handleInstCountOut = handleInstCount; + handleInstIndexOut = handleInstIndex; + } + + public static Agnostic_CORINFO_SIG_INFO StoreAgnostic_CORINFO_SIG_INFO(in CORINFO_SIG_INFO sigInfo, LightWeightMapBuffer buffers, ref DenseLightWeightMap handleMap) + { + Agnostic_CORINFO_SIG_INFO sig = CreateAgnostic_CORINFO_SIG_INFO_without_buffers(sigInfo); + StoreAgnostic_CORINFO_SIG_INST_HandleArray(sigInfo.sigInst.classInstCount, sigInfo.sigInst.classInst, ref handleMap, + out sig.sigInst_classInstCount, out sig.sigInst_classInst_Index); + StoreAgnostic_CORINFO_SIG_INST_HandleArray(sigInfo.sigInst.methInstCount, sigInfo.sigInst.methInst, ref handleMap, + out sig.sigInst_methInstCount, out sig.sigInst_methInst_Index); + sig.pSig_Index = buffers.AddBuffer(Bytes(sigInfo.pSig, sigInfo.cbSig)); + return sig; + } + + // Returns the index at which the handle map holds all the handles in order, or uint.MaxValue. + public static uint ContainsHandleMap(uint handleCount, CORINFO_CLASS_STRUCT_** handleArray, DenseLightWeightMap handleMap) + { + if (handleCount == 0) + return uint.MaxValue; + + uint mapCount = handleMap.GetCount(); + for (uint mapIndex = 0; mapIndex < mapCount; mapIndex++) + { + if (mapIndex + handleCount > mapCount) + return uint.MaxValue; + + bool found = true; + for (uint handleIndex = 0; handleIndex < handleCount; handleIndex++) + { + if (handleMap.Get(mapIndex + handleIndex) != CastHandle(handleArray[handleIndex])) + { + found = false; + break; + } + } + if (found) + return mapIndex; + } + return uint.MaxValue; + } + + // Builds the agnostic form of 'sigInfo' from already recorded data, for use as a lookup key. + public static Agnostic_CORINFO_SIG_INFO RestoreAgnostic_CORINFO_SIG_INFO(in CORINFO_SIG_INFO sigInfo, LightWeightMapBuffer buffers, DenseLightWeightMap handleMap) + { + Agnostic_CORINFO_SIG_INFO sig = CreateAgnostic_CORINFO_SIG_INFO_without_buffers(sigInfo); + sig.sigInst_classInst_Index = ContainsHandleMap(sigInfo.sigInst.classInstCount, sigInfo.sigInst.classInst, handleMap); + sig.sigInst_methInst_Index = ContainsHandleMap(sigInfo.sigInst.methInstCount, sigInfo.sigInst.methInst, handleMap); + sig.pSig_Index = (uint)buffers.Contains(Bytes(sigInfo.pSig, sigInfo.cbSig)); + return sig; + } + + public static CORINFO_CLASS_STRUCT_** DeserializeCORINFO_SIG_INST_HandleArray(uint handleInstCount, uint handleInstIndex, + DenseLightWeightMap handleMap, PinnedArena memoryTracker) + { + if (handleInstCount == 0) + return null; + + var handleInstArray = memoryTracker.Allocate(handleInstCount); + for (uint i = 0; i < handleInstCount; i++) + handleInstArray[i] = (nint)handleMap.Get(handleInstIndex + i); + return (CORINFO_CLASS_STRUCT_**)handleInstArray; + } + + public static CORINFO_SIG_INFO Restore_CORINFO_SIG_INFO(in Agnostic_CORINFO_SIG_INFO sigInfo, LightWeightMapBuffer buffers, + DenseLightWeightMap handleMap, PinnedArena memoryTracker) => new() + { + callConv = (CorInfoCallConv)sigInfo.callConv, + retTypeClass = (CORINFO_CLASS_STRUCT_*)sigInfo.retTypeClass, + retTypeSigClass = (CORINFO_CLASS_STRUCT_*)sigInfo.retTypeSigClass, + retType = (CorInfoType)sigInfo.retType, + flags = (CorInfoSigInfoFlags)sigInfo.flags, + numArgs = (ushort)sigInfo.numArgs, + args = (CORINFO_ARG_LIST_STRUCT_*)sigInfo.args, + cbSig = sigInfo.cbSig, + pSig = buffers.GetBufferPointer(sigInfo.pSig_Index), + methodSignature = (MethodSignatureInfo*)sigInfo.methodSignature, + scope = (CORINFO_MODULE_STRUCT_*)sigInfo.scope, + token = (mdToken)sigInfo.token, + sigInst = new CORINFO_SIG_INST + { + classInstCount = sigInfo.sigInst_classInstCount, + classInst = DeserializeCORINFO_SIG_INST_HandleArray(sigInfo.sigInst_classInstCount, sigInfo.sigInst_classInst_Index, handleMap, memoryTracker), + methInstCount = sigInfo.sigInst_methInstCount, + methInst = DeserializeCORINFO_SIG_INST_HandleArray(sigInfo.sigInst_methInstCount, sigInfo.sigInst_methInst_Index, handleMap, memoryTracker), + }, + }; + + public static Agnostic_CORINFO_LOOKUP_KIND CreateAgnostic_CORINFO_LOOKUP_KIND(CORINFO_LOOKUP_KIND* pGenericLookupKind) + => pGenericLookupKind == null ? default : new() + { + needsRuntimeLookup = pGenericLookupKind->needsRuntimeLookup ? 1u : 0u, + runtimeLookupKind = (uint)pGenericLookupKind->runtimeLookupKind, + }; + + public static CORINFO_LOOKUP_KIND RestoreCORINFO_LOOKUP_KIND(in Agnostic_CORINFO_LOOKUP_KIND lookupKind) => new() + { + needsRuntimeLookup = lookupKind.needsRuntimeLookup != 0, + runtimeLookupKind = (CORINFO_RUNTIME_LOOKUP_KIND)lookupKind.runtimeLookupKind, + }; + + public static Agnostic_CORINFO_CONST_LOOKUP StoreAgnostic_CORINFO_CONST_LOOKUP(CORINFO_CONST_LOOKUP* pLookup) + => new() { accessType = (uint)pLookup->accessType, handle = CastHandle(pLookup->handle) }; + + public static CORINFO_CONST_LOOKUP RestoreCORINFO_CONST_LOOKUP(in Agnostic_CORINFO_CONST_LOOKUP lookup) + => new() { accessType = (InfoAccessType)lookup.accessType, handle = (CORINFO_GENERIC_STRUCT_*)lookup.handle }; + + public static Agnostic_CORINFO_RUNTIME_LOOKUP StoreAgnostic_CORINFO_RUNTIME_LOOKUP(CORINFO_RUNTIME_LOOKUP* pLookup) + { + var runtimeLookup = new Agnostic_CORINFO_RUNTIME_LOOKUP + { + signature = CastHandle(pLookup->signature), + helper = (uint)pLookup->helper, + indirections = pLookup->indirections, + testForNull = pLookup->_testForNull, + sizeOffset = pLookup->sizeOffset, + indirectFirstOffset = pLookup->_indirectFirstOffset, + indirectSecondOffset = pLookup->_indirectSecondOffset, + helperEntryPoint = StoreAgnostic_CORINFO_CONST_LOOKUP(&pLookup->helperEntryPoint), + }; + for (int i = 0; i < CORINFO_MAXINDIRECTIONS; i++) + runtimeLookup.offsets[i] = (nuint)Unsafe.Add(ref pLookup->offset0, i); + return runtimeLookup; + } + + public static CORINFO_RUNTIME_LOOKUP RestoreCORINFO_RUNTIME_LOOKUP(in Agnostic_CORINFO_RUNTIME_LOOKUP lookup) + { + var runtimeLookup = new CORINFO_RUNTIME_LOOKUP + { + signature = (void*)lookup.signature, + helper = (CorInfoHelpFunc)lookup.helper, + indirections = (ushort)lookup.indirections, + testForNull = lookup.testForNull != 0, + sizeOffset = lookup.sizeOffset, + indirectFirstOffset = lookup.indirectFirstOffset != 0, + indirectSecondOffset = lookup.indirectSecondOffset != 0, + helperEntryPoint = RestoreCORINFO_CONST_LOOKUP(lookup.helperEntryPoint), + }; + for (int i = 0; i < CORINFO_MAXINDIRECTIONS; i++) + Unsafe.Add(ref runtimeLookup.offset0, i) = (nint)lookup.offsets[i]; + return runtimeLookup; + } + + public static Agnostic_CORINFO_LOOKUP StoreAgnostic_CORINFO_LOOKUP(CORINFO_LOOKUP* pLookup) + { + var lookup = new Agnostic_CORINFO_LOOKUP { lookupKind = CreateAgnostic_CORINFO_LOOKUP_KIND(&pLookup->lookupKind) }; + if (pLookup->lookupKind.needsRuntimeLookup) + lookup.runtimeLookup = StoreAgnostic_CORINFO_RUNTIME_LOOKUP(&pLookup->runtimeLookup); + else + lookup.constLookup = StoreAgnostic_CORINFO_CONST_LOOKUP((CORINFO_CONST_LOOKUP*)&pLookup->runtimeLookup); + return lookup; + } + + public static CORINFO_LOOKUP RestoreCORINFO_LOOKUP(in Agnostic_CORINFO_LOOKUP agnosticLookup) + { + var lookup = new CORINFO_LOOKUP { lookupKind = RestoreCORINFO_LOOKUP_KIND(agnosticLookup.lookupKind) }; + if (lookup.lookupKind.needsRuntimeLookup) + lookup.runtimeLookup = RestoreCORINFO_RUNTIME_LOOKUP(agnosticLookup.runtimeLookup); + else + lookup.constLookup = RestoreCORINFO_CONST_LOOKUP(agnosticLookup.constLookup); + return lookup; + } + + public static Agnostic_CORINFO_TYPE_LAYOUT_NODE StoreAgnostic_CORINFO_TYPE_LAYOUT_NODE(in CORINFO_TYPE_LAYOUT_NODE node) => new() + { + simdTypeHnd = CastHandle(node.simdTypeHnd), + diagFieldHnd = CastHandle(node.diagFieldHnd), + parent = node.parent, + offset = node.offset, + size = node.size, + numFields = node.numFields, + type = (byte)node.type, + hasSignificantPadding = node.hasSignificantPadding ? (byte)1 : (byte)0, + }; + + public static CORINFO_TYPE_LAYOUT_NODE RestoreCORINFO_TYPE_LAYOUT_NODE(in Agnostic_CORINFO_TYPE_LAYOUT_NODE node) => new() + { + simdTypeHnd = (CORINFO_CLASS_STRUCT_*)node.simdTypeHnd, + diagFieldHnd = (CORINFO_FIELD_STRUCT_*)node.diagFieldHnd, + parent = node.parent, + offset = node.offset, + size = node.size, + numFields = node.numFields, + type = (CorInfoType)node.type, + hasSignificantPadding = node.hasSignificantPadding != 0, + }; + + public static Agnostic_CORINFO_HELPER_DESC StoreAgnostic_CORINFO_HELPER_DESC(in CORINFO_HELPER_DESC desc) + { + var result = new Agnostic_CORINFO_HELPER_DESC { helperNum = (uint)desc.helperNum, numArgs = desc.numArgs }; + for (int i = 0; i < CORINFO_ACCESS_ALLOWED_MAX_ARGS; i++) + { + CORINFO_HELPER_ARG arg = Unsafe.Add(ref Unsafe.AsRef(in desc.args0), i); + result.args[i] = new Agnostic_CORINFO_HELPER_ARG { constant = (nuint)arg.argHandle, argType = (uint)arg.argType }; + } + return result; + } + + public static CORINFO_HELPER_DESC RestoreCORINFO_HELPER_DESC(in Agnostic_CORINFO_HELPER_DESC desc) + { + var result = new CORINFO_HELPER_DESC { helperNum = (CorInfoHelpFunc)desc.helperNum, numArgs = desc.numArgs }; + for (int i = 0; i < CORINFO_ACCESS_ALLOWED_MAX_ARGS; i++) + { + Unsafe.Add(ref result.args0, i) = new CORINFO_HELPER_ARG + { + argHandle = (nint)desc.args[i].constant, + argType = (CorInfoAccessAllowedHelperArgType)desc.args[i].argType, + }; + } + return result; + } + + // PatchpointInfo: a fixed header followed by an int32 per local; the local count follows two pointer-sized fields. + private static readonly int s_patchpointInfoHeaderSize = (8 + sizeof(nint) + 10 * sizeof(int) + 7) & ~7; + + public static nuint PatchpointInfoSize(PatchpointInfo* patchpointInfo) + => (nuint)s_patchpointInfoHeaderSize + *(uint*)((byte*)patchpointInfo + 8 + sizeof(nint)) * sizeof(int); + + private static ReadOnlySpan Bytes(byte* data, uint length) => data == null ? default : new ReadOnlySpan(data, (int)length); +} diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/SpmiUtil.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/SpmiUtil.cs new file mode 100644 index 00000000000000..43df53fea30075 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/SpmiUtil.cs @@ -0,0 +1,196 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.CommandLine; +using System.Diagnostics; +using Internal.TypeSystem; + +namespace SuperPmi; + +public static unsafe class SpmiUtil +{ + private static TargetArchitecture s_targetArchitecture = Helpers.GetTargetArchitecture(null); + + public static TargetArchitecture GetSpmiTargetArchitecture() => s_targetArchitecture; + + public static void SetSpmiTargetArchitecture(TargetArchitecture architecture) => s_targetArchitecture = architecture; + + public static bool IsSpmiTarget32Bit() => s_targetArchitecture is TargetArchitecture.X86 or TargetArchitecture.ARM or TargetArchitecture.Wasm32; + + public static bool IsSpmiTarget64Bit() => s_targetArchitecture is TargetArchitecture.X64 or TargetArchitecture.ARM64 + or TargetArchitecture.LoongArch64 or TargetArchitecture.RiscV64; + + public static uint SpmiTargetPointerSize() => IsSpmiTarget64Bit() ? 8u : 4u; + + public static bool BreakOnDebugBreakorAV { get; set; } + + public static bool BreakOnException { get; set; } + + // The handler for unexpected conditions, with a unique number per call site. + public static void DebugBreakorAV(int val) + { + if (Debugger.IsAttached && (val == 0 || BreakOnDebugBreakorAV)) + Debugger.Break(); + + ErrorHandling.LogException(ExceptionCodes.DebugBreakorAV + (uint)val, $"DebugBreak or AV Exception {val}"); + } + + // Instruction encoding helpers, as in src/coreclr/utilcode/util.cpp. + + public static void PutArm64Rel28(uint* pCode, int imm28) + => *pCode = (*pCode & 0xFC000000) | (uint)((imm28 >> 2) & 0x03FFFFFF); + + public static void PutArm64Rel21(uint* pCode, int imm21) + { + int immlo = imm21 & 0x03; + int immhi = (imm21 & 0x1FFFFC) >> 2; + *pCode = (*pCode & 0x9F00001F) | (uint)((immlo << 29) | (immhi << 5)); + } + + public static void PutArm64Rel12(uint* pCode, int imm12) => *pCode = (*pCode & 0xFFC003FF) | (uint)(imm12 << 10); + + // For a 64-bit LDR the encoded immediate is scaled by the access size (8). + public static void PutArm64Rel12Ldr(uint* pCode, int imm12) => *pCode = (*pCode & 0xFFC003FF) | (uint)((imm12 >> 3) << 10); + + public static void PutThumb2Imm16(ushort* p, ushort imm16) + { + int opcode0 = p[0] & ~((0xf000 >> 12) | (0x0800 >> 1)); + int opcode1 = p[1] & ~((0x0700 << 4) | (0x00ff << 0)); + opcode0 |= (imm16 & 0xf000) >> 12; + opcode0 |= (imm16 & 0x0800) >> 1; + opcode1 |= (imm16 & 0x0700) << 4; + opcode1 |= (imm16 & 0x00ff) << 0; + p[0] = (ushort)opcode0; + p[1] = (ushort)opcode1; + } + + public static void PutThumb2Mov32(ushort* p, uint imm32) + { + PutThumb2Imm16(p, (ushort)imm32); + PutThumb2Imm16(p + 2, (ushort)(imm32 >> 16)); + } + + public static void PutThumb2BlRel24(ushort* p, int imm24) + { + uint opcode0 = p[0] & 0xF800u; + uint opcode1 = p[1] & 0xD000u; + + uint s = (uint)(imm24 & 0x1000000) >> 24; + uint j1 = (((uint)(imm24 & 0x0800000) >> 23) ^ s ^ 1); + uint j2 = (((uint)(imm24 & 0x0400000) >> 22) ^ s ^ 1); + + opcode0 |= ((uint)(imm24 & 0x03FF000) >> 12) | (s << 10); + opcode1 |= ((uint)(imm24 & 0x0000FFE) >> 1) | (j1 << 13) | (j2 << 11); + + p[0] = (ushort)opcode0; + p[1] = (ushort)opcode1; + } + + // Decodes arm64 mov / movk instructions, which the near differ uses to recognize addresses built by a + // mov/movk sequence. For example: + // d29ff600 mov x0, #65456 + // f2ab8640 movk x0, #23602, lsl #16 + public static bool GetArm64MovConstant(uint* p, out uint reg, out uint con) + { + uint instr = *p; + bool result = (instr & 0xffe00000) == 0xd2800000; + reg = result ? instr & 0x1f : 0; + con = result ? (instr >> 5) & 0xffff : 0; + return result; + } + + public static bool GetArm64MovkConstant(uint* p, out uint reg, out uint con, out uint shift) + { + uint instr = *p; + bool result = (instr & 0xff800000) == 0xf2800000; + reg = result ? instr & 0x1f : 0; + con = result ? (instr >> 5) & 0xffff : 0; + shift = result ? ((instr >> 21) & 0x3) * 16 : 0; + return result; + } + + public static void PutArm64MovkConstant(uint* p, uint con) => *p = (*p & ~(0xffffu << 5)) | ((con & 0xffff) << 5); + + // Decodes Arm32 (Thumb-2) movw / movt instructions. For example: + // 4b f2 33 40 movw r0, #46131 + // c0 f2 79 30 movt r0, #889 + // This decodes "MOV (immediate)" encoding T3 (ARM manual A8.8.102), and "MOVT" encoding T1 (A8.8.106). + public static bool GetArm32MovwConstant(uint* p, out uint reg, out uint con) => GetArm32MovConstant(p, 0xf2400000, out reg, out con); + + public static bool GetArm32MovtConstant(uint* p, out uint reg, out uint con) => GetArm32MovConstant(p, 0xf2C00000, out reg, out con); + + private static bool GetArm32MovConstant(uint* p, uint pattern, out uint reg, out uint con) + { + reg = 0; + con = 0; + if (!Is32BitThumb2Instruction((ushort*)p)) + return false; + + // A Thumb-2 instruction is one or two 16-bit words (in little-endian format). + uint instr = ((uint)((ushort*)p)[0] << 16) | ((ushort*)p)[1]; + if ((instr & 0xfbf08000) != pattern) + return false; + + reg = (instr & 0xf00) >> 8; + con = ExtractArm32MovImm(instr); + return true; + } + + public static bool Is32BitThumb2Instruction(ushort* p) => (*p & 0xf800) >= 0xe800; + + public static uint ExtractArm32MovImm(uint instr) + { + uint imm4 = (instr >> 16) & 0xf; + uint i = (instr >> 26) & 0x1; + uint imm3 = (instr >> 12) & 0x7; + uint imm8 = instr & 0xff; + return (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8; + } + + // Sets the constant field of a movt instruction; 'con' must be a 16-bit constant. + public static void PutArm32MovtConstant(uint* p, uint con) + { + uint imm4 = (con >> 12) & 0xf; + uint i = (con >> 11) & 0x1; + uint imm3 = (con >> 8) & 0x7; + uint imm8 = con & 0xff; + uint instr = ((uint)((ushort*)p)[0] << 16) | ((ushort*)p)[1]; + instr = (instr & 0xfbf08f00) | (imm4 << 16) | (i << 26) | (imm3 << 12) | imm8; + ((ushort*)p)[0] = (ushort)(instr >> 16); + ((ushort*)p)[1] = (ushort)instr; + } + + // Extracts the PC-relative offset from an auipc + I-type or S-type adder (addi/load/store/jalr). + public static long GetRiscV64AuipcCombo(uint* pCode, bool isStype) + { + long hi20 = ((int)pCode[0] >> 12) << 12; + uint instr = pCode[1]; + long lo12 = ((int)instr >> 25) << 5; // the top 7 bits are in the same spot + lo12 |= (instr >> (isStype ? 7 : 20)) & 0x1F; + return hi20 + lo12; + } + + // Deposits the PC-relative offset into an auipc + I-type or S-type adder (addi/load/store/jalr). + public static void PutRiscV64AuipcCombo(uint* pCode, long offset, bool isStype) + { + int lo12 = (int)((offset << (64 - 12)) >> (64 - 12)); + int hi20 = (int)(offset - lo12); + + // Replace the existing immediate bits, since RISC-V relocation placeholders may already carry addends. + pCode[0] &= 0x00000FFF; + pCode[0] |= (uint)hi20 & 0xFFFFF000; + + uint lo12Bits = (uint)lo12 & 0xFFF; + if (isStype) + { + pCode[1] &= 0x01FFF07F; + pCode[1] |= (lo12Bits & 0xFE0) << 20; + pCode[1] |= (lo12Bits & 0x01F) << 7; + } + else + { + pCode[1] &= 0x000FFFFF; + pCode[1] |= lo12Bits << 20; + } + } +} diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/SuperPmi.Shared.csproj b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/SuperPmi.Shared.csproj new file mode 100644 index 00000000000000..e38c98e9a204d3 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/SuperPmi.Shared.csproj @@ -0,0 +1,16 @@ + + + true + + + + + + + + + + + + + diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/TocFile.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/TocFile.cs new file mode 100644 index 00000000000000..fed589f4bb1a83 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/TocFile.cs @@ -0,0 +1,121 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Buffers.Binary; +using System.IO; +using System.Text; + +namespace SuperPmi; + +public struct TOCElement +{ + // Native layout: int64 Offset, int Number, char Hash[33], padded to 8 bytes. + public const int Size = 48; + private const int HashOffset = 12; + + public long Offset; + public int Number; + public byte[] Hash; // MM3_HASH_BUFFER_SIZE bytes, including the null terminator + + public TOCElement(int number, long offset, string hash) + { + Number = number; + Offset = offset; + Hash = new byte[SuperPmi.Hash.MM3_HASH_BUFFER_SIZE]; + if (hash != null) + Encoding.ASCII.GetBytes(hash, Hash); + } + + public readonly string HashString + { + get + { + int nul = Array.IndexOf(Hash, (byte)0); + return Encoding.ASCII.GetString(Hash, 0, nul >= 0 ? nul : Hash.Length); + } + } + + public static TOCElement Read(ReadOnlySpan data) => new TOCElement + { + Offset = BinaryPrimitives.ReadInt64LittleEndian(data), + Number = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8)), + Hash = data.Slice(HashOffset, SuperPmi.Hash.MM3_HASH_BUFFER_SIZE).ToArray(), + }; + + public readonly void Write(Span data) + { + data.Slice(0, Size).Clear(); + BinaryPrimitives.WriteInt64LittleEndian(data, Offset); + BinaryPrimitives.WriteInt32LittleEndian(data.Slice(8), Number); + Hash.CopyTo(data.Slice(HashOffset)); + } +} + +// The table of contents (.mct) for a method context file: "INDX", the element count, the elements, "INDX". +public sealed class TOCFile +{ + public static readonly uint Sentinel = BinaryPrimitives.ReadUInt32LittleEndian("INDX"u8); + + private TOCElement[] m_tocArray = []; + + public int GetTocCount() => m_tocArray.Length; + + public TOCElement GetElement(int i) => m_tocArray[i]; + + public void Clear() => m_tocArray = []; + + public void LoadToc(string inputFileName, bool validate = true) + { + byte[] data; + try + { + data = File.ReadAllBytes(inputFileName); + } + catch (Exception e) when (e is IOException or UnauthorizedAccessException) + { + Logger.LogError($"Failed to open file '{inputFileName}'. GetLastError()={ErrorHandling.LastError(e)}"); + return; + } + + if (data.Length < 8 || BinaryPrimitives.ReadUInt32LittleEndian(data) != Sentinel) + { + Logger.LogWarning($"The index file {inputFileName} is invalid: it seems to be missing the starting sentinel/length"); + return; + } + + int count = BinaryPrimitives.ReadInt32LittleEndian(data.AsSpan(4)); + long elementsEnd = 8 + (long)count * TOCElement.Size; + if (count < 0 || elementsEnd > data.Length) + { + Logger.LogWarning($"The index file {inputFileName} is invalid: it appears to be truncated."); + return; + } + + if (elementsEnd + 4 > data.Length || BinaryPrimitives.ReadUInt32LittleEndian(data.AsSpan((int)elementsEnd)) != Sentinel) + { + Logger.LogWarning($"The index file {inputFileName} is invalid: it appears to be missing the ending sentinel."); + return; + } + + var elements = new TOCElement[count]; + for (int i = 0; i < count; i++) + elements[i] = TOCElement.Read(data.AsSpan(8 + i * TOCElement.Size, TOCElement.Size)); + + if (validate) + { + int lastNum = -1; + foreach (TOCElement element in elements) + { + if (element.Number <= lastNum) + { + Logger.LogWarning($"The index file {inputFileName} is invalid: it is not sorted."); + return; + } + lastNum = element.Number; + } + } + + m_tocArray = elements; + } +} diff --git a/src/coreclr/tools/superpmi/managed/mcs/ILDumper.cs b/src/coreclr/tools/superpmi/managed/mcs/ILDumper.cs new file mode 100644 index 00000000000000..11ca715507f990 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/mcs/ILDumper.cs @@ -0,0 +1,361 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.IO; + +namespace SuperPmi.Mcs; + +// Raw IL printing for -ildump. All the instructions of a method are printed +// on one line (only unknown opcodes end a line), short branch targets add the offset as an unsigned byte, +// and a few names are off (0x30 bgt.s, 0x3D bgt, 0xA3 stelem, leave.s as leave): the format of -ildump. +internal static partial class ILDumper +{ + private enum Operand : byte + { + None, + Int8, + Int16, + Int32, + Int64, + Float32, + Float64, + Token, + ShortBranch, + Branch, + Switch, + } + + private static readonly (string Name, Operand Operand)[] s_opcodes = BuildTable( + [ + (0x00, "nop", Operand.None), + (0x01, "break", Operand.None), + (0x02, "ldarg.0", Operand.None), + (0x03, "ldarg.1", Operand.None), + (0x04, "ldarg.2", Operand.None), + (0x05, "ldarg.3", Operand.None), + (0x06, "ldloc.0", Operand.None), + (0x07, "ldloc.1", Operand.None), + (0x08, "ldloc.2", Operand.None), + (0x09, "ldloc.3", Operand.None), + (0x0A, "stloc.0", Operand.None), + (0x0B, "stloc.1", Operand.None), + (0x0C, "stloc.2", Operand.None), + (0x0D, "stloc.3", Operand.None), + (0x0E, "ldarg.s", Operand.Int8), + (0x0F, "ldarga.s", Operand.Int8), + (0x10, "starg.s", Operand.Int8), + (0x11, "ldloc.s", Operand.Int8), + (0x12, "ldloca.s", Operand.Int8), + (0x13, "stloc.s", Operand.Int8), + (0x14, "ldnull", Operand.None), + (0x15, "ldc.i4.m1", Operand.None), + (0x16, "ldc.i4.0", Operand.None), + (0x17, "ldc.i4.1", Operand.None), + (0x18, "ldc.i4.2", Operand.None), + (0x19, "ldc.i4.3", Operand.None), + (0x1A, "ldc.i4.4", Operand.None), + (0x1B, "ldc.i4.5", Operand.None), + (0x1C, "ldc.i4.6", Operand.None), + (0x1D, "ldc.i4.7", Operand.None), + (0x1E, "ldc.i4.8", Operand.None), + (0x1F, "ldc.i4.s", Operand.Int8), + (0x20, "ldc.i4", Operand.Int32), + (0x21, "ldc.i8", Operand.Int64), + (0x22, "ldc.r4", Operand.Float32), + (0x23, "ldc.r8", Operand.Float64), + (0x25, "dup", Operand.None), + (0x26, "pop", Operand.None), + (0x27, "jmp", Operand.Token), + (0x28, "call", Operand.Token), + (0x29, "calli", Operand.Token), + (0x2A, "ret", Operand.None), + (0x2B, "br.s", Operand.ShortBranch), + (0x2C, "brfalse.s", Operand.ShortBranch), + (0x2D, "brtrue.s", Operand.ShortBranch), + (0x2E, "beq.s", Operand.ShortBranch), + (0x2F, "bgt.s", Operand.ShortBranch), + (0x30, "bgt.s", Operand.ShortBranch), + (0x31, "ble.s", Operand.ShortBranch), + (0x32, "blt.s", Operand.ShortBranch), + (0x33, "bne.un.s", Operand.ShortBranch), + (0x34, "bge.un.s", Operand.ShortBranch), + (0x35, "bgt.un.s", Operand.ShortBranch), + (0x36, "ble.un.s", Operand.ShortBranch), + (0x37, "blt.un.s", Operand.ShortBranch), + (0x38, "br", Operand.Branch), + (0x39, "brfalse", Operand.Branch), + (0x3A, "brtrue", Operand.Branch), + (0x3B, "beq", Operand.Branch), + (0x3C, "bgt", Operand.Branch), + (0x3D, "bgt", Operand.Branch), + (0x3E, "ble", Operand.Branch), + (0x3F, "blt", Operand.Branch), + (0x40, "bne.un", Operand.Branch), + (0x41, "bge.un", Operand.Branch), + (0x42, "bgt.un", Operand.Branch), + (0x43, "ble.un", Operand.Branch), + (0x44, "blt.un", Operand.Branch), + (0x45, "switch", Operand.Switch), + (0x46, "ldind.i1", Operand.None), + (0x47, "ldind.u1", Operand.None), + (0x48, "ldind.i2", Operand.None), + (0x49, "ldind.u2", Operand.None), + (0x4A, "ldind.i4", Operand.None), + (0x4B, "ldind.u4", Operand.None), + (0x4C, "ldind.i8", Operand.None), + (0x4D, "ldind.u8", Operand.None), + (0x4E, "ldind.r4", Operand.None), + (0x4F, "ldind.r8", Operand.None), + (0x50, "ldind.ref", Operand.None), + (0x51, "stind.ref", Operand.None), + (0x52, "stind.i1", Operand.None), + (0x53, "stind.i2", Operand.None), + (0x54, "stind.i4", Operand.None), + (0x55, "stind.i8", Operand.None), + (0x56, "stind.r4", Operand.None), + (0x57, "stind.r8", Operand.None), + (0x58, "add", Operand.None), + (0x59, "sub", Operand.None), + (0x5A, "mul", Operand.None), + (0x5B, "div", Operand.None), + (0x5C, "div.un", Operand.None), + (0x5D, "rem", Operand.None), + (0x5E, "rem.un", Operand.None), + (0x5F, "and", Operand.None), + (0x60, "or", Operand.None), + (0x61, "xor", Operand.None), + (0x62, "shl", Operand.None), + (0x63, "shr", Operand.None), + (0x64, "shr.un", Operand.None), + (0x65, "neg", Operand.None), + (0x66, "not", Operand.None), + (0x67, "conv.i1", Operand.None), + (0x68, "conv.i2", Operand.None), + (0x69, "conv.i4", Operand.None), + (0x6A, "conv.i8", Operand.None), + (0x6B, "conv.r4", Operand.None), + (0x6C, "conv.r8", Operand.None), + (0x6D, "conv.u4", Operand.None), + (0x6E, "conv.u8", Operand.None), + (0x6F, "callvirt", Operand.Token), + (0x70, "cpobj", Operand.Token), + (0x71, "ldobj", Operand.Token), + (0x72, "ldstr", Operand.Token), + (0x73, "newobj", Operand.Token), + (0x74, "castclass", Operand.Token), + (0x75, "isinst", Operand.Token), + (0x76, "conv.r.un", Operand.None), + (0x79, "unbox", Operand.Token), + (0x7A, "throw", Operand.None), + (0x7B, "ldfld", Operand.Token), + (0x7C, "ldflda", Operand.Token), + (0x7D, "stfld", Operand.Token), + (0x7E, "ldsfld", Operand.Token), + (0x7F, "ldsflda", Operand.Token), + (0x80, "stsfld", Operand.Token), + (0x81, "stobj", Operand.Token), + (0x82, "conv.ovf.i1.un", Operand.None), + (0x83, "conv.ovf.i2.un", Operand.None), + (0x84, "conv.ovf.i4.un", Operand.None), + (0x85, "conv.ovf.i8.un", Operand.None), + (0x86, "conv.ovf.u1.un", Operand.None), + (0x87, "conv.ovf.u2.un", Operand.None), + (0x88, "conv.ovf.u4.un", Operand.None), + (0x89, "conv.ovf.u8.un", Operand.None), + (0x8A, "conv.ovf.i.un", Operand.None), + (0x8B, "conv.ovf.u.un", Operand.None), + (0x8C, "box", Operand.Token), + (0x8D, "newarr", Operand.Token), + (0x8E, "ldlen", Operand.None), + (0x8F, "ldelema", Operand.Token), + (0x90, "ldelem.i1", Operand.None), + (0x91, "ldelem.u1", Operand.None), + (0x92, "ldelem.i2", Operand.None), + (0x93, "ldelem.u2", Operand.None), + (0x94, "ldelem.i4", Operand.None), + (0x95, "ldelem.u4", Operand.None), + (0x96, "ldelem.i8", Operand.None), + (0x97, "ldelem.i", Operand.None), + (0x98, "ldelem.r4", Operand.None), + (0x99, "ldelem.r8", Operand.None), + (0x9A, "ldelem.ref", Operand.None), + (0x9B, "stelem.i", Operand.None), + (0x9C, "stelem.i1", Operand.None), + (0x9D, "stelem.i2", Operand.None), + (0x9E, "stelem.i4", Operand.None), + (0x9F, "stelem.i8", Operand.None), + (0xA0, "stelem.r4", Operand.None), + (0xA1, "stelem.r8", Operand.None), + (0xA2, "stelem.ref", Operand.None), + (0xA3, "stelem", Operand.Token), + (0xA4, "stelem", Operand.Token), + (0xA5, "unbox.any", Operand.Token), + (0xB3, "conv.ovf.i1", Operand.None), + (0xB4, "conv.ovf.u1", Operand.None), + (0xB5, "conv.ovf.i2", Operand.None), + (0xB6, "conv.ovf.u2", Operand.None), + (0xB7, "conv.ovf.i4", Operand.None), + (0xB8, "conv.ovf.u4", Operand.None), + (0xB9, "conv.ovf.i8", Operand.None), + (0xBA, "conv.ovf.u8", Operand.None), + (0xC2, "refanyval", Operand.Token), + (0xC3, "ckfinite", Operand.None), + (0xC6, "mkrefany", Operand.Token), + (0xD0, "ldtoken", Operand.Token), + (0xD1, "conv.u2", Operand.None), + (0xD2, "conv.u1", Operand.None), + (0xD3, "conv.i", Operand.None), + (0xD4, "conv.ovf.i", Operand.None), + (0xD5, "conv.ovf.u", Operand.None), + (0xD6, "add.ovf", Operand.None), + (0xD7, "add.ovf.un", Operand.None), + (0xD8, "mul.ovf", Operand.None), + (0xD9, "mul.ovf.un", Operand.None), + (0xDA, "sub.ovf", Operand.None), + (0xDB, "sub.ovf.un", Operand.None), + (0xDC, "endfinally", Operand.None), + (0xDD, "leave", Operand.Int32), + (0xDE, "leave", Operand.Int8), + (0xDF, "stind.i", Operand.None), + (0xE0, "conv.u", Operand.None), + ]); + + private static readonly (string Name, Operand Operand)[] s_fePrefixedOpcodes = BuildTable( + [ + (0x00, "arglist", Operand.None), + (0x01, "ceq", Operand.None), + (0x02, "cgt", Operand.None), + (0x03, "cgt.un", Operand.None), + (0x04, "clt", Operand.None), + (0x05, "clt.un", Operand.None), + (0x06, "ldftn", Operand.Token), + (0x07, "ldvirtftn", Operand.Token), + (0x09, "ldarg", Operand.Int16), + (0x0A, "ldarga", Operand.Int16), + (0x0B, "starg", Operand.Int16), + (0x0C, "ldloc", Operand.Int16), + (0x0D, "ldloca", Operand.Int16), + (0x0E, "stloc", Operand.Int16), + (0x0F, "localloc", Operand.None), + (0x11, "endfilter", Operand.None), + (0x12, "unaligned.", Operand.Int8), + (0x13, "volatile.", Operand.None), + (0x14, "tail.", Operand.None), + (0x15, "initobj", Operand.Token), + (0x16, "constrained.", Operand.Token), + (0x17, "cpblk", Operand.None), + (0x18, "initblk", Operand.None), + (0x19, "no.", Operand.None), + (0x1A, "rethrow", Operand.None), + (0x1C, "sizeof", Operand.Token), + (0x1D, "refanytype", Operand.None), + ]); + + private static (string, Operand)[] BuildTable((byte Opcode, string Name, Operand Operand)[] entries) + { + var table = new (string, Operand)[256]; + foreach ((byte opcode, string name, Operand operand) in entries) + table[opcode] = (name, operand); + return table; + } + + public static void DumpILToConsoleBare(TextWriter output, byte[] ilCode, int len) + { + for (int i = 0; i < len; i++) + { + CFormat.Printf(output, "IL_%04x: ", i); + + (string name, Operand operand) = s_opcodes[ilCode[i]]; + if (ilCode[i] == 0xFE) + { + i++; + (name, operand) = s_fePrefixedOpcodes[ilCode[i]]; + if (name == null) + { + Logger.LogError(CFormat.Sprintf("unknown ilCode 0xfe%2x at offset %d in MethodGen::PrettyPrint", ilCode[i], i)); + output.Write('\n'); + continue; + } + } + else if (name == null) + { + Logger.LogError(CFormat.Sprintf("unknown ilCode 0x%02x at offset %d in MethodGen::PrettyPrint", ilCode[i], i)); + output.Write('\n'); + continue; + } + + WriteInstruction(output, name, operand, ilCode, ref i); + } + } + + // Writes the instruction at 'i' and advances 'i' to its last byte. + private static void WriteInstruction(TextWriter output, string name, Operand operand, byte[] ilCode, ref int i) + { + int at = i; + switch (operand) + { + case Operand.None: + output.Write(name); + break; + case Operand.Int8: + output.Write($"{name} 0x{Hex(ilCode, at, 1)}"); + i += 1; + break; + case Operand.Int16: + output.Write($"{name} 0x{Hex(ilCode, at, 2)}"); + i += 2; + break; + case Operand.Int32: + output.Write($"{name} 0x{Hex(ilCode, at, 4)}"); + i += 4; + break; + case Operand.Int64: + output.Write($"{name} 0x{Hex(ilCode, at, 8)}"); + i += 8; + break; + case Operand.Float32: + output.Write($"{name} float32(0x{Hex(ilCode, at, 4)})"); + i += 4; + break; + case Operand.Float64: + output.Write($"{name} float64(0x{Hex(ilCode, at, 8)})"); + i += 8; + break; + case Operand.Token: + output.Write($"{name} <0x{Hex(ilCode, at, 4)}>"); + i += 4; + break; + case Operand.ShortBranch: + CFormat.Printf(output, "%s IL_%04x", name, at + 2 + ilCode[at + 1]); + i += 1; + break; + case Operand.Branch: + CFormat.Printf(output, "%s IL_%04x", name, at + 5 + Int32At(ilCode, at)); + i += 4; + break; + case Operand.Switch: + output.Write($"{name} (0x{Hex(ilCode, at, 4)})"); + int count = Int32At(ilCode, at); + i += 4; + for (int j = 0; j < count; j++) + { + output.Write($" <0x{Hex(ilCode, i, 4)}>"); + i += 4; + } + break; + } + } + + private static int Int32At(byte[] ilCode, int at) + => (ilCode[at + 4] << 24) | (ilCode[at + 3] << 16) | (ilCode[at + 2] << 8) | ilCode[at + 1]; + + // The 'count' operand bytes after 'at', most significant first. + private static string Hex(byte[] ilCode, int at, int count) + { + Span bytes = stackalloc byte[count]; + for (int k = 1; k <= count; k++) + bytes[count - k] = ilCode[at + k]; + return Convert.ToHexStringLower(bytes); + } +} diff --git a/src/coreclr/tools/superpmi/managed/mcs/McsRootCommand.cs b/src/coreclr/tools/superpmi/managed/mcs/McsRootCommand.cs new file mode 100644 index 00000000000000..478dbc8b0e1c44 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/mcs/McsRootCommand.cs @@ -0,0 +1,257 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.CommandLine; +using System.CommandLine.Parsing; + +namespace SuperPmi.Mcs; + +internal sealed class McsRootCommand : RootCommand +{ + public Option Verbosity { get; } = + new("--verbosity", "-verbosity", "-v") { Recursive = true, HelpName = "messagetypes", Description = "Message types to log: e(rrors), w(arnings), m(issing), n(otifications), v(erbose), d(ebug), a(ll), q(uiet). Default: ewmnv" }; + public Option LogFile { get; } = + new("--write-log-file", "-writeLogFile") { Recursive = true, HelpName = "logfile", Description = "Write log messages to the specified file" }; + + public McsRootCommand() + : base("MCS is a utility for examining and manipulating SuperPMI MC files.") + { + Options.Add(Verbosity); + Options.Add(LogFile); + + { + Operands operands = new("inputfile", "outputfile"); + Verb("ASMDump", "Dump out the asm file for each input methodContext.", operands) + .SetAction(r => Run(r, () => VerbASMDump.DoWork(operands.File(r, 0), operands.File(r, 1), operands.Range(r)))); + } + { + Argument file1 = File("file1"); + Argument file2 = File("file2"); + Verb("concat", "Concatenate two files without regard to internal formatting. file2 is appended to file1.", file1, file2) + .SetAction(r => Run(r, () => VerbConcat.DoWork(r.GetValue(file1), r.GetValue(file2)))); + } + { + Operands operands = new("file1", "file2"); + Option thin = Thin(); + Command copy = Verb("copy", "Copy methodContext numbers in range from file1 to file2.", operands, thin); + copy.Validators.Add(result => + { + if (operands.Range(result) is { Length: 0 }) + result.AddError("-copy requires a range."); + }); + copy.SetAction(r => Run(r, () => VerbStrip.DoWork(operands.File(r, 0), operands.File(r, 1), operands.Range(r), strip: false, r.GetValue(thin)))); + } + { + Operands operands = new("inputfile"); + Option simple = Flag("simple", "Don't display the function name/arguments in the header (useful for debugging mcs itself)"); + Verb("dump", "Dump details for each methodContext.", operands, simple) + .SetAction(r => Run(r, () => VerbDump.DoWork(operands.File(r, 0), operands.Range(r), r.GetValue(simple)))); + } + { + Argument input = File("inputfile"); + Verb("dumpMap", "Dump a map from MC index to function name to the console, in CSV format.", input) + .SetAction(r => Run(r, () => VerbDumpMap.DoWork(r.GetValue(input)))); + } + { + Argument input = File("inputfile"); + Verb("dumpToc", "Dump a TOC file.", input) + .SetAction(r => Run(r, () => VerbDumpToc.DoWork(r.GetValue(input)))); + } + { + Argument range = Range("range", "Number of method contexts in each output file"); + Argument input = File("inputfile"); + Argument output = File("outputfile"); + Option thin = Thin(); + Verb("fracture", "Break the input file into chunks sized by range: '-fracture 3 a.mch b' leads to b-00000.mch, b-00001.mch, etc.", range, input, output, thin) + .SetAction(r => Run(r, () => VerbFracture.DoWork(r.GetValue(input), r.GetValue(output), r.GetValue(range), r.GetValue(thin)))); + } + { + Operands operands = new("inputfile"); + Verb("ildump", "Dump raw IL for each methodContext.", operands) + .SetAction(r => Run(r, () => VerbILDump.DoWork(operands.File(r, 0), operands.Range(r)))); + } + { + Argument input = File("inputfile"); + Verb("integ", "Check the integrity of each methodContext.", input) + .SetAction(r => Run(r, () => VerbInteg.DoWork(r.GetValue(input)))); + } + { + Argument input = File("inputfile"); + Verb("jitflags", "Summarize interesting jitflags for the method contexts.", input) + .SetAction(r => Run(r, () => VerbJitFlags.DoWork(r.GetValue(input)))); + } + { + Argument output = File("outputfile"); + Argument pattern = new("pattern") { Description = "Files to merge, e.g. *.mc, relpath/*.mc, or a directory name" }; + Option recursive = Flag("recursive", "Also merge matching files in all child directories"); + Option dedup = Flag("dedup", "Skip duplicates when copying (like using -removeDup)"); + Option thin = Thin(); + Command merge = Verb("merge", "Merge all the input files matching the pattern.", output, pattern, recursive, dedup, thin); + merge.Validators.Add(result => + { + if (result.GetValue(thin) && !result.GetValue(dedup)) + result.AddError("'-thin' in '-merge' requires -dedup."); + }); + merge.SetAction(r => Run(r, () => VerbMerge.DoWork(r.GetValue(output), r.GetValue(pattern), r.GetValue(recursive), r.GetValue(dedup), r.GetValue(thin)))); + } + { + Verb("printJITEEVersion", "Print the JITEEVersion GUID with which this was built, in the form: a5eec3a4-4176-43a7-8c2b-a05b551d4f49") + .SetAction(r => Run(r, VerbPrintJITEEVersion.DoWork)); + } + { + Argument input = File("inputfile"); + Argument output = File("outputfile"); + Option legacy = Flag("legacy", "Compare using the legacy method, which may take much longer"); + Option thin = Thin(); + Verb("removeDup", "Copy methodContexts from inputfile to outputfile, skipping duplicates.", input, output, legacy, thin) + .SetAction(r => Run(r, () => VerbRemoveDup.DoWork(r.GetValue(input), r.GetValue(output), r.GetValue(thin), r.GetValue(legacy)))); + } + { + Operands operands = new("inputfile", "outputfile"); + Verb("stat", "Report various statistics per method context into outputfile, in CSV format.", operands) + .SetAction(r => Run(r, () => VerbStat.DoWork(operands.File(r, 0), operands.File(r, 1), operands.Range(r)))); + } + { + Operands operands = new("inputfile", "outputfile"); + Option thin = Thin(); + Verb("strip", "Copy method contexts not in range from inputfile to outputfile. An empty range (e.g., an empty .mcl file from a clean replay) copies the file.", operands, thin) + .SetAction(r => Run(r, () => VerbStrip.DoWork(operands.File(r, 0), operands.File(r, 1), operands.Range(r), strip: true, r.GetValue(thin)))); + } + { + Argument input = File("inputfile"); + Verb("toc", "Create a Table of Contents file for inputfile to allow better random access: '-toc a.mch' creates a.mch.mct.", input) + .SetAction(r => Run(r, () => VerbTOC.DoWork(r.GetValue(input)))); + } + } + + // Verbs are subcommands; the '-verb' spellings are aliases. + private Command Verb(string name, string description, params object[] symbols) + { + var command = new Command(name.ToLowerInvariant(), description); + command.Aliases.Add("-" + name); + if (name != name.ToLowerInvariant()) + command.Aliases.Add("-" + name.ToLowerInvariant()); + + foreach (object symbol in symbols) + { + switch (symbol) + { + case Option option: + command.Options.Add(option); + break; + case Argument argument: + command.Arguments.Add(argument); + break; + case Operands operands: + command.Arguments.Add(operands.Argument); + command.Validators.Add(operands.Validate); + break; + } + } + + Subcommands.Add(command); + return command; + } + + private static Argument File(string name) => new(name); + + private static Option Flag(string name, string description) => new("--" + name, "-" + name) { Description = description }; + + private static Option Thin() => Flag("thin", "Strip CompileResults from the method contexts that are written"); + + private static Argument Range(string name, string description) => new(name) + { + Description = description, + Arity = ArgumentArity.ExactlyOne, + CustomParser = result => + { + if (!MCList.TryParse(result.Tokens[0].Value, out int[] list, out string error)) + result.AddError(error ?? $"'{result.Tokens[0].Value}' is not a method context list"); + return list; + }, + }; + + private int Run(ParseResult result, Func verb) + { + try + { + string verbosity = result.GetValue(Verbosity); + if (verbosity != null) + Logger.SetLogLevel(Logger.ParseLogLevelString(verbosity)); + Logger.OpenLogFile(result.GetValue(LogFile)); + + return verb(); + } + catch (Exception) when (FlushBeforeCrash()) + { + throw; + } + finally + { + Logger.Shutdown(); + } + } + + // Runs as an exception filter, before an unhandled exception terminates the process without running + // finally blocks, so the output written so far isn't lost. + private static bool FlushBeforeCrash() + { + Logger.Flush(); + return false; + } + + // File operands optionally preceded by a range: a method context number, a list such as 1-5,9, + // or an .mcl file. With one operand more than the number of files, the first one is the range. + private sealed class Operands + { + private readonly string[] _fileNames; + + public Operands(params string[] fileNames) + { + _fileNames = fileNames; + Argument = new Argument("operands") + { + Arity = new ArgumentArity(fileNames.Length, fileNames.Length + 1), + HelpName = "[range] " + string.Join(' ', fileNames), + Description = "Files, optionally preceded by a method context number, a range list such as 1-5,9, or an .mcl file", + }; + } + + public Argument Argument { get; } + + private bool HasRange(string[] tokens) => tokens.Length > _fileNames.Length; + + public string File(ParseResult result, int index) + { + string[] tokens = result.GetValue(Argument); + return tokens[index + (HasRange(tokens) ? 1 : 0)]; + } + + public int[] Range(ParseResult result) => ParseRange(result.GetValue(Argument), out _); + + public int[] Range(CommandResult result) => ParseRange(result.GetValue(Argument), out _); + + private int[] ParseRange(string[] tokens, out string error) + { + error = null; + if (tokens == null || !HasRange(tokens)) + return null; + if (MCList.TryParse(tokens[0], out int[] list, out error)) + return list; + error ??= "not a method context list"; + return null; + } + + public void Validate(CommandResult result) + { + string[] tokens = result.GetValue(Argument); + if (tokens != null && HasRange(tokens)) + { + ParseRange(tokens, out string error); + if (error != null) + result.AddError($"Invalid range '{tokens[0]}': {error}"); + } + } + } +} diff --git a/src/coreclr/tools/superpmi/managed/mcs/Program.cs b/src/coreclr/tools/superpmi/managed/mcs/Program.cs new file mode 100644 index 00000000000000..462f80486f796c --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/mcs/Program.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace SuperPmi.Mcs; + +internal static class Program +{ + private static int Main(string[] args) => + new McsRootCommand() + .Parse(args) + .Invoke(new() + { + EnableDefaultExceptionHandler = false + }); +} diff --git a/src/coreclr/tools/superpmi/managed/mcs/VerbDump.cs b/src/coreclr/tools/superpmi/managed/mcs/VerbDump.cs new file mode 100644 index 00000000000000..4dd966b852579a --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/mcs/VerbDump.cs @@ -0,0 +1,75 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Internal.JitInterface; + +namespace SuperPmi.Mcs; + +internal static class VerbDump +{ + public static int DoWork(string nameOfInput, int[] indexes, bool simple) + { + Logger.LogVerbose($"Dumping '{nameOfInput}' to console"); + + using var mci = new MethodContextIterator(indexes); + if (!mci.Initialize(nameOfInput)) + return -1; + + int dumpedCount = 0; + while (mci.MoveNext()) + { + mci.Current.dumpToConsole(mci.MethodContextNumber, simple); + dumpedCount++; + } + + Logger.LogVerbose($"Dumped {dumpedCount} methodContexts"); + + return mci.Destroy() ? 0 : -1; + } +} + +internal static unsafe class VerbASMDump +{ + // Writes one -.asm file per method context. Open-source builds have no disassembler, + // so only the header is written. + public static int DoWork(string nameOfInput, string nameOfOutput, int[] indexes) + { + Logger.LogVerbose($"Loading from '{nameOfInput}' and writing ASM output into '{nameOfOutput}-MC#.asm'"); + + using var mci = new MethodContextIterator(indexes, progressReport: true); + if (!mci.Initialize(nameOfInput)) + return -1; + + int savedCount = 0; + while (mci.MoveNext()) + { + MethodContext mc = mci.Current; + using (System.IO.FileStream output = FileHelpers.CreateOutput($"{nameOfOutput}-{mci.MethodContextNumber}.asm")) + { + if (output == null) + return -1; + + string text = mc.cr.IsEmpty() ? ";;Method context has no compile result" : DumpToFile(mc); + output.Write(System.Text.Encoding.UTF8.GetBytes(text)); + } + savedCount++; + } + + Logger.LogInfo($"Asm'd {savedCount}"); + + return mci.Destroy() ? 0 : -1; + } + + private static string DumpToFile(MethodContext mc) + { + CORINFO_METHOD_INFO info = mc.repCompileMethod(out _, out _); + + string header = CFormat.Sprintf(";;Generated from SuperPMI on original input '%s'", mc.cr.repProcessName()) + + CFormat.Sprintf("\r\n Method Name \"%s\"", CallUtils.getMethodName(mc, info.ftn)); + + // A disassembler would read the code here, and relocate it; reading it checks that it was recorded. + mc.cr.AllocMem.Get(0); + + return header + ";; No disassembler available"; + } +} diff --git a/src/coreclr/tools/superpmi/managed/mcs/VerbDumpMap.cs b/src/coreclr/tools/superpmi/managed/mcs/VerbDumpMap.cs new file mode 100644 index 00000000000000..f86f54f130a829 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/mcs/VerbDumpMap.cs @@ -0,0 +1,224 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using Internal.JitInterface; + +using static SuperPmi.SpmiRecordsHelper; + +namespace SuperPmi.Mcs; + +// Signature printing shared by -dumpMap and -ildump. +internal static unsafe class SigDumper +{ + private static TextWriter Out => Logger.Out; + + public static void DumpPrimToConsoleBare(MethodContext mc, CorInfoType prim, CORINFO_CLASS_STRUCT_* classHandle) + { + switch (prim) + { + case CorInfoType.CORINFO_TYPE_VOID: Out.Write("void"); return; + case CorInfoType.CORINFO_TYPE_BOOL: Out.Write("bool"); return; + case CorInfoType.CORINFO_TYPE_CHAR: Out.Write("char"); return; + case CorInfoType.CORINFO_TYPE_BYTE: Out.Write("int8"); return; + case CorInfoType.CORINFO_TYPE_UBYTE: Out.Write("unsigned int8"); return; + case CorInfoType.CORINFO_TYPE_SHORT: Out.Write("int16"); return; + case CorInfoType.CORINFO_TYPE_USHORT: Out.Write("unsigned int16"); return; + case CorInfoType.CORINFO_TYPE_INT: Out.Write("int32"); return; + case CorInfoType.CORINFO_TYPE_UINT: Out.Write("unsigned int32"); return; + case CorInfoType.CORINFO_TYPE_LONG: Out.Write("int64"); return; + case CorInfoType.CORINFO_TYPE_ULONG: Out.Write("unsigned int64"); return; + case CorInfoType.CORINFO_TYPE_NATIVEINT: Out.Write("native int"); return; + case CorInfoType.CORINFO_TYPE_NATIVEUINT: Out.Write("native unsigned int"); return; + case CorInfoType.CORINFO_TYPE_FLOAT: Out.Write("float32"); return; + case CorInfoType.CORINFO_TYPE_DOUBLE: Out.Write("float64"); return; + case CorInfoType.CORINFO_TYPE_PTR: Out.Write("ptr"); return; + case CorInfoType.CORINFO_TYPE_BYREF: Out.Write("byref"); return; + case CorInfoType.CORINFO_TYPE_VALUECLASS: + case CorInfoType.CORINFO_TYPE_CLASS: + uint arrayRank = mc.repGetArrayRank(classHandle); + if (arrayRank > 0) + { + CORINFO_CLASS_STRUCT_* childCls; + CorInfoType childType = mc.repGetChildType(classHandle, &childCls); + DumpPrimToConsoleBare(mc, childType, childCls); + Out.Write('['); + for (uint i = 1; i < arrayRank; i++) + Out.Write(','); + Out.Write(']'); + } + else + { + Out.Write(prim == CorInfoType.CORINFO_TYPE_VALUECLASS ? "valueclass " : "class "); + Out.Write(PrintClassName(mc, classHandle)); + } + return; + default: + Logger.LogWarning($"unknown type in PrimToString(0x{(int)prim:x})"); + return; + } + } + + public static void DumpSigToConsoleBare(MethodContext mc, CORINFO_SIG_INFO sig) + { + CORINFO_ARG_LIST_STRUCT_* currentItem = sig.args; + for (int i = 0; i < sig.numArgs; i++) + { + CORINFO_CLASS_STRUCT_* dl; + CorInfoTypeWithMod type = mc.repGetArgType(&sig, currentItem, &dl, out _); + CorInfoType cit = TypeUtils.strip(type); + if (cit == CorInfoType.CORINFO_TYPE_CLASS) + dl = mc.repGetArgClass(&sig, currentItem, out _); + if ((type & CorInfoTypeWithMod.CORINFO_TYPE_MOD_PINNED) == CorInfoTypeWithMod.CORINFO_TYPE_MOD_PINNED) + Out.Write("pinned "); + DumpPrimToConsoleBare(mc, cit, dl); + currentItem = mc.repGetArgNext(currentItem); + if (i + 1 < sig.numArgs) + Out.Write(", "); + } + } + + public static void DumpAttributeToConsoleBare(uint attribute) + { + var flags = (CorInfoFlag)attribute; + if ((flags & CorInfoFlag.CORINFO_FLG_STATIC) == CorInfoFlag.CORINFO_FLG_STATIC) + Out.Write("static "); + else if ((flags & CorInfoFlag.CORINFO_FLG_DONT_INLINE) == CorInfoFlag.CORINFO_FLG_DONT_INLINE) + Out.Write("$dontInline "); + else if ((flags & CorInfoFlag.CORINFO_FLG_CONSTRUCTOR) == CorInfoFlag.CORINFO_FLG_CONSTRUCTOR) + Out.Write("$constructor "); + } + + // A name printed into a fixed 256-byte buffer, truncated to fit. + public static string PrintName(MethodContext mc, string mapName, LightWeightMap map, ulong handle) + { + byte* buffer = stackalloc byte[256]; + int length = (int)mc.repPrint(mapName, map, handle, buffer, 256, null); + int nul = new ReadOnlySpan(buffer, length).IndexOf((byte)0); + return Encoding.UTF8.GetString(buffer, nul >= 0 ? nul : length); + } + + public static string PrintClassName(MethodContext mc, CORINFO_CLASS_STRUCT_* cls) => PrintName(mc, "PrintClassName", mc.PrintClassName, CastHandle(cls)); + + public static string PrintMethodName(MethodContext mc, CORINFO_METHOD_STRUCT_* meth) => PrintName(mc, "PrintMethodName", mc.PrintMethodName, CastHandle(meth)); +} + +internal static unsafe class VerbDumpMap +{ + // CSV: index, method name, full signature, jit flags, os. + public static int DoWork(string nameOfInput) + { + using var mci = new MethodContextIterator(); + if (!mci.Initialize(nameOfInput)) + return -1; + + TextWriter output = Logger.Out; + output.Write("index,method name,full signature,jit flags,os\n"); + + while (mci.MoveNext()) + DumpMap(output, mci.MethodContextNumber, mci.Current); + + return mci.Destroy() ? 0 : -1; + } + + private static void DumpMap(TextWriter output, int index, MethodContext mc) + { + CORINFO_METHOD_INFO cmi = mc.repCompileMethod(out _, out CORINFO_OS os); + + string methodName = SigDumper.PrintMethodName(mc, cmi.ftn); + string className = SigDumper.PrintClassName(mc, mc.repGetMethodClass(cmi.ftn)); + + output.Write($"{index},{className}:{methodName},"); + + output.Write('"'); + SigDumper.DumpAttributeToConsoleBare(mc.repGetMethodAttribs(cmi.ftn)); + SigDumper.DumpPrimToConsoleBare(mc, cmi.args.retType, cmi.args.retTypeClass); + output.Write($" {methodName}"); + + // Class and method generic parameters, if there are any. + CORINFO_SIG_INFO sig; + mc.repGetMethodSig(cmi.ftn, &sig, null); + WriteInstantiation(output, mc, sig.sigInst.classInstCount, sig.sigInst.classInst); + WriteInstantiation(output, mc, sig.sigInst.methInstCount, sig.sigInst.methInst); + + output.Write('('); + SigDumper.DumpSigToConsoleBare(mc, cmi.args); + output.Write(")\""); + + output.Write($", {SpmiDumpHelper.DumpJitFlags(ExtraJitFlags.GetFlagsWithPgo(mc))}, {(int)os}\n"); + } + + private static void WriteInstantiation(TextWriter output, MethodContext mc, uint count, CORINFO_CLASS_STRUCT_** handles) + { + for (uint i = 0; i < count; i++) + { + output.Write(i == 0 ? "[" : ""); + output.Write(i > 0 ? ", " : ""); + output.Write(SigDumper.PrintClassName(mc, handles[i])); + output.Write(i == count - 1 ? "]" : ""); + } + } +} + +internal static class VerbJitFlags +{ + public static int DoWork(string nameOfInput) + { + using var mci = new MethodContextIterator(); + if (!mci.Initialize(nameOfInput)) + return -1; + + // Kept sorted the way LightWeightMap sorts its keys: by memcmp of the little-endian bytes. + var flagMap = new LightWeightMap(); + uint mcCount = 0; + + while (mci.MoveNext()) + { + ulong rawFlags = ExtraJitFlags.GetFlagsWithPgo(mci.Current); + + int index = flagMap.GetIndex(rawFlags); + if (index == -1) + flagMap.Add(rawFlags, 1); + else + flagMap.Update(index, flagMap.GetItem(index) + 1); + + mcCount++; + } + + if (!mci.Destroy()) + return -1; + + TextWriter output = Logger.Out; + output.Write($"\nGrouped Flag Appearances ({mcCount} contexts)\n\n"); + output.Write($"{"bits",-16} {"count",8} {"percent",8} parsed\n"); + + var appearancesPerBit = new uint[64]; + ReadOnlySpan keys = flagMap.GetRawKeys(); + ReadOnlySpan items = flagMap.GetRawItems(); + for (int i = 0; i < keys.Length; i++) + { + ulong flags = keys[i]; + uint appearances = items[i]; + output.Write($"{flags:x16} {appearances,8} {100.0 * appearances / mcCount,7:F2}% {SpmiDumpHelper.DumpJitFlags(flags)}\n"); + + for (int bit = 0; bit < 64; bit++) + { + if ((flags & (1UL << bit)) != 0) + appearancesPerBit[bit] += appearances; + } + } + + output.Write("\nIndividual Flag Appearances\n\n"); + for (int bit = 0; bit < 64; bit++) + { + uint perBit = appearancesPerBit[bit]; + if (perBit > 0) + output.Write($"{perBit,8} {100.0 * perBit / mcCount,7:F2}% {SpmiDumpHelper.DumpJitFlags(1UL << bit)}\n"); + } + + return 0; + } +} diff --git a/src/coreclr/tools/superpmi/managed/mcs/VerbILDump.cs b/src/coreclr/tools/superpmi/managed/mcs/VerbILDump.cs new file mode 100644 index 00000000000000..4e208a259a78f9 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/mcs/VerbILDump.cs @@ -0,0 +1,60 @@ +// 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 Internal.JitInterface; + +namespace SuperPmi.Mcs; + +internal static class VerbILDump +{ + public static int DoWork(string nameOfInput, int[] indexes) + { + Logger.LogVerbose($"// Reading from '{nameOfInput}' dumping raw IL for MC Indexes to console"); + + using var mci = new MethodContextIterator(indexes); + if (!mci.Initialize(nameOfInput)) + return -1; + + int dumpedCount = 0; + while (mci.MoveNext()) + { + ILDumper.DumpIL(mci.Current); + dumpedCount++; + } + + Logger.LogInfo($"// Dumped {dumpedCount}"); + + return mci.Destroy() ? 0 : -1; + } +} + +internal static unsafe partial class ILDumper +{ + private static System.IO.TextWriter Out => Logger.Out; + + public static void DumpIL(MethodContext mc) + { + CORINFO_METHOD_INFO cmi = mc.repCompileMethod(out _, out _); + + CFormat.Printf(Out, "// ProcessName - '%s'\n", mc.cr.repProcessName()); + Out.Write(".assembly extern mscorlib{}\n"); + Out.Write(".assembly dumped_asm\n"); + CFormat.Printf(Out, ".class %s\n", CallUtils.getClassName(mc, mc.repGetMethodClass(cmi.ftn))); + Out.Write("{\n"); + Out.Write(" .method "); + SigDumper.DumpAttributeToConsoleBare(mc.repGetMethodAttribs(cmi.ftn)); + SigDumper.DumpPrimToConsoleBare(mc, cmi.args.retType, cmi.args.retTypeClass); + CFormat.Printf(Out, " %s(", CallUtils.getMethodName(mc, cmi.ftn)); + SigDumper.DumpSigToConsoleBare(mc, cmi.args); + Out.Write(")\n"); + Out.Write(" {\n"); + CFormat.Printf(Out, " .maxstack %u\n", cmi.maxStack); + Out.Write((cmi.options & CorInfoOptions.CORINFO_OPT_INIT_LOCALS) == CorInfoOptions.CORINFO_OPT_INIT_LOCALS ? " .locals init (" : " .locals ("); + SigDumper.DumpSigToConsoleBare(mc, cmi.locals); + Out.Write(")\n"); + DumpILToConsoleBare(Out, new ReadOnlySpan(cmi.ILCode, (int)cmi.ILCodeSize).ToArray(), (int)cmi.ILCodeSize); + Out.Write(" }\n"); + Out.Write("}\n"); + } +} diff --git a/src/coreclr/tools/superpmi/managed/mcs/VerbMerge.cs b/src/coreclr/tools/superpmi/managed/mcs/VerbMerge.cs new file mode 100644 index 00000000000000..a96aa9c1cd5cce --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/mcs/VerbMerge.cs @@ -0,0 +1,288 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.IO.Enumeration; +using Internal.JitInterface; + +namespace SuperPmi.Mcs; + +internal static class VerbMerge +{ + private const int BufferSize = 0x10000000; + + // Merges the files matching 'pattern' into one output file. The pattern is one of: + // 1. *.mc -- assumes the current directory. + // 2. foo/bar/*.mc -- with a relative directory. + // 3. /foo/bar/baz/*.mc -- with a full path. + // Without a wildcard, the last component is a directory name, and all its files are merged. + // 'recursive' also searches all child directories. 'dedup' removes duplicates while merging, + // and 'stripCR' also removes CompileResults. + public static int DoWork(string nameOfOutputFile, string pattern, bool recursive, bool dedup, bool stripCR) + { + Logger.LogInfo($"Merging files matching '{pattern}' into '{nameOfOutputFile}'"); + + RemoveDup removeDups = dedup ? new RemoveDup(stripCR, legacyCompare: false) : null; + + string dir; + string file; + int lastSlash = pattern.LastIndexOf(Path.DirectorySeparatorChar); + if (lastSlash < 0) + { + // A pattern with a wildcard in the current directory, or else a directory name. + if (pattern.Contains('*')) + { + file = pattern; + dir = "."; + } + else + { + file = "*"; + dir = pattern; + } + } + else if (pattern.IndexOf('*', lastSlash) < 0) + { + file = "*"; + dir = lastSlash == pattern.Length - 1 ? pattern.Substring(0, lastSlash) : pattern; + } + else + { + dir = pattern.Substring(0, lastSlash); + file = pattern.Substring(lastSlash + 1); + } + + int result; + long totalSize = 0; + using (FileStream output = FileHelpers.CreateOutput(nameOfOutputFile)) + { + if (output == null) + return -1; + + var timer = Stopwatch.StartNew(); + byte[] buffer = new byte[BufferSize]; + result = AppendAllInDir(output, dir, file, buffer, recursive, removeDups, ref totalSize); + timer.Stop(); + + if (result == 0) + Logger.LogInfo(FileHelpers.Rate(totalSize, timer)); + } + + if (result != 0) + { + // Don't leave a half-created file behind. + try + { + File.Delete(nameOfOutputFile); + } + catch (Exception e) when (e is IOException or UnauthorizedAccessException) + { + Logger.LogError($"Failed to delete file after MCS /merge failed. GetLastError()={ErrorHandling.LastError(e)}"); + } + } + else if (totalSize == 0) + { + Logger.LogError("No files found to merge."); + result = 1; + } + + return result; + } + + private static int AppendAllInDir(FileStream output, string dir, string file, byte[] buffer, bool recursive, RemoveDup removeDups, ref long totalSize) + { + if (!FilterDirectory(dir, file, wantDirectories: false, out List files)) + return -1; + + foreach (string name in files) + { + string fileFullPath = dir + Path.DirectorySeparatorChar + name; + + long fileSize; + try + { + fileSize = new FileInfo(fileFullPath).Length; + } + catch (Exception e) when (e is IOException or UnauthorizedAccessException) + { + Logger.LogError($"Failed to stat file '{fileFullPath}'. errno={ErrorHandling.LastError(e)}"); + return -1; + } + + if (fileSize == 0) + { + Logger.LogInfo($"Skipping zero-length file '{fileFullPath}'"); + } + else + { + int result = AppendFile(output, fileFullPath, removeDups, buffer); + if (result != 0) + return result; + } + + totalSize += fileSize; + } + + if (recursive) + { + if (!FilterDirectory(dir, "*", wantDirectories: true, out List subDirs)) + return -1; + + foreach (string name in subDirs) + { + int result = AppendAllInDir(output, dir + Path.DirectorySeparatorChar + name, file, buffer, recursive, removeDups, ref totalSize); + if (result != 0) + return result; + } + } + + return 0; + } + + private static int AppendFile(FileStream output, string fileFullPath, RemoveDup removeDups, byte[] buffer) + { + Logger.LogInfo($"Appending file '{fileFullPath}'"); + + if (removeDups != null) + { + if (!removeDups.CopyAndRemoveDups(fileFullPath, output)) + { + Logger.LogError("Failed to remove dups"); + return -1; + } + return 0; + } + + try + { + using var input = new FileStream(fileFullPath, FileMode.Open, FileAccess.Read, FileShare.Read, 1, FileOptions.SequentialScan); + int read; + while ((read = input.Read(buffer)) > 0) + output.Write(buffer, 0, read); + } + catch (Exception e) when (e is IOException or UnauthorizedAccessException) + { + Logger.LogError($"Failed to open input file '{fileFullPath}'. GetLastError()={ErrorHandling.LastError(e)}"); + return -1; + } + return 0; + } + + // Lists the files (or directories) in 'dir' matching 'searchPattern', sorted by name. + // A directory that doesn't exist just has no matches. + private static bool FilterDirectory(string dir, string searchPattern, bool wantDirectories, out List names) + { + names = new List(); + + if (!Directory.Exists(dir)) + return true; + + bool ignoreCase = OperatingSystem.IsWindows(); + try + { + var options = new EnumerationOptions { AttributesToSkip = 0, IgnoreInaccessible = false, RecurseSubdirectories = false }; + foreach (string path in Directory.EnumerateFileSystemEntries(dir, "*", options)) + { + string name = Path.GetFileName(path); + if (!FileSystemName.MatchesSimpleExpression(searchPattern, name, ignoreCase)) + continue; + + FileAttributes attributes = File.GetAttributes(path); + bool isDirectory = (attributes & FileAttributes.Directory) != 0; + if (wantDirectories) + { + // Skip links (possible loops), and on Windows system and hidden directories. + const FileAttributes skipped = FileAttributes.ReparsePoint | FileAttributes.System | FileAttributes.Hidden; + if (!isDirectory || (attributes & (OperatingSystem.IsWindows() ? skipped : FileAttributes.ReparsePoint)) != 0) + continue; + } + else if (isDirectory) + { + continue; + } + + names.Add(name); + } + } + catch (Exception e) when (e is IOException or UnauthorizedAccessException) + { + Logger.LogError($"Failed to read directory. errno={ErrorHandling.LastError(e)}"); + return false; + } + + names.Sort(string.CompareOrdinal); + return true; + } +} + +// Removes duplicate method contexts while copying. Method contexts are bucketed by IL size, then +// compared by method hash (ignoring the method name), or with MethodContext.Equal for the legacy mode. +internal sealed unsafe class RemoveDup +{ + private readonly bool m_stripCR; + private readonly bool m_legacyCompare; + private readonly Dictionary> m_inFile = new(); + private readonly Dictionary> m_inFileLegacy = new(); + + public RemoveDup(bool stripCR, bool legacyCompare) + { + m_stripCR = stripCR; + m_legacyCompare = legacyCompare; + } + + private bool unique(MethodContext mc) + { + CORINFO_METHOD_INFO info = mc.repCompileMethod(out uint flags, out _); + string hash = mc.dumpMethodHashToBuffer(ignoreMethodName: true, &info, flags); + + if (!m_inFile.TryGetValue(info.ILCodeSize, out HashSet ourRank)) + m_inFile.Add(info.ILCodeSize, ourRank = new HashSet(StringComparer.Ordinal)); + + return ourRank.Add(hash); + } + + private bool uniqueLegacy(MethodContext mc) + { + CORINFO_METHOD_INFO info = mc.repCompileMethod(out _, out _); + + if (!m_inFileLegacy.TryGetValue(info.ILCodeSize, out List ourRank)) + m_inFileLegacy.Add(info.ILCodeSize, ourRank = new List()); + + foreach (MethodContext scratch in ourRank) + { + if (mc.Equal(scratch)) + return false; + } + + ourRank.Add(mc); + return true; + } + + public bool CopyAndRemoveDups(string nameOfInput, Stream output) + { + using var mci = new MethodContextIterator(progressReport: true); + if (!mci.Initialize(nameOfInput)) + return false; + + int savedCount = 0; + while (mci.MoveNext()) + { + MethodContext mc = mci.CurrentTakeOwnership(); + if (m_stripCR) + mc.cr = new CompileResult(); + + if (m_legacyCompare ? uniqueLegacy(mc) : unique(mc)) + { + mc.saveToFile(output); + savedCount++; + } + } + + Logger.LogInfo($"Loaded {mci.MethodContextNumber}, Saved {savedCount}"); + + return mci.Destroy(); + } +} diff --git a/src/coreclr/tools/superpmi/managed/mcs/Verbs.cs b/src/coreclr/tools/superpmi/managed/mcs/Verbs.cs new file mode 100644 index 00000000000000..f737c0b80db66e --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/mcs/Verbs.cs @@ -0,0 +1,382 @@ +// 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.Diagnostics; +using System.IO; +using System.Text; + +namespace SuperPmi.Mcs; + +internal static class FileHelpers +{ + public static FileStream CreateOutput(string fileName) + { + try + { + return new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None, 1 << 20, FileOptions.SequentialScan); + } + catch (Exception e) when (e is IOException or UnauthorizedAccessException) + { + Logger.LogError($"Failed to open output file '{fileName}'. GetLastError()={ErrorHandling.LastError(e)}"); + return null; + } + } + + public static string Rate(long bytes, Stopwatch timer) + => $"Read/Wrote {bytes / (1000 * 1000)} MB @ {bytes / (1000.0 * 1000) / timer.Elapsed.TotalSeconds,4:F2} MB/s."; +} + +internal static class VerbConcat +{ + private const int BufferSize = 0xFFFFFF; + + // Appends file2 to file1, without regard to the internal format. + public static int DoWork(string nameOfFile1, string nameOfFile2) + { + Logger.LogVerbose($"Concatenating '{nameOfFile1}'+'{nameOfFile2}' into {nameOfFile1}"); + + FileStream file1; + try + { + file1 = new FileStream(nameOfFile1, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None, 1, FileOptions.SequentialScan); + } + catch (Exception e) when (e is IOException or UnauthorizedAccessException) + { + Logger.LogError($"Failed to open input 1 '{nameOfFile1}'. GetLastError()={ErrorHandling.LastError(e)}"); + return -1; + } + + using (file1) + { + file1.Seek(0, SeekOrigin.End); + + FileStream file2; + try + { + file2 = new FileStream(nameOfFile2, FileMode.Open, FileAccess.Read, FileShare.Read, 1, FileOptions.SequentialScan); + } + catch (Exception e) when (e is IOException or UnauthorizedAccessException) + { + Logger.LogError($"Failed to open input 2 '{nameOfFile2}'. GetLastError()={ErrorHandling.LastError(e)}"); + return -1; + } + + using (file2) + { + long size = file2.Length; + var timer = Stopwatch.StartNew(); + byte[] buffer = new byte[BufferSize]; + int read; + while ((read = file2.Read(buffer)) > 0) + file1.Write(buffer, 0, read); + timer.Stop(); + + Logger.LogInfo(FileHelpers.Rate(size, timer) + "\n"); + } + } + return 0; + } +} + +internal static class VerbStrip +{ + // Handles both "-copy" and "-strip": both copy from the input file to the output file, but + // treat the indexes in opposite ways. + public static int DoWork(string nameOfInput, string nameOfOutput, int[] indexes, bool strip, bool stripCR) + { + if (strip) + return DoWorkTheOldWay(nameOfInput, nameOfOutput, indexes ?? [], stripCR); + + Logger.LogVerbose($"Reading from '{nameOfInput}' removing Mc Indexes and writing into '{nameOfOutput}'"); + + // The reader skips unrequested method contexts, using the TOC if there is one. + using var reader = new MethodContextReader(nameOfInput, indexes); + if (!reader.isValid()) + return -1; + + using FileStream output = FileHelpers.CreateOutput(nameOfOutput); + if (output == null) + return -1; + + var timer = Stopwatch.StartNew(); + int loadedCount = 0; + int savedCount = 0; + while (true) + { + MethodContextBuffer mcb = reader.GetNextMethodContext(); + if (mcb.Error()) + return -1; + if (mcb.allDone()) + break; + + loadedCount++; + if (loadedCount % 500 == 0) + { + Logger.LogVerbose($"{reader.PercentComplete(),2:F1}% - Loaded {loadedCount} at {(int)(500 / timer.Elapsed.TotalSeconds)} per second"); + timer.Restart(); + } + + if (!MethodContext.Initialize(loadedCount, mcb.buff, (uint)mcb.size, !stripCR, out MethodContext mc)) + return -1; + + mc.saveToFile(output); + savedCount++; + } + + Logger.LogInfo($"Loaded {loadedCount}, Saved {savedCount}"); + return 0; + } + + private static int DoWorkTheOldWay(string nameOfInput, string nameOfOutput, int[] indexes, bool stripCR) + { + Logger.LogVerbose($"Reading from '{nameOfInput}' removing MC Indexes and writing into '{nameOfOutput}'"); + + using var mci = new MethodContextIterator(progressReport: true); + if (!mci.Initialize(nameOfInput)) + return -1; + + int savedCount = 0; + int index = 0; + + using (FileStream output = FileHelpers.CreateOutput(nameOfOutput)) + { + if (output == null) + return -1; + + while (mci.MoveNext()) + { + MethodContext mc = mci.Current; + + if (index < indexes.Length && indexes[index] == mci.MethodContextNumber) + { + index++; + continue; + } + + if (stripCR) + mc.cr = new CompileResult(); + mc.saveToFile(output); + savedCount++; + } + } + + if (index < indexes.Length) + Logger.LogWarning($"Didn't use all of index count input {index} < {indexes.Length} (i.e. didn't see MC #{indexes[index]})"); + + Logger.LogInfo($"Loaded {mci.MethodContextNumber}, Saved {savedCount}"); + + return mci.Destroy() ? 0 : -1; + } +} + +internal static class VerbFracture +{ + public static int DoWork(string nameOfInput, string nameOfOutput, int[] indexes, bool stripCR) + { + if (indexes.Length == 0) + { + Logger.LogError("-fracture requires a range."); + return -1; + } + if (indexes.Length > 1) + Logger.LogWarning("-fracture found multiple ranges, we'll use the first one."); + + int rangeSize = indexes[0]; + + Logger.LogVerbose($"Reading from '{nameOfInput}' copying {rangeSize} MethodContexts files into each output file of '{nameOfOutput}'"); + + using var mci = new MethodContextIterator(progressReport: true); + if (!mci.Initialize(nameOfInput)) + return -1; + + int fileCount = 0; + FileStream output = null; + try + { + while (mci.MoveNext()) + { + MethodContext mc = mci.Current; + + if (output == null || ((mci.MethodContextNumber - 1) % rangeSize) == 0) + { + output?.Dispose(); + output = FileHelpers.CreateOutput($"{nameOfOutput}-{fileCount++:D5}.mch"); + if (output == null) + return -1; + } + + if (stripCR) + mc.cr = new CompileResult(); + mc.saveToFile(output); + } + } + finally + { + output?.Dispose(); + } + + Logger.LogInfo($"Output fileCount {fileCount}"); + + return mci.Destroy() ? 0 : -1; + } +} + +internal static class VerbDumpToc +{ + public static int DoWork(string nameOfInput) + { + var tf = new TOCFile(); + tf.LoadToc(nameOfInput, validate: false); + + var sb = new StringBuilder(); + for (int i = 0; i < tf.GetTocCount(); i++) + { + TOCElement te = tf.GetElement(i); + sb.Clear(); + sb.Append($"{(uint)te.Number,4}: {te.Offset:X16} "); + foreach (byte b in te.Hash) + sb.Append(((int)(sbyte)b).ToString("x2")).Append(' '); + sb.Append('\n'); + Logger.Out.Write(sb); + } + + return 0; + } +} + +internal static class VerbInteg +{ + public static int DoWork(string nameOfInput) + { + Logger.LogVerbose($"Checking the integrity of '{nameOfInput}'"); + + var timer = Stopwatch.StartNew(); + + using var mci = new MethodContextIterator(progressReport: true); + if (!mci.Initialize(nameOfInput)) + return -1; + + // Nothing to do except load each one. + while (mci.MoveNext()) + { + } + + timer.Stop(); + Logger.LogInfo($"Checked the integrity of {mci.MethodContextNumber} methodContexts at {(int)(mci.MethodContextNumber / timer.Elapsed.TotalSeconds)} per second"); + + return mci.Destroy() ? 0 : -1; + } +} + +internal static class VerbStat +{ + public static int DoWork(string nameOfInput, string nameOfOutput, int[] indexes) + { + Logger.LogVerbose($"Stat'ing from '{nameOfInput}' and writing output into '{nameOfOutput}'"); + + using var mci = new MethodContextIterator(indexes, progressReport: true); + if (!mci.Initialize(nameOfInput)) + return -1; + + int savedCount = 0; + using (FileStream output = FileHelpers.CreateOutput(nameOfOutput)) + { + if (output == null) + return -1; + + var sb = new StringBuilder("Title,MC#,"); + MethodContext.dumpStatTitleToBuffer(sb); + sb.Append("\r\n"); + output.Write(Encoding.UTF8.GetBytes(sb.ToString())); + + while (mci.MoveNext()) + { + MethodContext mc = mci.Current; + + sb.Clear(); + if (mc.cr.ProcessName != null && mc.cr.ProcessName.GetCount() > 0) + sb.Append(mc.cr.repProcessName()); + sb.Append(','); + sb.Append(mci.MethodContextNumber).Append(','); + mc.dumpStatToBuffer(sb); + sb.Append("\r\n"); + output.Write(Encoding.UTF8.GetBytes(sb.ToString())); + savedCount++; + } + } + + Logger.LogInfo($"Loaded {mci.MethodContextNumber}, Stat'd {savedCount}"); + + return mci.Destroy() ? 0 : -1; + } +} + +internal static class VerbPrintJITEEVersion +{ + // Tools use this to pick the MCH files that match a JIT built from the same source tree. + public static int DoWork() + { + Logger.Out.Write(JitEEVersion.Identifier.ToString("D") + "\n"); + return 0; + } +} + +internal static class VerbTOC +{ + public static int DoWork(string nameOfInput) + { + Logger.LogVerbose($"Indexing from '{nameOfInput}' into '{nameOfInput}.mct'"); + + using var mci = new MethodContextIterator(); + if (!mci.Initialize(nameOfInput)) + return -1; + + var elements = new System.Collections.Generic.List(); + while (mci.MoveNext()) + { + MethodContext mc = mci.Current; + elements.Add(new TOCElement(mci.MethodContextNumber, mci.CurrentPos, mc.dumpMethodHashToBuffer())); + } + + string nameOfOutput = nameOfInput + ".mct"; + using (FileStream output = FileHelpers.CreateOutput(nameOfOutput)) + { + if (output == null) + return -1; + + byte[] data = new byte[8 + elements.Count * TOCElement.Size + 4]; + System.Buffers.Binary.BinaryPrimitives.WriteUInt32LittleEndian(data, TOCFile.Sentinel); + System.Buffers.Binary.BinaryPrimitives.WriteInt32LittleEndian(data.AsSpan(4), elements.Count); + for (int i = 0; i < elements.Count; i++) + elements[i].Write(data.AsSpan(8 + i * TOCElement.Size)); + System.Buffers.Binary.BinaryPrimitives.WriteUInt32LittleEndian(data.AsSpan(data.Length - 4), TOCFile.Sentinel); + output.Write(data); + } + + Logger.LogInfo($"Loaded {mci.MethodContextNumber}, added {elements.Count} to Table of Contents"); + + return mci.Destroy() ? 0 : -1; + } +} + +internal static class VerbRemoveDup +{ + public static int DoWork(string nameOfInput, string nameOfOutput, bool stripCR, bool legacyCompare) + { + Logger.LogVerbose($"Removing duplicates from '{nameOfInput}', writing to '{nameOfOutput}'"); + + var removeDups = new RemoveDup(stripCR, legacyCompare); + + using FileStream output = FileHelpers.CreateOutput(nameOfOutput); + if (output == null) + return -1; + + if (!removeDups.CopyAndRemoveDups(nameOfInput, output)) + { + Logger.LogError("Failed to remove dups"); + return -1; + } + return 0; + } +} diff --git a/src/coreclr/tools/superpmi/managed/mcs/mcs.csproj b/src/coreclr/tools/superpmi/managed/mcs/mcs.csproj new file mode 100644 index 00000000000000..ec94a19efc130b --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/mcs/mcs.csproj @@ -0,0 +1,19 @@ + + + mcs + Exe + true + + + true + true + true + $(PortableOS)-$(TargetArchitecture) + $(RuntimeBinDir) + + + + + + + diff --git a/src/coreclr/tools/superpmi/managed/shim/CorInfoImpl_forwarding_generated.cs b/src/coreclr/tools/superpmi/managed/shim/CorInfoImpl_forwarding_generated.cs new file mode 100644 index 00000000000000..91bc1150160738 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/shim/CorInfoImpl_forwarding_generated.cs @@ -0,0 +1,1114 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// DO NOT EDIT THIS FILE! IT IS AUTOGENERATED +// To regenerate run the gen script in src/coreclr/tools/Common/JitInterface/ThunkGenerator +// and follow the instructions in docs/project/updating-jitinterface.md + +using System; + +namespace Internal.JitInterface; + +internal sealed unsafe partial class CorInfoImpl +{ + // Called before each call is forwarded, with the name of the ICorJitInfo method. + partial void OnCall(string name); + + private bool isIntrinsic(CORINFO_METHOD_STRUCT_* ftn) + { + OnCall("isIntrinsic"); + return _original.isIntrinsic(ftn); + } + + private bool canValueClassInstancePointerEscape(CORINFO_METHOD_STRUCT_* ftn) + { + OnCall("canValueClassInstancePointerEscape"); + return _original.canValueClassInstancePointerEscape(ftn); + } + + private bool notifyMethodInfoUsage(CORINFO_METHOD_STRUCT_* ftn) + { + OnCall("notifyMethodInfoUsage"); + return _original.notifyMethodInfoUsage(ftn); + } + + private uint getMethodAttribs(CORINFO_METHOD_STRUCT_* ftn) + { + OnCall("getMethodAttribs"); + return _original.getMethodAttribs(ftn); + } + + private void setMethodAttribs(CORINFO_METHOD_STRUCT_* ftn, CorInfoMethodRuntimeFlags attribs) + { + OnCall("setMethodAttribs"); + _original.setMethodAttribs(ftn, attribs); + } + + private void getMethodSig(CORINFO_METHOD_STRUCT_* ftn, CORINFO_SIG_INFO* sig, CORINFO_CLASS_STRUCT_* memberParent) + { + OnCall("getMethodSig"); + _original.getMethodSig(ftn, sig, memberParent); + } + + private bool getMethodInfo(CORINFO_METHOD_STRUCT_* ftn, CORINFO_METHOD_INFO* info, CORINFO_CONTEXT_STRUCT* context) + { + OnCall("getMethodInfo"); + return _original.getMethodInfo(ftn, info, context); + } + + private bool haveSameMethodDefinition(CORINFO_METHOD_STRUCT_* meth1Hnd, CORINFO_METHOD_STRUCT_* meth2Hnd) + { + OnCall("haveSameMethodDefinition"); + return _original.haveSameMethodDefinition(meth1Hnd, meth2Hnd); + } + + private CORINFO_CLASS_STRUCT_* getTypeDefinition(CORINFO_CLASS_STRUCT_* type) + { + OnCall("getTypeDefinition"); + return _original.getTypeDefinition(type); + } + + private CorInfoInline canInline(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* calleeHnd) + { + OnCall("canInline"); + return _original.canInline(callerHnd, calleeHnd); + } + + private void beginInlining(CORINFO_METHOD_STRUCT_* inlinerHnd, CORINFO_METHOD_STRUCT_* inlineeHnd) + { + OnCall("beginInlining"); + _original.beginInlining(inlinerHnd, inlineeHnd); + } + + private void reportInliningDecision(CORINFO_METHOD_STRUCT_* inlinerHnd, CORINFO_METHOD_STRUCT_* inlineeHnd, CorInfoInline inlineResult, byte* reason) + { + OnCall("reportInliningDecision"); + _original.reportInliningDecision(inlinerHnd, inlineeHnd, inlineResult, reason); + } + + private bool canTailCall(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* declaredCalleeHnd, CORINFO_METHOD_STRUCT_* exactCalleeHnd, bool fIsTailPrefix) + { + OnCall("canTailCall"); + return _original.canTailCall(callerHnd, declaredCalleeHnd, exactCalleeHnd, fIsTailPrefix); + } + + private void reportTailCallDecision(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* calleeHnd, bool fIsTailPrefix, CorInfoTailCall tailCallResult, byte* reason) + { + OnCall("reportTailCallDecision"); + _original.reportTailCallDecision(callerHnd, calleeHnd, fIsTailPrefix, tailCallResult, reason); + } + + private void getEHinfo(CORINFO_METHOD_STRUCT_* ftn, uint EHnumber, ref CORINFO_EH_CLAUSE clause) + { + OnCall("getEHinfo"); + _original.getEHinfo(ftn, EHnumber, ref clause); + } + + private CORINFO_CLASS_STRUCT_* getMethodClass(CORINFO_METHOD_STRUCT_* method) + { + OnCall("getMethodClass"); + return _original.getMethodClass(method); + } + + private void getMethodVTableOffset(CORINFO_METHOD_STRUCT_* method, ref uint offsetOfIndirection, ref uint offsetAfterIndirection, ref bool isRelative) + { + OnCall("getMethodVTableOffset"); + _original.getMethodVTableOffset(method, ref offsetOfIndirection, ref offsetAfterIndirection, ref isRelative); + } + + private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) + { + OnCall("resolveVirtualMethod"); + return _original.resolveVirtualMethod(info); + } + + private CORINFO_METHOD_STRUCT_* getAsyncOtherVariant(CORINFO_METHOD_STRUCT_* ftn, ref bool variantIsThunk) + { + OnCall("getAsyncOtherVariant"); + return _original.getAsyncOtherVariant(ftn, ref variantIsThunk); + } + + private CORINFO_CLASS_STRUCT_* getDefaultComparerClass(CORINFO_CLASS_STRUCT_* elemType) + { + OnCall("getDefaultComparerClass"); + return _original.getDefaultComparerClass(elemType); + } + + private CORINFO_CLASS_STRUCT_* getDefaultEqualityComparerClass(CORINFO_CLASS_STRUCT_* elemType) + { + OnCall("getDefaultEqualityComparerClass"); + return _original.getDefaultEqualityComparerClass(elemType); + } + + private CORINFO_CLASS_STRUCT_* getSZArrayHelperEnumeratorClass(CORINFO_CLASS_STRUCT_* elemType) + { + OnCall("getSZArrayHelperEnumeratorClass"); + return _original.getSZArrayHelperEnumeratorClass(elemType); + } + + private void expandRawHandleIntrinsic(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_GENERICHANDLE_RESULT pResult) + { + OnCall("expandRawHandleIntrinsic"); + _original.expandRawHandleIntrinsic(ref pResolvedToken, callerHandle, ref pResult); + } + + private bool isIntrinsicType(CORINFO_CLASS_STRUCT_* classHnd) + { + OnCall("isIntrinsicType"); + return _original.isIntrinsicType(classHnd); + } + + private CorInfoCallConvExtension getUnmanagedCallConv(CORINFO_METHOD_STRUCT_* method, CORINFO_SIG_INFO* callSiteSig, ref bool pSuppressGCTransition) + { + OnCall("getUnmanagedCallConv"); + return _original.getUnmanagedCallConv(method, callSiteSig, ref pSuppressGCTransition); + } + + private bool pInvokeMarshalingRequired(CORINFO_METHOD_STRUCT_* method, CORINFO_SIG_INFO* callSiteSig) + { + OnCall("pInvokeMarshalingRequired"); + return _original.pInvokeMarshalingRequired(method, callSiteSig); + } + + private bool satisfiesMethodConstraints(CORINFO_CLASS_STRUCT_* parent, CORINFO_METHOD_STRUCT_* method) + { + OnCall("satisfiesMethodConstraints"); + return _original.satisfiesMethodConstraints(parent, method); + } + + private void getGSCookie(IntPtr* pCookieVal, IntPtr** ppCookieVal) + { + OnCall("getGSCookie"); + _original.getGSCookie(pCookieVal, ppCookieVal); + } + + private void setPatchpointInfo(PatchpointInfo* patchpointInfo) + { + OnCall("setPatchpointInfo"); + _original.setPatchpointInfo(patchpointInfo); + } + + private PatchpointInfo* getOSRInfo(ref uint ilOffset) + { + OnCall("getOSRInfo"); + return _original.getOSRInfo(ref ilOffset); + } + + private void resolveToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken) + { + OnCall("resolveToken"); + _original.resolveToken(ref pResolvedToken); + } + + private void findSig(CORINFO_MODULE_STRUCT_* module, uint sigTOK, CORINFO_CONTEXT_STRUCT* context, CORINFO_SIG_INFO* sig) + { + OnCall("findSig"); + _original.findSig(module, sigTOK, context, sig); + } + + private void findCallSiteSig(CORINFO_MODULE_STRUCT_* module, uint methTOK, CORINFO_CONTEXT_STRUCT* context, CORINFO_SIG_INFO* sig) + { + OnCall("findCallSiteSig"); + _original.findCallSiteSig(module, methTOK, context, sig); + } + + private CORINFO_CLASS_STRUCT_* getTokenTypeAsHandle(ref CORINFO_RESOLVED_TOKEN pResolvedToken) + { + OnCall("getTokenTypeAsHandle"); + return _original.getTokenTypeAsHandle(ref pResolvedToken); + } + + private int getStringLiteral(CORINFO_MODULE_STRUCT_* module, uint metaTOK, char* buffer, int bufferSize, int startIndex) + { + OnCall("getStringLiteral"); + return _original.getStringLiteral(module, metaTOK, buffer, bufferSize, startIndex); + } + + private nuint printObjectDescription(CORINFO_OBJECT_STRUCT_* handle, byte* buffer, nuint bufferSize, nuint* pRequiredBufferSize) + { + OnCall("printObjectDescription"); + return _original.printObjectDescription(handle, buffer, bufferSize, pRequiredBufferSize); + } + + private CorInfoType asCorInfoType(CORINFO_CLASS_STRUCT_* cls) + { + OnCall("asCorInfoType"); + return _original.asCorInfoType(cls); + } + + private byte* getClassNameFromMetadata(CORINFO_CLASS_STRUCT_* cls, byte** namespaceName) + { + OnCall("getClassNameFromMetadata"); + return _original.getClassNameFromMetadata(cls, namespaceName); + } + + private CORINFO_CLASS_STRUCT_* getTypeInstantiationArgument(CORINFO_CLASS_STRUCT_* cls, uint index) + { + OnCall("getTypeInstantiationArgument"); + return _original.getTypeInstantiationArgument(cls, index); + } + + private CORINFO_CLASS_STRUCT_* getMethodInstantiationArgument(CORINFO_METHOD_STRUCT_* ftn, uint index) + { + OnCall("getMethodInstantiationArgument"); + return _original.getMethodInstantiationArgument(ftn, index); + } + + private nuint printClassName(CORINFO_CLASS_STRUCT_* cls, byte* buffer, nuint bufferSize, nuint* pRequiredBufferSize) + { + OnCall("printClassName"); + return _original.printClassName(cls, buffer, bufferSize, pRequiredBufferSize); + } + + private bool isValueClass(CORINFO_CLASS_STRUCT_* cls) + { + OnCall("isValueClass"); + return _original.isValueClass(cls); + } + + private bool isByRefLike(CORINFO_CLASS_STRUCT_* cls) + { + OnCall("isByRefLike"); + return _original.isByRefLike(cls); + } + + private bool isSharedInst(CORINFO_CLASS_STRUCT_* cls) + { + OnCall("isSharedInst"); + return _original.isSharedInst(cls); + } + + private uint getClassAttribs(CORINFO_CLASS_STRUCT_* cls) + { + OnCall("getClassAttribs"); + return _original.getClassAttribs(cls); + } + + private byte* getClassAssemblyName(CORINFO_CLASS_STRUCT_* cls) + { + OnCall("getClassAssemblyName"); + return _original.getClassAssemblyName(cls); + } + + private void* LongLifetimeMalloc(nuint sz) + { + OnCall("LongLifetimeMalloc"); + return _original.LongLifetimeMalloc(sz); + } + + private void LongLifetimeFree(void* obj) + { + OnCall("LongLifetimeFree"); + _original.LongLifetimeFree(obj); + } + + private bool getIsClassInitedFlagAddress(CORINFO_CLASS_STRUCT_* cls, ref CORINFO_CONST_LOOKUP addr, ref int offset) + { + OnCall("getIsClassInitedFlagAddress"); + return _original.getIsClassInitedFlagAddress(cls, ref addr, ref offset); + } + + private void* getClassThreadStaticDynamicInfo(CORINFO_CLASS_STRUCT_* clr) + { + OnCall("getClassThreadStaticDynamicInfo"); + return _original.getClassThreadStaticDynamicInfo(clr); + } + + private void* getClassStaticDynamicInfo(CORINFO_CLASS_STRUCT_* clr) + { + OnCall("getClassStaticDynamicInfo"); + return _original.getClassStaticDynamicInfo(clr); + } + + private bool getStaticBaseAddress(CORINFO_CLASS_STRUCT_* cls, bool isGc, ref CORINFO_CONST_LOOKUP addr) + { + OnCall("getStaticBaseAddress"); + return _original.getStaticBaseAddress(cls, isGc, ref addr); + } + + private uint getClassSize(CORINFO_CLASS_STRUCT_* cls) + { + OnCall("getClassSize"); + return _original.getClassSize(cls); + } + + private uint getHeapClassSize(CORINFO_CLASS_STRUCT_* cls) + { + OnCall("getHeapClassSize"); + return _original.getHeapClassSize(cls); + } + + private bool canAllocateOnStack(CORINFO_CLASS_STRUCT_* cls) + { + OnCall("canAllocateOnStack"); + return _original.canAllocateOnStack(cls); + } + + private uint getClassAlignmentRequirement(CORINFO_CLASS_STRUCT_* cls, bool fDoubleAlignHint) + { + OnCall("getClassAlignmentRequirement"); + return _original.getClassAlignmentRequirement(cls, fDoubleAlignHint); + } + + private uint getClassGClayout(CORINFO_CLASS_STRUCT_* cls, byte* gcPtrs) + { + OnCall("getClassGClayout"); + return _original.getClassGClayout(cls, gcPtrs); + } + + private uint getClassNumInstanceFields(CORINFO_CLASS_STRUCT_* cls) + { + OnCall("getClassNumInstanceFields"); + return _original.getClassNumInstanceFields(cls); + } + + private CORINFO_FIELD_STRUCT_* getFieldInClass(CORINFO_CLASS_STRUCT_* clsHnd, int num) + { + OnCall("getFieldInClass"); + return _original.getFieldInClass(clsHnd, num); + } + + private GetTypeLayoutResult getTypeLayout(CORINFO_CLASS_STRUCT_* typeHnd, CORINFO_TYPE_LAYOUT_NODE* treeNodes, nuint* numTreeNodes) + { + OnCall("getTypeLayout"); + return _original.getTypeLayout(typeHnd, treeNodes, numTreeNodes); + } + + private bool checkMethodModifier(CORINFO_METHOD_STRUCT_* hMethod, byte* modifier, bool fOptional) + { + OnCall("checkMethodModifier"); + return _original.checkMethodModifier(hMethod, modifier, fOptional); + } + + private CorInfoHelpFunc getNewHelper(CORINFO_CLASS_STRUCT_* classHandle, ref bool pHasSideEffects) + { + OnCall("getNewHelper"); + return _original.getNewHelper(classHandle, ref pHasSideEffects); + } + + private CorInfoHelpFunc getNewArrHelper(CORINFO_CLASS_STRUCT_* arrayCls) + { + OnCall("getNewArrHelper"); + return _original.getNewArrHelper(arrayCls); + } + + private CorInfoHelpFunc getCastingHelper(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool fThrowing) + { + OnCall("getCastingHelper"); + return _original.getCastingHelper(ref pResolvedToken, fThrowing); + } + + private CorInfoHelpFunc getSharedCCtorHelper(CORINFO_CLASS_STRUCT_* clsHnd) + { + OnCall("getSharedCCtorHelper"); + return _original.getSharedCCtorHelper(clsHnd); + } + + private CORINFO_CLASS_STRUCT_* getTypeForBox(CORINFO_CLASS_STRUCT_* cls) + { + OnCall("getTypeForBox"); + return _original.getTypeForBox(cls); + } + + private CorInfoHelpFunc getBoxHelper(CORINFO_CLASS_STRUCT_* cls) + { + OnCall("getBoxHelper"); + return _original.getBoxHelper(cls); + } + + private CorInfoHelpFunc getUnBoxHelper(CORINFO_CLASS_STRUCT_* cls) + { + OnCall("getUnBoxHelper"); + return _original.getUnBoxHelper(cls); + } + + private CORINFO_OBJECT_STRUCT_* getRuntimeTypePointer(CORINFO_CLASS_STRUCT_* cls) + { + OnCall("getRuntimeTypePointer"); + return _original.getRuntimeTypePointer(cls); + } + + private bool isObjectImmutable(CORINFO_OBJECT_STRUCT_* objPtr) + { + OnCall("isObjectImmutable"); + return _original.isObjectImmutable(objPtr); + } + + private bool getStringChar(CORINFO_OBJECT_STRUCT_* strObj, int index, ushort* value) + { + OnCall("getStringChar"); + return _original.getStringChar(strObj, index, value); + } + + private CORINFO_CLASS_STRUCT_* getObjectType(CORINFO_OBJECT_STRUCT_* objPtr) + { + OnCall("getObjectType"); + return _original.getObjectType(objPtr); + } + + private bool getReadyToRunHelper(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CorInfoHelpFunc id, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_CONST_LOOKUP pLookup) + { + OnCall("getReadyToRunHelper"); + return _original.getReadyToRunHelper(ref pResolvedToken, id, callerHandle, ref pLookup); + } + + private void getReadyToRunDelegateCtorHelper(ref CORINFO_RESOLVED_TOKEN pTargetMethod, mdToken targetConstraint, CORINFO_CLASS_STRUCT_* delegateType, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_LOOKUP pLookup) + { + OnCall("getReadyToRunDelegateCtorHelper"); + _original.getReadyToRunDelegateCtorHelper(ref pTargetMethod, targetConstraint, delegateType, callerHandle, ref pLookup); + } + + private CorInfoInitClassResult initClass(CORINFO_FIELD_STRUCT_* field, CORINFO_METHOD_STRUCT_* method, CORINFO_CONTEXT_STRUCT* context) + { + OnCall("initClass"); + return _original.initClass(field, method, context); + } + + private CORINFO_CLASS_STRUCT_* getBuiltinClass(CorInfoClassId classId) + { + OnCall("getBuiltinClass"); + return _original.getBuiltinClass(classId); + } + + private CorInfoType getTypeForPrimitiveValueClass(CORINFO_CLASS_STRUCT_* cls) + { + OnCall("getTypeForPrimitiveValueClass"); + return _original.getTypeForPrimitiveValueClass(cls); + } + + private CorInfoType getTypeForPrimitiveNumericClass(CORINFO_CLASS_STRUCT_* cls) + { + OnCall("getTypeForPrimitiveNumericClass"); + return _original.getTypeForPrimitiveNumericClass(cls); + } + + private bool canCast(CORINFO_CLASS_STRUCT_* child, CORINFO_CLASS_STRUCT_* parent) + { + OnCall("canCast"); + return _original.canCast(child, parent); + } + + private TypeCompareState compareTypesForCast(CORINFO_CLASS_STRUCT_* fromClass, CORINFO_CLASS_STRUCT_* toClass) + { + OnCall("compareTypesForCast"); + return _original.compareTypesForCast(fromClass, toClass); + } + + private TypeCompareState compareTypesForEquality(CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2) + { + OnCall("compareTypesForEquality"); + return _original.compareTypesForEquality(cls1, cls2); + } + + private bool isMoreSpecificType(CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2) + { + OnCall("isMoreSpecificType"); + return _original.isMoreSpecificType(cls1, cls2); + } + + private bool isExactType(CORINFO_CLASS_STRUCT_* cls) + { + OnCall("isExactType"); + return _original.isExactType(cls); + } + + private TypeCompareState isGenericType(CORINFO_CLASS_STRUCT_* cls) + { + OnCall("isGenericType"); + return _original.isGenericType(cls); + } + + private TypeCompareState isNullableType(CORINFO_CLASS_STRUCT_* cls) + { + OnCall("isNullableType"); + return _original.isNullableType(cls); + } + + private TypeCompareState isEnum(CORINFO_CLASS_STRUCT_* cls, CORINFO_CLASS_STRUCT_** underlyingType) + { + OnCall("isEnum"); + return _original.isEnum(cls, underlyingType); + } + + private CORINFO_CLASS_STRUCT_* getParentType(CORINFO_CLASS_STRUCT_* cls) + { + OnCall("getParentType"); + return _original.getParentType(cls); + } + + private CorInfoType getChildType(CORINFO_CLASS_STRUCT_* clsHnd, CORINFO_CLASS_STRUCT_** clsRet) + { + OnCall("getChildType"); + return _original.getChildType(clsHnd, clsRet); + } + + private bool isSDArray(CORINFO_CLASS_STRUCT_* cls) + { + OnCall("isSDArray"); + return _original.isSDArray(cls); + } + + private uint getArrayRank(CORINFO_CLASS_STRUCT_* cls) + { + OnCall("getArrayRank"); + return _original.getArrayRank(cls); + } + + private CorInfoArrayIntrinsic getArrayIntrinsicID(CORINFO_METHOD_STRUCT_* ftn) + { + OnCall("getArrayIntrinsicID"); + return _original.getArrayIntrinsicID(ftn); + } + + private void* getArrayInitializationData(CORINFO_FIELD_STRUCT_* field, uint size) + { + OnCall("getArrayInitializationData"); + return _original.getArrayInitializationData(field, size); + } + + private CorInfoIsAccessAllowedResult canAccessClass(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_HELPER_DESC pAccessHelper) + { + OnCall("canAccessClass"); + return _original.canAccessClass(ref pResolvedToken, callerHandle, ref pAccessHelper); + } + + private nuint printFieldName(CORINFO_FIELD_STRUCT_* field, byte* buffer, nuint bufferSize, nuint* pRequiredBufferSize) + { + OnCall("printFieldName"); + return _original.printFieldName(field, buffer, bufferSize, pRequiredBufferSize); + } + + private CORINFO_CLASS_STRUCT_* getFieldClass(CORINFO_FIELD_STRUCT_* field) + { + OnCall("getFieldClass"); + return _original.getFieldClass(field); + } + + private CorInfoType getFieldType(CORINFO_FIELD_STRUCT_* field, CORINFO_CLASS_STRUCT_** structType, CORINFO_CLASS_STRUCT_* fieldOwnerHint) + { + OnCall("getFieldType"); + return _original.getFieldType(field, structType, fieldOwnerHint); + } + + private uint getFieldOffset(CORINFO_FIELD_STRUCT_* field) + { + OnCall("getFieldOffset"); + return _original.getFieldOffset(field); + } + + private void getFieldInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult) + { + OnCall("getFieldInfo"); + _original.getFieldInfo(ref pResolvedToken, callerHandle, flags, pResult); + } + + private uint getThreadLocalFieldInfo(CORINFO_FIELD_STRUCT_* field, bool isGCtype) + { + OnCall("getThreadLocalFieldInfo"); + return _original.getThreadLocalFieldInfo(field, isGCtype); + } + + private void getThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) + { + OnCall("getThreadLocalStaticBlocksInfo"); + _original.getThreadLocalStaticBlocksInfo(pInfo); + } + + private void getThreadLocalStaticInfo_NativeAOT(CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo) + { + OnCall("getThreadLocalStaticInfo_NativeAOT"); + _original.getThreadLocalStaticInfo_NativeAOT(pInfo); + } + + private bool isFieldStatic(CORINFO_FIELD_STRUCT_* fldHnd) + { + OnCall("isFieldStatic"); + return _original.isFieldStatic(fldHnd); + } + + private int getArrayOrStringLength(CORINFO_OBJECT_STRUCT_* objHnd) + { + OnCall("getArrayOrStringLength"); + return _original.getArrayOrStringLength(objHnd); + } + + private void getBoundaries(CORINFO_METHOD_STRUCT_* ftn, ref uint cILOffsets, ref uint* pILOffsets, BoundaryTypes* implicitBoundaries) + { + OnCall("getBoundaries"); + _original.getBoundaries(ftn, ref cILOffsets, ref pILOffsets, implicitBoundaries); + } + + private void setBoundaries(CORINFO_METHOD_STRUCT_* ftn, uint cMap, OffsetMapping* pMap) + { + OnCall("setBoundaries"); + _original.setBoundaries(ftn, cMap, pMap); + } + + private void getVars(CORINFO_METHOD_STRUCT_* ftn, ref uint cVars, ILVarInfo** vars, ref bool extendOthers) + { + OnCall("getVars"); + _original.getVars(ftn, ref cVars, vars, ref extendOthers); + } + + private void setVars(CORINFO_METHOD_STRUCT_* ftn, uint cVars, NativeVarInfo* vars) + { + OnCall("setVars"); + _original.setVars(ftn, cVars, vars); + } + + private void reportRichMappings(InlineTreeNode* inlineTreeNodes, uint numInlineTreeNodes, RichOffsetMapping* mappings, uint numMappings) + { + OnCall("reportRichMappings"); + _original.reportRichMappings(inlineTreeNodes, numInlineTreeNodes, mappings, numMappings); + } + + private void reportAsyncDebugInfo(AsyncInfo* asyncInfo, AsyncSuspensionPoint* suspensionPoints, AsyncContinuationVarInfo* vars, uint numVars) + { + OnCall("reportAsyncDebugInfo"); + _original.reportAsyncDebugInfo(asyncInfo, suspensionPoints, vars, numVars); + } + + private void reportMetadata(byte* key, void* value, nuint length) + { + OnCall("reportMetadata"); + _original.reportMetadata(key, value, length); + } + + private void* allocateArray(nuint cBytes) + { + OnCall("allocateArray"); + return _original.allocateArray(cBytes); + } + + private void freeArray(void* array) + { + OnCall("freeArray"); + _original.freeArray(array); + } + + private CORINFO_ARG_LIST_STRUCT_* getArgNext(CORINFO_ARG_LIST_STRUCT_* args) + { + OnCall("getArgNext"); + return _original.getArgNext(args); + } + + private CorInfoTypeWithMod getArgType(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_STRUCT_* args, CORINFO_CLASS_STRUCT_** vcTypeRet) + { + OnCall("getArgType"); + return _original.getArgType(sig, args, vcTypeRet); + } + + private int getExactClasses(CORINFO_CLASS_STRUCT_* baseType, int maxExactClasses, CORINFO_CLASS_STRUCT_** exactClsRet) + { + OnCall("getExactClasses"); + return _original.getExactClasses(baseType, maxExactClasses, exactClsRet); + } + + private CORINFO_CLASS_STRUCT_* getArgClass(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_STRUCT_* args) + { + OnCall("getArgClass"); + return _original.getArgClass(sig, args); + } + + private CorInfoHFAElemType getHFAType(CORINFO_CLASS_STRUCT_* hClass) + { + OnCall("getHFAType"); + return _original.getHFAType(hClass); + } + + private bool runWithErrorTrap(void* function, void* parameter) + { + OnCall("runWithErrorTrap"); + return _original.runWithErrorTrap(function, parameter); + } + + private bool runWithSPMIErrorTrap(void* function, void* parameter) + { + OnCall("runWithSPMIErrorTrap"); + return _original.runWithSPMIErrorTrap(function, parameter); + } + + private void getEEInfo(ref CORINFO_EE_INFO pEEInfoOut) + { + OnCall("getEEInfo"); + _original.getEEInfo(ref pEEInfoOut); + } + + private void getAsyncInfo(ref CORINFO_ASYNC_INFO pAsyncInfoOut) + { + OnCall("getAsyncInfo"); + _original.getAsyncInfo(ref pAsyncInfoOut); + } + + private CORINFO_METHOD_STRUCT_* getAwaitReturnCall(CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_CONTEXT_STRUCT** contextHandle, ref CORINFO_LOOKUP instArg) + { + OnCall("getAwaitReturnCall"); + return _original.getAwaitReturnCall(callerHandle, contextHandle, ref instArg); + } + + private CORINFO_METHOD_STRUCT_* getAwaitAwaiterInContinuationCall(CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool isUnsafe, CORINFO_CONTEXT_STRUCT** contextHandle, ref CORINFO_LOOKUP instArg) + { + OnCall("getAwaitAwaiterInContinuationCall"); + return _original.getAwaitAwaiterInContinuationCall(callerHandle, ref pResolvedToken, isUnsafe, contextHandle, ref instArg); + } + + private mdToken getMethodDefFromMethod(CORINFO_METHOD_STRUCT_* hMethod) + { + OnCall("getMethodDefFromMethod"); + return _original.getMethodDefFromMethod(hMethod); + } + + private nuint printMethodName(CORINFO_METHOD_STRUCT_* ftn, byte* buffer, nuint bufferSize, nuint* pRequiredBufferSize) + { + OnCall("printMethodName"); + return _original.printMethodName(ftn, buffer, bufferSize, pRequiredBufferSize); + } + + private byte* getMethodNameFromMetadata(CORINFO_METHOD_STRUCT_* ftn, byte** className, byte** namespaceName, byte** enclosingClassNames, nuint maxEnclosingClassNames) + { + OnCall("getMethodNameFromMetadata"); + return _original.getMethodNameFromMetadata(ftn, className, namespaceName, enclosingClassNames, maxEnclosingClassNames); + } + + private uint getMethodHash(CORINFO_METHOD_STRUCT_* ftn) + { + OnCall("getMethodHash"); + return _original.getMethodHash(ftn); + } + + private bool getSystemVAmd64PassStructInRegisterDescriptor(CORINFO_CLASS_STRUCT_* structHnd, SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr) + { + OnCall("getSystemVAmd64PassStructInRegisterDescriptor"); + return _original.getSystemVAmd64PassStructInRegisterDescriptor(structHnd, structPassInRegDescPtr); + } + + private void getSwiftLowering(CORINFO_CLASS_STRUCT_* structHnd, ref CORINFO_SWIFT_LOWERING pLowering) + { + OnCall("getSwiftLowering"); + _original.getSwiftLowering(structHnd, ref pLowering); + } + + private void getFpStructLowering(CORINFO_CLASS_STRUCT_* structHnd, ref CORINFO_FPSTRUCT_LOWERING pLowering) + { + OnCall("getFpStructLowering"); + _original.getFpStructLowering(structHnd, ref pLowering); + } + + private CorInfoWasmType getWasmLowering(CORINFO_CLASS_STRUCT_* structHnd) + { + OnCall("getWasmLowering"); + return _original.getWasmLowering(structHnd); + } + + private uint getAddressAlignment(void* address) + { + OnCall("getAddressAlignment"); + return _original.getAddressAlignment(address); + } + + private void getWasmWellKnownGlobals(ref CORINFO_WASM_WELLKNOWN_GLOBALS pWellKnownGlobalsOut) + { + OnCall("getWasmWellKnownGlobals"); + _original.getWasmWellKnownGlobals(ref pWellKnownGlobalsOut); + } + + private uint getThreadTLSIndex(ref void* ppIndirection) + { + OnCall("getThreadTLSIndex"); + return _original.getThreadTLSIndex(ref ppIndirection); + } + + private int* getAddrOfCaptureThreadGlobal(ref void* ppIndirection) + { + OnCall("getAddrOfCaptureThreadGlobal"); + return _original.getAddrOfCaptureThreadGlobal(ref ppIndirection); + } + + private void getHelperFtn(CorInfoHelpFunc ftnNum, CORINFO_CONST_LOOKUP* pNativeEntrypoint, CORINFO_METHOD_STRUCT_** pMethod) + { + OnCall("getHelperFtn"); + _original.getHelperFtn(ftnNum, pNativeEntrypoint, pMethod); + } + + private void getFunctionEntryPoint(CORINFO_METHOD_STRUCT_* ftn, ref CORINFO_CONST_LOOKUP pResult, CORINFO_ACCESS_FLAGS accessFlags) + { + OnCall("getFunctionEntryPoint"); + _original.getFunctionEntryPoint(ftn, ref pResult, accessFlags); + } + + private void getFunctionFixedEntryPoint(CORINFO_METHOD_STRUCT_* ftn, bool isUnsafeFunctionPointer, ref CORINFO_CONST_LOOKUP pResult) + { + OnCall("getFunctionFixedEntryPoint"); + _original.getFunctionFixedEntryPoint(ftn, isUnsafeFunctionPointer, ref pResult); + } + + private CORINFO_MODULE_STRUCT_* embedModuleHandle(CORINFO_MODULE_STRUCT_* handle, ref void* ppIndirection) + { + OnCall("embedModuleHandle"); + return _original.embedModuleHandle(handle, ref ppIndirection); + } + + private CORINFO_CLASS_STRUCT_* embedClassHandle(CORINFO_CLASS_STRUCT_* handle, ref void* ppIndirection) + { + OnCall("embedClassHandle"); + return _original.embedClassHandle(handle, ref ppIndirection); + } + + private CORINFO_METHOD_STRUCT_* embedMethodHandle(CORINFO_METHOD_STRUCT_* handle, ref void* ppIndirection) + { + OnCall("embedMethodHandle"); + return _original.embedMethodHandle(handle, ref ppIndirection); + } + + private CORINFO_FIELD_STRUCT_* embedFieldHandle(CORINFO_FIELD_STRUCT_* handle, ref void* ppIndirection) + { + OnCall("embedFieldHandle"); + return _original.embedFieldHandle(handle, ref ppIndirection); + } + + private void embedGenericHandle(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool fEmbedParent, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_GENERICHANDLE_RESULT pResult) + { + OnCall("embedGenericHandle"); + _original.embedGenericHandle(ref pResolvedToken, fEmbedParent, callerHandle, ref pResult); + } + + private void getLocationOfThisType(CORINFO_METHOD_STRUCT_* context, ref CORINFO_LOOKUP_KIND pLookupKind) + { + OnCall("getLocationOfThisType"); + _original.getLocationOfThisType(context, ref pLookupKind); + } + + private void getAddressOfPInvokeTarget(CORINFO_METHOD_STRUCT_* method, ref CORINFO_CONST_LOOKUP pLookup) + { + OnCall("getAddressOfPInvokeTarget"); + _original.getAddressOfPInvokeTarget(method, ref pLookup); + } + + private void* GetCookieForInterpreterCalliSig(CORINFO_SIG_INFO* szMetaSig) + { + OnCall("GetCookieForInterpreterCalliSig"); + return _original.GetCookieForInterpreterCalliSig(szMetaSig); + } + + private CORINFO_JUST_MY_CODE_HANDLE_* getJustMyCodeHandle(CORINFO_METHOD_STRUCT_* method, ref CORINFO_JUST_MY_CODE_HANDLE_* ppIndirection) + { + OnCall("getJustMyCodeHandle"); + return _original.getJustMyCodeHandle(method, ref ppIndirection); + } + + private void GetProfilingHandle(ref bool pbHookFunction, ref void* pProfilerHandle, ref bool pbIndirectedHandles) + { + OnCall("GetProfilingHandle"); + _original.GetProfilingHandle(ref pbHookFunction, ref pProfilerHandle, ref pbIndirectedHandles); + } + + private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_CALLINFO_FLAGS flags, CORINFO_CALL_INFO* pResult) + { + OnCall("getCallInfo"); + _original.getCallInfo(ref pResolvedToken, pConstrainedResolvedToken, callerHandle, flags, pResult); + } + + private bool getStaticFieldContent(CORINFO_FIELD_STRUCT_* field, byte* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects) + { + OnCall("getStaticFieldContent"); + return _original.getStaticFieldContent(field, buffer, bufferSize, valueOffset, ignoreMovableObjects); + } + + private bool getObjectContent(CORINFO_OBJECT_STRUCT_* obj, byte* buffer, int bufferSize, int valueOffset) + { + OnCall("getObjectContent"); + return _original.getObjectContent(obj, buffer, bufferSize, valueOffset); + } + + private CORINFO_CLASS_STRUCT_* getStaticFieldCurrentClass(CORINFO_FIELD_STRUCT_* field, byte* pIsSpeculative) + { + OnCall("getStaticFieldCurrentClass"); + return _original.getStaticFieldCurrentClass(field, pIsSpeculative); + } + + private IntPtr getVarArgsHandle(CORINFO_SIG_INFO* pSig, CORINFO_METHOD_STRUCT_* methHnd, ref void* ppIndirection) + { + OnCall("getVarArgsHandle"); + return _original.getVarArgsHandle(pSig, methHnd, ref ppIndirection); + } + + private InfoAccessType constructStringLiteral(CORINFO_MODULE_STRUCT_* module, mdToken metaTok, ref void* ppValue) + { + OnCall("constructStringLiteral"); + return _original.constructStringLiteral(module, metaTok, ref ppValue); + } + + private InfoAccessType emptyStringLiteral(ref void* ppValue) + { + OnCall("emptyStringLiteral"); + return _original.emptyStringLiteral(ref ppValue); + } + + private uint getFieldThreadLocalStoreID(CORINFO_FIELD_STRUCT_* field, ref void* ppIndirection) + { + OnCall("getFieldThreadLocalStoreID"); + return _original.getFieldThreadLocalStoreID(field, ref ppIndirection); + } + + private CORINFO_METHOD_STRUCT_* GetDelegateCtor(CORINFO_METHOD_STRUCT_* methHnd, CORINFO_CLASS_STRUCT_* clsHnd, CORINFO_METHOD_STRUCT_* targetMethodHnd, ref DelegateCtorArgs pCtorData) + { + OnCall("GetDelegateCtor"); + return _original.GetDelegateCtor(methHnd, clsHnd, targetMethodHnd, ref pCtorData); + } + + private void MethodCompileComplete(CORINFO_METHOD_STRUCT_* methHnd) + { + OnCall("MethodCompileComplete"); + _original.MethodCompileComplete(methHnd); + } + + private bool getTailCallHelpers(ref CORINFO_RESOLVED_TOKEN callToken, CORINFO_SIG_INFO* sig, CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, ref CORINFO_TAILCALL_HELPERS pResult) + { + OnCall("getTailCallHelpers"); + return _original.getTailCallHelpers(ref callToken, sig, flags, ref pResult); + } + + private CORINFO_CLASS_STRUCT_* getContinuationType(nuint dataSize, ref bool objRefs, nuint objRefsSize) + { + OnCall("getContinuationType"); + return _original.getContinuationType(dataSize, ref objRefs, objRefsSize); + } + + private CORINFO_METHOD_STRUCT_* getAsyncResumptionStub(ref void* entryPoint) + { + OnCall("getAsyncResumptionStub"); + return _original.getAsyncResumptionStub(ref entryPoint); + } + + private bool convertPInvokeCalliToCall(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool mustConvert) + { + OnCall("convertPInvokeCalliToCall"); + return _original.convertPInvokeCalliToCall(ref pResolvedToken, mustConvert); + } + + private bool notifyInstructionSetUsage(InstructionSet instructionSet, bool supportEnabled, bool preserveNegativeDependency) + { + OnCall("notifyInstructionSetUsage"); + return _original.notifyInstructionSetUsage(instructionSet, supportEnabled, preserveNegativeDependency); + } + + private void updateEntryPointForTailCall(ref CORINFO_CONST_LOOKUP entryPoint) + { + OnCall("updateEntryPointForTailCall"); + _original.updateEntryPointForTailCall(ref entryPoint); + } + + private void allocMem(ref AllocMemArgs pArgs) + { + OnCall("allocMem"); + _original.allocMem(ref pArgs); + } + + private void reserveUnwindInfo(bool isFunclet, bool isColdCode, uint unwindSize) + { + OnCall("reserveUnwindInfo"); + _original.reserveUnwindInfo(isFunclet, isColdCode, unwindSize); + } + + private void allocUnwindInfo(byte* pHotCode, byte* pColdCode, uint startOffset, uint endOffset, uint unwindSize, byte* pUnwindBlock, CorJitFuncKind funcKind) + { + OnCall("allocUnwindInfo"); + _original.allocUnwindInfo(pHotCode, pColdCode, startOffset, endOffset, unwindSize, pUnwindBlock, funcKind); + } + + private void* allocGCInfo(nuint size) + { + OnCall("allocGCInfo"); + return _original.allocGCInfo(size); + } + + private void setEHcount(uint cEH) + { + OnCall("setEHcount"); + _original.setEHcount(cEH); + } + + private void setEHinfo(uint EHnumber, ref CORINFO_EH_CLAUSE clause) + { + OnCall("setEHinfo"); + _original.setEHinfo(EHnumber, ref clause); + } + + private bool logMsg(uint level, byte* fmt, IntPtr args) + { + OnCall("logMsg"); + return _original.logMsg(level, fmt, args); + } + + private int doAssert(byte* szFile, int iLine, byte* szExpr) + { + OnCall("doAssert"); + return _original.doAssert(szFile, iLine, szExpr); + } + + private void reportFatalError(CorJitResult result) + { + OnCall("reportFatalError"); + _original.reportFatalError(result); + } + + private HRESULT getPgoInstrumentationResults(CORINFO_METHOD_STRUCT_* ftnHnd, ref PgoInstrumentationSchema* pSchema, ref uint pCountSchemaItems, byte** pInstrumentationData, ref PgoSource pPgoSource, ref bool pDynamicPgo) + { + OnCall("getPgoInstrumentationResults"); + return _original.getPgoInstrumentationResults(ftnHnd, ref pSchema, ref pCountSchemaItems, pInstrumentationData, ref pPgoSource, ref pDynamicPgo); + } + + private HRESULT allocPgoInstrumentationBySchema(CORINFO_METHOD_STRUCT_* ftnHnd, PgoInstrumentationSchema* pSchema, uint countSchemaItems, byte** pInstrumentationData) + { + OnCall("allocPgoInstrumentationBySchema"); + return _original.allocPgoInstrumentationBySchema(ftnHnd, pSchema, countSchemaItems, pInstrumentationData); + } + + private void recordCallSite(uint instrOffset, CORINFO_SIG_INFO* callSig, CORINFO_METHOD_STRUCT_* methodHandle) + { + OnCall("recordCallSite"); + _original.recordCallSite(instrOffset, callSig, methodHandle); + } + + private void recordWasmManagedCallSig(CORINFO_SIG_INFO* callSig) + { + OnCall("recordWasmManagedCallSig"); + _original.recordWasmManagedCallSig(callSig); + } + + private void recordRelocation(void* location, void* locationRW, void* target, CorInfoReloc fRelocType, int addlDelta) + { + OnCall("recordRelocation"); + _original.recordRelocation(location, locationRW, target, fRelocType, addlDelta); + } + + private CorInfoReloc getRelocTypeHint(void* target) + { + OnCall("getRelocTypeHint"); + return _original.getRelocTypeHint(target); + } + + private uint getExpectedTargetArchitecture() + { + OnCall("getExpectedTargetArchitecture"); + return _original.getExpectedTargetArchitecture(); + } + + private uint getJitFlags(ref CORJIT_FLAGS flags, uint sizeInBytes) + { + OnCall("getJitFlags"); + return _original.getJitFlags(ref flags, sizeInBytes); + } + + private CORINFO_WASM_TYPE_SYMBOL_STRUCT_* getWasmTypeSymbol(CorInfoWasmType* types, nuint typesSize) + { + OnCall("getWasmTypeSymbol"); + return _original.getWasmTypeSymbol(types, typesSize); + } + + private CORINFO_METHOD_STRUCT_* getSpecialCopyHelper(CORINFO_CLASS_STRUCT_* type) + { + OnCall("getSpecialCopyHelper"); + return _original.getSpecialCopyHelper(type); + } +} diff --git a/src/coreclr/tools/superpmi/managed/shim/ForwardingCorInfoImpl.cs b/src/coreclr/tools/superpmi/managed/shim/ForwardingCorInfoImpl.cs new file mode 100644 index 00000000000000..aeb47f703a1a77 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/shim/ForwardingCorInfoImpl.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.CompilerServices; +using SuperPmi.Shim; + +namespace Internal.JitInterface; + +// The JIT-EE interface of the forwarding shims, whose methods (CorInfoImpl_forwarding_generated.cs) call the EE's. +internal sealed unsafe partial class CorInfoImpl +{ + private readonly OriginalJitInfo _original; + + public CorInfoImpl(OriginalJitInfo original) => _original = original; + + private static CorInfoImpl GetThis(IntPtr thisHandle) => Unsafe.Read((void*)thisHandle); + + private IntPtr AllocException(Exception ex) => ShimInterop.ToNativeException(ex); + + // Compiles the method with the real JIT through this JIT-EE interface, rethrowing what escapes the JIT. + public CorJitResult CompileMethod(IntPtr jit, CORINFO_METHOD_INFO* info, uint flags, byte** nativeEntry, uint* nativeSizeOfCode) + { + CorInfoImpl _this = this; + IntPtr exception = 0; + CorJitResult result = ShimInterop.Shim_CompileMethodWithJitInfo(&exception, jit, (IntPtr)Unsafe.AsPointer(ref _this), + GetUnmanagedCallbacks(), info, flags, nativeEntry, nativeSizeOfCode); + if (exception != 0) + throw new EEException(exception); + return result; + } +} diff --git a/src/coreclr/tools/superpmi/managed/shim/ForwardingShim.cs b/src/coreclr/tools/superpmi/managed/shim/ForwardingShim.cs new file mode 100644 index 00000000000000..85805a5d4c1dd8 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/shim/ForwardingShim.cs @@ -0,0 +1,146 @@ +// 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.InteropServices; +using Internal.JitInterface; + +namespace SuperPmi.Shim; + +// The shims that forward all the JIT-EE interface calls between the runtime and the real JIT (SuperPMIShimPath), +// optionally counting them. +internal static unsafe class ForwardingShim +{ + private static readonly ShimInterop.JitCompilerCallbacks* s_compilerCallbacks = ShimInterop.Allocate(new ShimInterop.JitCompilerCallbacks + { + compileMethod = &CompileMethod, + ProcessShutdownWork = &ProcessShutdownWork, + getVersionIdentifier = &GetVersionIdentifier, + setTargetOS = &SetTargetOS, + }); + + private static readonly ShimInterop.JitHostCallbacks* s_hostCallbacks = ShimInterop.Allocate(new ShimInterop.JitHostCallbacks + { + getIntConfigValue = &GetIntConfigValue, + getStringConfigValue = &GetStringConfigValue, + freeStringConfigValue = &FreeStringConfigValue, + }); + + private static IntPtr s_originalHost; + + static ForwardingShim() + { + string logFilePath = Environment.GetEnvironmentVariable("SuperPMIShimLogFilePath"); + if (logFilePath != null) + Logger.OpenLogFile(logFilePath); + } + + // Counts the calls (other than those of the JIT-EE interface itself), for the counter shim. + public static Action OnCall { get; set; } + + // Called once the real JIT is loaded, before the JIT gets the shim's objects. + public static Action OnStartup { get; set; } + + public static void JitStartup(IntPtr host) + { + ShimEnvironment.SetDefaultPaths(); + ShimEnvironment.SetLibName(); + + if (!ShimEnvironment.LoadRealJitLib()) + return; + + var realJitStartup = (delegate* unmanaged)ShimEnvironment.GetRealJitExport("jitStartup"); + if (realJitStartup == null) + { + // This portion of the interface is not used by the JIT under test. + return; + } + + s_originalHost = host; + IntPtr ourJitHost = ShimInterop.Shim_CreateJitHost(host, 0, s_hostCallbacks); + OnStartup?.Invoke(); + realJitStartup(ourJitHost); + } + + public static IntPtr GetJit() + { + ShimEnvironment.SetDefaultPaths(); + ShimEnvironment.SetLibName(); + + if (!ShimEnvironment.LoadRealJitLib()) + return 0; + + var realGetJit = (delegate* unmanaged)ShimEnvironment.GetRealJitExport("getJit"); + if (realGetJit == null) + { + Logger.LogError("getJit() - GetProcAddress 'getJit' failed (0x0000007f)"); + return 0; + } + + IntPtr original = realGetJit(); + if (original == 0) + { + Logger.LogError("getJit() - pngetJit gave us null"); + return 0; + } + + // The JIT is used for the lifetime of the process. + IntPtr ourJit = ShimInterop.Shim_CreateJitCompiler(original, s_compilerCallbacks); + OnStartup?.Invoke(); + return ourJit; + } + + [UnmanagedCallersOnly] + private static CorJitResult CompileMethod(IntPtr original, IntPtr* ppException, IntPtr comp, CORINFO_METHOD_INFO* info, + uint flags, byte** nativeEntry, uint* nativeSizeOfCode) + { + try + { + OnCall?.Invoke("compileMethod"); + return new CorInfoImpl(new OriginalJitInfo(comp, ShimInterop.Forwarders)).CompileMethod(original, info, flags, nativeEntry, nativeSizeOfCode); + } + catch (Exception ex) + { + *ppException = ShimInterop.ToNativeException(ex); + return CorJitResult.CORJIT_INTERNALERROR; + } + } + + [UnmanagedCallersOnly] + private static void ProcessShutdownWork(IntPtr original, IntPtr info) + { + OnCall?.Invoke("ProcessShutdownWork"); + ShimInterop.Shim_ProcessShutdownWork(original, info); + } + + [UnmanagedCallersOnly] + private static void GetVersionIdentifier(IntPtr original, Guid* versionIdentifier) + { + OnCall?.Invoke("getVersionIdentifier"); + ShimInterop.Shim_GetVersionIdentifier(original, versionIdentifier); + } + + [UnmanagedCallersOnly] + private static void SetTargetOS(IntPtr original, CORINFO_OS os) => ShimInterop.Shim_SetTargetOS(original, os); + + [UnmanagedCallersOnly] + private static int GetIntConfigValue(IntPtr thisHandle, byte* name, int defaultValue) + { + OnCall?.Invoke("getIntConfigValue"); + return ShimInterop.Shim_HostGetIntConfigValue(s_originalHost, name, defaultValue); + } + + [UnmanagedCallersOnly] + private static byte* GetStringConfigValue(IntPtr thisHandle, byte* name) + { + OnCall?.Invoke("getStringConfigValue"); + return ShimInterop.Shim_HostGetStringConfigValue(s_originalHost, name); + } + + [UnmanagedCallersOnly] + private static void FreeStringConfigValue(IntPtr thisHandle, byte* value) + { + OnCall?.Invoke("freeStringConfigValue"); + ShimInterop.Shim_HostFreeStringConfigValue(s_originalHost, value); + } +} diff --git a/src/coreclr/tools/superpmi/managed/shim/OriginalJitInfo_generated.cs b/src/coreclr/tools/superpmi/managed/shim/OriginalJitInfo_generated.cs new file mode 100644 index 00000000000000..38599adce0d977 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/shim/OriginalJitInfo_generated.cs @@ -0,0 +1,2015 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// DO NOT EDIT THIS FILE! IT IS AUTOGENERATED +// To regenerate run the gen script in src/coreclr/tools/Common/JitInterface/ThunkGenerator +// and follow the instructions in docs/project/updating-jitinterface.md + +using System; +using SuperPmi.Shim; + +namespace Internal.JitInterface; + +// The ICorJitInfo of the EE, called through the forwarders of the native shim library. +internal readonly unsafe struct OriginalJitInfo +{ + private readonly IntPtr _target; + private readonly Forwarders* _forwarders; + + public OriginalJitInfo(IntPtr target, IntPtr forwarders) + { + _target = target; + _forwarders = (Forwarders*)forwarders; + } + + public IntPtr Target => _target; + +#pragma warning disable CS0649 // The native shim fills in the table. + private struct Forwarders + { + public delegate* unmanaged isIntrinsic; + public delegate* unmanaged canValueClassInstancePointerEscape; + public delegate* unmanaged notifyMethodInfoUsage; + public delegate* unmanaged getMethodAttribs; + public delegate* unmanaged setMethodAttribs; + public delegate* unmanaged getMethodSig; + public delegate* unmanaged getMethodInfo; + public delegate* unmanaged haveSameMethodDefinition; + public delegate* unmanaged getTypeDefinition; + public delegate* unmanaged canInline; + public delegate* unmanaged beginInlining; + public delegate* unmanaged reportInliningDecision; + public delegate* unmanaged canTailCall; + public delegate* unmanaged reportTailCallDecision; + public delegate* unmanaged getEHinfo; + public delegate* unmanaged getMethodClass; + public delegate* unmanaged getMethodVTableOffset; + public delegate* unmanaged resolveVirtualMethod; + public delegate* unmanaged getAsyncOtherVariant; + public delegate* unmanaged getDefaultComparerClass; + public delegate* unmanaged getDefaultEqualityComparerClass; + public delegate* unmanaged getSZArrayHelperEnumeratorClass; + public delegate* unmanaged expandRawHandleIntrinsic; + public delegate* unmanaged isIntrinsicType; + public delegate* unmanaged getUnmanagedCallConv; + public delegate* unmanaged pInvokeMarshalingRequired; + public delegate* unmanaged satisfiesMethodConstraints; + public delegate* unmanaged getGSCookie; + public delegate* unmanaged setPatchpointInfo; + public delegate* unmanaged getOSRInfo; + public delegate* unmanaged resolveToken; + public delegate* unmanaged findSig; + public delegate* unmanaged findCallSiteSig; + public delegate* unmanaged getTokenTypeAsHandle; + public delegate* unmanaged getStringLiteral; + public delegate* unmanaged printObjectDescription; + public delegate* unmanaged asCorInfoType; + public delegate* unmanaged getClassNameFromMetadata; + public delegate* unmanaged getTypeInstantiationArgument; + public delegate* unmanaged getMethodInstantiationArgument; + public delegate* unmanaged printClassName; + public delegate* unmanaged isValueClass; + public delegate* unmanaged isByRefLike; + public delegate* unmanaged isSharedInst; + public delegate* unmanaged getClassAttribs; + public delegate* unmanaged getClassAssemblyName; + public delegate* unmanaged LongLifetimeMalloc; + public delegate* unmanaged LongLifetimeFree; + public delegate* unmanaged getIsClassInitedFlagAddress; + public delegate* unmanaged getClassThreadStaticDynamicInfo; + public delegate* unmanaged getClassStaticDynamicInfo; + public delegate* unmanaged getStaticBaseAddress; + public delegate* unmanaged getClassSize; + public delegate* unmanaged getHeapClassSize; + public delegate* unmanaged canAllocateOnStack; + public delegate* unmanaged getClassAlignmentRequirement; + public delegate* unmanaged getClassGClayout; + public delegate* unmanaged getClassNumInstanceFields; + public delegate* unmanaged getFieldInClass; + public delegate* unmanaged getTypeLayout; + public delegate* unmanaged checkMethodModifier; + public delegate* unmanaged getNewHelper; + public delegate* unmanaged getNewArrHelper; + public delegate* unmanaged getCastingHelper; + public delegate* unmanaged getSharedCCtorHelper; + public delegate* unmanaged getTypeForBox; + public delegate* unmanaged getBoxHelper; + public delegate* unmanaged getUnBoxHelper; + public delegate* unmanaged getRuntimeTypePointer; + public delegate* unmanaged isObjectImmutable; + public delegate* unmanaged getStringChar; + public delegate* unmanaged getObjectType; + public delegate* unmanaged getReadyToRunHelper; + public delegate* unmanaged getReadyToRunDelegateCtorHelper; + public delegate* unmanaged initClass; + public delegate* unmanaged getBuiltinClass; + public delegate* unmanaged getTypeForPrimitiveValueClass; + public delegate* unmanaged getTypeForPrimitiveNumericClass; + public delegate* unmanaged canCast; + public delegate* unmanaged compareTypesForCast; + public delegate* unmanaged compareTypesForEquality; + public delegate* unmanaged isMoreSpecificType; + public delegate* unmanaged isExactType; + public delegate* unmanaged isGenericType; + public delegate* unmanaged isNullableType; + public delegate* unmanaged isEnum; + public delegate* unmanaged getParentType; + public delegate* unmanaged getChildType; + public delegate* unmanaged isSDArray; + public delegate* unmanaged getArrayRank; + public delegate* unmanaged getArrayIntrinsicID; + public delegate* unmanaged getArrayInitializationData; + public delegate* unmanaged canAccessClass; + public delegate* unmanaged printFieldName; + public delegate* unmanaged getFieldClass; + public delegate* unmanaged getFieldType; + public delegate* unmanaged getFieldOffset; + public delegate* unmanaged getFieldInfo; + public delegate* unmanaged getThreadLocalFieldInfo; + public delegate* unmanaged getThreadLocalStaticBlocksInfo; + public delegate* unmanaged getThreadLocalStaticInfo_NativeAOT; + public delegate* unmanaged isFieldStatic; + public delegate* unmanaged getArrayOrStringLength; + public delegate* unmanaged getBoundaries; + public delegate* unmanaged setBoundaries; + public delegate* unmanaged getVars; + public delegate* unmanaged setVars; + public delegate* unmanaged reportRichMappings; + public delegate* unmanaged reportAsyncDebugInfo; + public delegate* unmanaged reportMetadata; + public delegate* unmanaged allocateArray; + public delegate* unmanaged freeArray; + public delegate* unmanaged getArgNext; + public delegate* unmanaged getArgType; + public delegate* unmanaged getExactClasses; + public delegate* unmanaged getArgClass; + public delegate* unmanaged getHFAType; + public delegate* unmanaged runWithErrorTrap; + public delegate* unmanaged runWithSPMIErrorTrap; + public delegate* unmanaged getEEInfo; + public delegate* unmanaged getAsyncInfo; + public delegate* unmanaged getAwaitReturnCall; + public delegate* unmanaged getAwaitAwaiterInContinuationCall; + public delegate* unmanaged getMethodDefFromMethod; + public delegate* unmanaged printMethodName; + public delegate* unmanaged getMethodNameFromMetadata; + public delegate* unmanaged getMethodHash; + public delegate* unmanaged getSystemVAmd64PassStructInRegisterDescriptor; + public delegate* unmanaged getSwiftLowering; + public delegate* unmanaged getFpStructLowering; + public delegate* unmanaged getWasmLowering; + public delegate* unmanaged getAddressAlignment; + public delegate* unmanaged getWasmWellKnownGlobals; + public delegate* unmanaged getThreadTLSIndex; + public delegate* unmanaged getAddrOfCaptureThreadGlobal; + public delegate* unmanaged getHelperFtn; + public delegate* unmanaged getFunctionEntryPoint; + public delegate* unmanaged getFunctionFixedEntryPoint; + public delegate* unmanaged embedModuleHandle; + public delegate* unmanaged embedClassHandle; + public delegate* unmanaged embedMethodHandle; + public delegate* unmanaged embedFieldHandle; + public delegate* unmanaged embedGenericHandle; + public delegate* unmanaged getLocationOfThisType; + public delegate* unmanaged getAddressOfPInvokeTarget; + public delegate* unmanaged GetCookieForInterpreterCalliSig; + public delegate* unmanaged getJustMyCodeHandle; + public delegate* unmanaged GetProfilingHandle; + public delegate* unmanaged getCallInfo; + public delegate* unmanaged getStaticFieldContent; + public delegate* unmanaged getObjectContent; + public delegate* unmanaged getStaticFieldCurrentClass; + public delegate* unmanaged getVarArgsHandle; + public delegate* unmanaged constructStringLiteral; + public delegate* unmanaged emptyStringLiteral; + public delegate* unmanaged getFieldThreadLocalStoreID; + public delegate* unmanaged GetDelegateCtor; + public delegate* unmanaged MethodCompileComplete; + public delegate* unmanaged getTailCallHelpers; + public delegate* unmanaged getContinuationType; + public delegate* unmanaged getAsyncResumptionStub; + public delegate* unmanaged convertPInvokeCalliToCall; + public delegate* unmanaged notifyInstructionSetUsage; + public delegate* unmanaged updateEntryPointForTailCall; + public delegate* unmanaged allocMem; + public delegate* unmanaged reserveUnwindInfo; + public delegate* unmanaged allocUnwindInfo; + public delegate* unmanaged allocGCInfo; + public delegate* unmanaged setEHcount; + public delegate* unmanaged setEHinfo; + public delegate* unmanaged logMsg; + public delegate* unmanaged doAssert; + public delegate* unmanaged reportFatalError; + public delegate* unmanaged getPgoInstrumentationResults; + public delegate* unmanaged allocPgoInstrumentationBySchema; + public delegate* unmanaged recordCallSite; + public delegate* unmanaged recordWasmManagedCallSig; + public delegate* unmanaged recordRelocation; + public delegate* unmanaged getRelocTypeHint; + public delegate* unmanaged getExpectedTargetArchitecture; + public delegate* unmanaged getJitFlags; + public delegate* unmanaged getWasmTypeSymbol; + public delegate* unmanaged getSpecialCopyHelper; + } +#pragma warning restore CS0649 + + public bool isIntrinsic(CORINFO_METHOD_STRUCT_* ftn) + { + IntPtr exception = 0; + byte result; + result = _forwarders->isIntrinsic(_target, &exception, ftn); + if (exception != 0) + throw new EEException(exception); + return result != 0; + } + + public bool canValueClassInstancePointerEscape(CORINFO_METHOD_STRUCT_* ftn) + { + IntPtr exception = 0; + byte result; + result = _forwarders->canValueClassInstancePointerEscape(_target, &exception, ftn); + if (exception != 0) + throw new EEException(exception); + return result != 0; + } + + public bool notifyMethodInfoUsage(CORINFO_METHOD_STRUCT_* ftn) + { + IntPtr exception = 0; + byte result; + result = _forwarders->notifyMethodInfoUsage(_target, &exception, ftn); + if (exception != 0) + throw new EEException(exception); + return result != 0; + } + + public uint getMethodAttribs(CORINFO_METHOD_STRUCT_* ftn) + { + IntPtr exception = 0; + uint result; + result = _forwarders->getMethodAttribs(_target, &exception, ftn); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public void setMethodAttribs(CORINFO_METHOD_STRUCT_* ftn, CorInfoMethodRuntimeFlags attribs) + { + IntPtr exception = 0; + _forwarders->setMethodAttribs(_target, &exception, ftn, attribs); + if (exception != 0) + throw new EEException(exception); + } + + public void getMethodSig(CORINFO_METHOD_STRUCT_* ftn, CORINFO_SIG_INFO* sig, CORINFO_CLASS_STRUCT_* memberParent) + { + IntPtr exception = 0; + _forwarders->getMethodSig(_target, &exception, ftn, sig, memberParent); + if (exception != 0) + throw new EEException(exception); + } + + public bool getMethodInfo(CORINFO_METHOD_STRUCT_* ftn, CORINFO_METHOD_INFO* info, CORINFO_CONTEXT_STRUCT* context) + { + IntPtr exception = 0; + byte result; + result = _forwarders->getMethodInfo(_target, &exception, ftn, info, context); + if (exception != 0) + throw new EEException(exception); + return result != 0; + } + + public bool haveSameMethodDefinition(CORINFO_METHOD_STRUCT_* meth1Hnd, CORINFO_METHOD_STRUCT_* meth2Hnd) + { + IntPtr exception = 0; + byte result; + result = _forwarders->haveSameMethodDefinition(_target, &exception, meth1Hnd, meth2Hnd); + if (exception != 0) + throw new EEException(exception); + return result != 0; + } + + public CORINFO_CLASS_STRUCT_* getTypeDefinition(CORINFO_CLASS_STRUCT_* type) + { + IntPtr exception = 0; + CORINFO_CLASS_STRUCT_* result; + result = _forwarders->getTypeDefinition(_target, &exception, type); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public CorInfoInline canInline(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* calleeHnd) + { + IntPtr exception = 0; + CorInfoInline result; + result = _forwarders->canInline(_target, &exception, callerHnd, calleeHnd); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public void beginInlining(CORINFO_METHOD_STRUCT_* inlinerHnd, CORINFO_METHOD_STRUCT_* inlineeHnd) + { + IntPtr exception = 0; + _forwarders->beginInlining(_target, &exception, inlinerHnd, inlineeHnd); + if (exception != 0) + throw new EEException(exception); + } + + public void reportInliningDecision(CORINFO_METHOD_STRUCT_* inlinerHnd, CORINFO_METHOD_STRUCT_* inlineeHnd, CorInfoInline inlineResult, byte* reason) + { + IntPtr exception = 0; + _forwarders->reportInliningDecision(_target, &exception, inlinerHnd, inlineeHnd, inlineResult, reason); + if (exception != 0) + throw new EEException(exception); + } + + public bool canTailCall(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* declaredCalleeHnd, CORINFO_METHOD_STRUCT_* exactCalleeHnd, bool fIsTailPrefix) + { + IntPtr exception = 0; + byte result; + result = _forwarders->canTailCall(_target, &exception, callerHnd, declaredCalleeHnd, exactCalleeHnd, fIsTailPrefix ? (byte)1 : (byte)0); + if (exception != 0) + throw new EEException(exception); + return result != 0; + } + + public void reportTailCallDecision(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* calleeHnd, bool fIsTailPrefix, CorInfoTailCall tailCallResult, byte* reason) + { + IntPtr exception = 0; + _forwarders->reportTailCallDecision(_target, &exception, callerHnd, calleeHnd, fIsTailPrefix ? (byte)1 : (byte)0, tailCallResult, reason); + if (exception != 0) + throw new EEException(exception); + } + + public void getEHinfo(CORINFO_METHOD_STRUCT_* ftn, uint EHnumber, ref CORINFO_EH_CLAUSE clause) + { + IntPtr exception = 0; + fixed (CORINFO_EH_CLAUSE* p_clause = &clause) + _forwarders->getEHinfo(_target, &exception, ftn, EHnumber, p_clause); + if (exception != 0) + throw new EEException(exception); + } + + public CORINFO_CLASS_STRUCT_* getMethodClass(CORINFO_METHOD_STRUCT_* method) + { + IntPtr exception = 0; + CORINFO_CLASS_STRUCT_* result; + result = _forwarders->getMethodClass(_target, &exception, method); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public void getMethodVTableOffset(CORINFO_METHOD_STRUCT_* method, ref uint offsetOfIndirection, ref uint offsetAfterIndirection, ref bool isRelative) + { + IntPtr exception = 0; + fixed (uint* p_offsetOfIndirection = &offsetOfIndirection) + fixed (uint* p_offsetAfterIndirection = &offsetAfterIndirection) + fixed (bool* p_isRelative = &isRelative) + _forwarders->getMethodVTableOffset(_target, &exception, method, p_offsetOfIndirection, p_offsetAfterIndirection, p_isRelative); + if (exception != 0) + throw new EEException(exception); + } + + public bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) + { + IntPtr exception = 0; + byte result; + result = _forwarders->resolveVirtualMethod(_target, &exception, info); + if (exception != 0) + throw new EEException(exception); + return result != 0; + } + + public CORINFO_METHOD_STRUCT_* getAsyncOtherVariant(CORINFO_METHOD_STRUCT_* ftn, ref bool variantIsThunk) + { + IntPtr exception = 0; + CORINFO_METHOD_STRUCT_* result; + fixed (bool* p_variantIsThunk = &variantIsThunk) + result = _forwarders->getAsyncOtherVariant(_target, &exception, ftn, p_variantIsThunk); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public CORINFO_CLASS_STRUCT_* getDefaultComparerClass(CORINFO_CLASS_STRUCT_* elemType) + { + IntPtr exception = 0; + CORINFO_CLASS_STRUCT_* result; + result = _forwarders->getDefaultComparerClass(_target, &exception, elemType); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public CORINFO_CLASS_STRUCT_* getDefaultEqualityComparerClass(CORINFO_CLASS_STRUCT_* elemType) + { + IntPtr exception = 0; + CORINFO_CLASS_STRUCT_* result; + result = _forwarders->getDefaultEqualityComparerClass(_target, &exception, elemType); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public CORINFO_CLASS_STRUCT_* getSZArrayHelperEnumeratorClass(CORINFO_CLASS_STRUCT_* elemType) + { + IntPtr exception = 0; + CORINFO_CLASS_STRUCT_* result; + result = _forwarders->getSZArrayHelperEnumeratorClass(_target, &exception, elemType); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public void expandRawHandleIntrinsic(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_GENERICHANDLE_RESULT pResult) + { + IntPtr exception = 0; + fixed (CORINFO_RESOLVED_TOKEN* p_pResolvedToken = &pResolvedToken) + fixed (CORINFO_GENERICHANDLE_RESULT* p_pResult = &pResult) + _forwarders->expandRawHandleIntrinsic(_target, &exception, p_pResolvedToken, callerHandle, p_pResult); + if (exception != 0) + throw new EEException(exception); + } + + public bool isIntrinsicType(CORINFO_CLASS_STRUCT_* classHnd) + { + IntPtr exception = 0; + byte result; + result = _forwarders->isIntrinsicType(_target, &exception, classHnd); + if (exception != 0) + throw new EEException(exception); + return result != 0; + } + + public CorInfoCallConvExtension getUnmanagedCallConv(CORINFO_METHOD_STRUCT_* method, CORINFO_SIG_INFO* callSiteSig, ref bool pSuppressGCTransition) + { + IntPtr exception = 0; + CorInfoCallConvExtension result; + fixed (bool* p_pSuppressGCTransition = &pSuppressGCTransition) + result = _forwarders->getUnmanagedCallConv(_target, &exception, method, callSiteSig, p_pSuppressGCTransition); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public bool pInvokeMarshalingRequired(CORINFO_METHOD_STRUCT_* method, CORINFO_SIG_INFO* callSiteSig) + { + IntPtr exception = 0; + byte result; + result = _forwarders->pInvokeMarshalingRequired(_target, &exception, method, callSiteSig); + if (exception != 0) + throw new EEException(exception); + return result != 0; + } + + public bool satisfiesMethodConstraints(CORINFO_CLASS_STRUCT_* parent, CORINFO_METHOD_STRUCT_* method) + { + IntPtr exception = 0; + byte result; + result = _forwarders->satisfiesMethodConstraints(_target, &exception, parent, method); + if (exception != 0) + throw new EEException(exception); + return result != 0; + } + + public void getGSCookie(IntPtr* pCookieVal, IntPtr** ppCookieVal) + { + IntPtr exception = 0; + _forwarders->getGSCookie(_target, &exception, pCookieVal, ppCookieVal); + if (exception != 0) + throw new EEException(exception); + } + + public void setPatchpointInfo(PatchpointInfo* patchpointInfo) + { + IntPtr exception = 0; + _forwarders->setPatchpointInfo(_target, &exception, patchpointInfo); + if (exception != 0) + throw new EEException(exception); + } + + public PatchpointInfo* getOSRInfo(ref uint ilOffset) + { + IntPtr exception = 0; + PatchpointInfo* result; + fixed (uint* p_ilOffset = &ilOffset) + result = _forwarders->getOSRInfo(_target, &exception, p_ilOffset); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public void resolveToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken) + { + IntPtr exception = 0; + fixed (CORINFO_RESOLVED_TOKEN* p_pResolvedToken = &pResolvedToken) + _forwarders->resolveToken(_target, &exception, p_pResolvedToken); + if (exception != 0) + throw new EEException(exception); + } + + public void findSig(CORINFO_MODULE_STRUCT_* module, uint sigTOK, CORINFO_CONTEXT_STRUCT* context, CORINFO_SIG_INFO* sig) + { + IntPtr exception = 0; + _forwarders->findSig(_target, &exception, module, sigTOK, context, sig); + if (exception != 0) + throw new EEException(exception); + } + + public void findCallSiteSig(CORINFO_MODULE_STRUCT_* module, uint methTOK, CORINFO_CONTEXT_STRUCT* context, CORINFO_SIG_INFO* sig) + { + IntPtr exception = 0; + _forwarders->findCallSiteSig(_target, &exception, module, methTOK, context, sig); + if (exception != 0) + throw new EEException(exception); + } + + public CORINFO_CLASS_STRUCT_* getTokenTypeAsHandle(ref CORINFO_RESOLVED_TOKEN pResolvedToken) + { + IntPtr exception = 0; + CORINFO_CLASS_STRUCT_* result; + fixed (CORINFO_RESOLVED_TOKEN* p_pResolvedToken = &pResolvedToken) + result = _forwarders->getTokenTypeAsHandle(_target, &exception, p_pResolvedToken); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public int getStringLiteral(CORINFO_MODULE_STRUCT_* module, uint metaTOK, char* buffer, int bufferSize, int startIndex) + { + IntPtr exception = 0; + int result; + result = _forwarders->getStringLiteral(_target, &exception, module, metaTOK, buffer, bufferSize, startIndex); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public nuint printObjectDescription(CORINFO_OBJECT_STRUCT_* handle, byte* buffer, nuint bufferSize, nuint* pRequiredBufferSize) + { + IntPtr exception = 0; + nuint result; + result = _forwarders->printObjectDescription(_target, &exception, handle, buffer, bufferSize, pRequiredBufferSize); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public CorInfoType asCorInfoType(CORINFO_CLASS_STRUCT_* cls) + { + IntPtr exception = 0; + CorInfoType result; + result = _forwarders->asCorInfoType(_target, &exception, cls); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public byte* getClassNameFromMetadata(CORINFO_CLASS_STRUCT_* cls, byte** namespaceName) + { + IntPtr exception = 0; + byte* result; + result = _forwarders->getClassNameFromMetadata(_target, &exception, cls, namespaceName); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public CORINFO_CLASS_STRUCT_* getTypeInstantiationArgument(CORINFO_CLASS_STRUCT_* cls, uint index) + { + IntPtr exception = 0; + CORINFO_CLASS_STRUCT_* result; + result = _forwarders->getTypeInstantiationArgument(_target, &exception, cls, index); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public CORINFO_CLASS_STRUCT_* getMethodInstantiationArgument(CORINFO_METHOD_STRUCT_* ftn, uint index) + { + IntPtr exception = 0; + CORINFO_CLASS_STRUCT_* result; + result = _forwarders->getMethodInstantiationArgument(_target, &exception, ftn, index); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public nuint printClassName(CORINFO_CLASS_STRUCT_* cls, byte* buffer, nuint bufferSize, nuint* pRequiredBufferSize) + { + IntPtr exception = 0; + nuint result; + result = _forwarders->printClassName(_target, &exception, cls, buffer, bufferSize, pRequiredBufferSize); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public bool isValueClass(CORINFO_CLASS_STRUCT_* cls) + { + IntPtr exception = 0; + byte result; + result = _forwarders->isValueClass(_target, &exception, cls); + if (exception != 0) + throw new EEException(exception); + return result != 0; + } + + public bool isByRefLike(CORINFO_CLASS_STRUCT_* cls) + { + IntPtr exception = 0; + byte result; + result = _forwarders->isByRefLike(_target, &exception, cls); + if (exception != 0) + throw new EEException(exception); + return result != 0; + } + + public bool isSharedInst(CORINFO_CLASS_STRUCT_* cls) + { + IntPtr exception = 0; + byte result; + result = _forwarders->isSharedInst(_target, &exception, cls); + if (exception != 0) + throw new EEException(exception); + return result != 0; + } + + public uint getClassAttribs(CORINFO_CLASS_STRUCT_* cls) + { + IntPtr exception = 0; + uint result; + result = _forwarders->getClassAttribs(_target, &exception, cls); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public byte* getClassAssemblyName(CORINFO_CLASS_STRUCT_* cls) + { + IntPtr exception = 0; + byte* result; + result = _forwarders->getClassAssemblyName(_target, &exception, cls); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public void* LongLifetimeMalloc(nuint sz) + { + IntPtr exception = 0; + void* result; + result = _forwarders->LongLifetimeMalloc(_target, &exception, sz); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public void LongLifetimeFree(void* obj) + { + IntPtr exception = 0; + _forwarders->LongLifetimeFree(_target, &exception, obj); + if (exception != 0) + throw new EEException(exception); + } + + public bool getIsClassInitedFlagAddress(CORINFO_CLASS_STRUCT_* cls, ref CORINFO_CONST_LOOKUP addr, ref int offset) + { + IntPtr exception = 0; + byte result; + fixed (CORINFO_CONST_LOOKUP* p_addr = &addr) + fixed (int* p_offset = &offset) + result = _forwarders->getIsClassInitedFlagAddress(_target, &exception, cls, p_addr, p_offset); + if (exception != 0) + throw new EEException(exception); + return result != 0; + } + + public void* getClassThreadStaticDynamicInfo(CORINFO_CLASS_STRUCT_* clr) + { + IntPtr exception = 0; + void* result; + result = _forwarders->getClassThreadStaticDynamicInfo(_target, &exception, clr); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public void* getClassStaticDynamicInfo(CORINFO_CLASS_STRUCT_* clr) + { + IntPtr exception = 0; + void* result; + result = _forwarders->getClassStaticDynamicInfo(_target, &exception, clr); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public bool getStaticBaseAddress(CORINFO_CLASS_STRUCT_* cls, bool isGc, ref CORINFO_CONST_LOOKUP addr) + { + IntPtr exception = 0; + byte result; + fixed (CORINFO_CONST_LOOKUP* p_addr = &addr) + result = _forwarders->getStaticBaseAddress(_target, &exception, cls, isGc ? (byte)1 : (byte)0, p_addr); + if (exception != 0) + throw new EEException(exception); + return result != 0; + } + + public uint getClassSize(CORINFO_CLASS_STRUCT_* cls) + { + IntPtr exception = 0; + uint result; + result = _forwarders->getClassSize(_target, &exception, cls); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public uint getHeapClassSize(CORINFO_CLASS_STRUCT_* cls) + { + IntPtr exception = 0; + uint result; + result = _forwarders->getHeapClassSize(_target, &exception, cls); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public bool canAllocateOnStack(CORINFO_CLASS_STRUCT_* cls) + { + IntPtr exception = 0; + byte result; + result = _forwarders->canAllocateOnStack(_target, &exception, cls); + if (exception != 0) + throw new EEException(exception); + return result != 0; + } + + public uint getClassAlignmentRequirement(CORINFO_CLASS_STRUCT_* cls, bool fDoubleAlignHint) + { + IntPtr exception = 0; + uint result; + result = _forwarders->getClassAlignmentRequirement(_target, &exception, cls, fDoubleAlignHint ? (byte)1 : (byte)0); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public uint getClassGClayout(CORINFO_CLASS_STRUCT_* cls, byte* gcPtrs) + { + IntPtr exception = 0; + uint result; + result = _forwarders->getClassGClayout(_target, &exception, cls, gcPtrs); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public uint getClassNumInstanceFields(CORINFO_CLASS_STRUCT_* cls) + { + IntPtr exception = 0; + uint result; + result = _forwarders->getClassNumInstanceFields(_target, &exception, cls); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public CORINFO_FIELD_STRUCT_* getFieldInClass(CORINFO_CLASS_STRUCT_* clsHnd, int num) + { + IntPtr exception = 0; + CORINFO_FIELD_STRUCT_* result; + result = _forwarders->getFieldInClass(_target, &exception, clsHnd, num); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public GetTypeLayoutResult getTypeLayout(CORINFO_CLASS_STRUCT_* typeHnd, CORINFO_TYPE_LAYOUT_NODE* treeNodes, nuint* numTreeNodes) + { + IntPtr exception = 0; + GetTypeLayoutResult result; + result = _forwarders->getTypeLayout(_target, &exception, typeHnd, treeNodes, numTreeNodes); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public bool checkMethodModifier(CORINFO_METHOD_STRUCT_* hMethod, byte* modifier, bool fOptional) + { + IntPtr exception = 0; + byte result; + result = _forwarders->checkMethodModifier(_target, &exception, hMethod, modifier, fOptional ? (byte)1 : (byte)0); + if (exception != 0) + throw new EEException(exception); + return result != 0; + } + + public CorInfoHelpFunc getNewHelper(CORINFO_CLASS_STRUCT_* classHandle, ref bool pHasSideEffects) + { + IntPtr exception = 0; + CorInfoHelpFunc result; + fixed (bool* p_pHasSideEffects = &pHasSideEffects) + result = _forwarders->getNewHelper(_target, &exception, classHandle, p_pHasSideEffects); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public CorInfoHelpFunc getNewArrHelper(CORINFO_CLASS_STRUCT_* arrayCls) + { + IntPtr exception = 0; + CorInfoHelpFunc result; + result = _forwarders->getNewArrHelper(_target, &exception, arrayCls); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public CorInfoHelpFunc getCastingHelper(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool fThrowing) + { + IntPtr exception = 0; + CorInfoHelpFunc result; + fixed (CORINFO_RESOLVED_TOKEN* p_pResolvedToken = &pResolvedToken) + result = _forwarders->getCastingHelper(_target, &exception, p_pResolvedToken, fThrowing ? (byte)1 : (byte)0); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public CorInfoHelpFunc getSharedCCtorHelper(CORINFO_CLASS_STRUCT_* clsHnd) + { + IntPtr exception = 0; + CorInfoHelpFunc result; + result = _forwarders->getSharedCCtorHelper(_target, &exception, clsHnd); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public CORINFO_CLASS_STRUCT_* getTypeForBox(CORINFO_CLASS_STRUCT_* cls) + { + IntPtr exception = 0; + CORINFO_CLASS_STRUCT_* result; + result = _forwarders->getTypeForBox(_target, &exception, cls); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public CorInfoHelpFunc getBoxHelper(CORINFO_CLASS_STRUCT_* cls) + { + IntPtr exception = 0; + CorInfoHelpFunc result; + result = _forwarders->getBoxHelper(_target, &exception, cls); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public CorInfoHelpFunc getUnBoxHelper(CORINFO_CLASS_STRUCT_* cls) + { + IntPtr exception = 0; + CorInfoHelpFunc result; + result = _forwarders->getUnBoxHelper(_target, &exception, cls); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public CORINFO_OBJECT_STRUCT_* getRuntimeTypePointer(CORINFO_CLASS_STRUCT_* cls) + { + IntPtr exception = 0; + CORINFO_OBJECT_STRUCT_* result; + result = _forwarders->getRuntimeTypePointer(_target, &exception, cls); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public bool isObjectImmutable(CORINFO_OBJECT_STRUCT_* objPtr) + { + IntPtr exception = 0; + byte result; + result = _forwarders->isObjectImmutable(_target, &exception, objPtr); + if (exception != 0) + throw new EEException(exception); + return result != 0; + } + + public bool getStringChar(CORINFO_OBJECT_STRUCT_* strObj, int index, ushort* value) + { + IntPtr exception = 0; + byte result; + result = _forwarders->getStringChar(_target, &exception, strObj, index, value); + if (exception != 0) + throw new EEException(exception); + return result != 0; + } + + public CORINFO_CLASS_STRUCT_* getObjectType(CORINFO_OBJECT_STRUCT_* objPtr) + { + IntPtr exception = 0; + CORINFO_CLASS_STRUCT_* result; + result = _forwarders->getObjectType(_target, &exception, objPtr); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public bool getReadyToRunHelper(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CorInfoHelpFunc id, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_CONST_LOOKUP pLookup) + { + IntPtr exception = 0; + byte result; + fixed (CORINFO_RESOLVED_TOKEN* p_pResolvedToken = &pResolvedToken) + fixed (CORINFO_CONST_LOOKUP* p_pLookup = &pLookup) + result = _forwarders->getReadyToRunHelper(_target, &exception, p_pResolvedToken, id, callerHandle, p_pLookup); + if (exception != 0) + throw new EEException(exception); + return result != 0; + } + + public void getReadyToRunDelegateCtorHelper(ref CORINFO_RESOLVED_TOKEN pTargetMethod, mdToken targetConstraint, CORINFO_CLASS_STRUCT_* delegateType, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_LOOKUP pLookup) + { + IntPtr exception = 0; + fixed (CORINFO_RESOLVED_TOKEN* p_pTargetMethod = &pTargetMethod) + fixed (CORINFO_LOOKUP* p_pLookup = &pLookup) + _forwarders->getReadyToRunDelegateCtorHelper(_target, &exception, p_pTargetMethod, targetConstraint, delegateType, callerHandle, p_pLookup); + if (exception != 0) + throw new EEException(exception); + } + + public CorInfoInitClassResult initClass(CORINFO_FIELD_STRUCT_* field, CORINFO_METHOD_STRUCT_* method, CORINFO_CONTEXT_STRUCT* context) + { + IntPtr exception = 0; + CorInfoInitClassResult result; + result = _forwarders->initClass(_target, &exception, field, method, context); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public CORINFO_CLASS_STRUCT_* getBuiltinClass(CorInfoClassId classId) + { + IntPtr exception = 0; + CORINFO_CLASS_STRUCT_* result; + result = _forwarders->getBuiltinClass(_target, &exception, classId); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public CorInfoType getTypeForPrimitiveValueClass(CORINFO_CLASS_STRUCT_* cls) + { + IntPtr exception = 0; + CorInfoType result; + result = _forwarders->getTypeForPrimitiveValueClass(_target, &exception, cls); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public CorInfoType getTypeForPrimitiveNumericClass(CORINFO_CLASS_STRUCT_* cls) + { + IntPtr exception = 0; + CorInfoType result; + result = _forwarders->getTypeForPrimitiveNumericClass(_target, &exception, cls); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public bool canCast(CORINFO_CLASS_STRUCT_* child, CORINFO_CLASS_STRUCT_* parent) + { + IntPtr exception = 0; + byte result; + result = _forwarders->canCast(_target, &exception, child, parent); + if (exception != 0) + throw new EEException(exception); + return result != 0; + } + + public TypeCompareState compareTypesForCast(CORINFO_CLASS_STRUCT_* fromClass, CORINFO_CLASS_STRUCT_* toClass) + { + IntPtr exception = 0; + TypeCompareState result; + result = _forwarders->compareTypesForCast(_target, &exception, fromClass, toClass); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public TypeCompareState compareTypesForEquality(CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2) + { + IntPtr exception = 0; + TypeCompareState result; + result = _forwarders->compareTypesForEquality(_target, &exception, cls1, cls2); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public bool isMoreSpecificType(CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2) + { + IntPtr exception = 0; + byte result; + result = _forwarders->isMoreSpecificType(_target, &exception, cls1, cls2); + if (exception != 0) + throw new EEException(exception); + return result != 0; + } + + public bool isExactType(CORINFO_CLASS_STRUCT_* cls) + { + IntPtr exception = 0; + byte result; + result = _forwarders->isExactType(_target, &exception, cls); + if (exception != 0) + throw new EEException(exception); + return result != 0; + } + + public TypeCompareState isGenericType(CORINFO_CLASS_STRUCT_* cls) + { + IntPtr exception = 0; + TypeCompareState result; + result = _forwarders->isGenericType(_target, &exception, cls); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public TypeCompareState isNullableType(CORINFO_CLASS_STRUCT_* cls) + { + IntPtr exception = 0; + TypeCompareState result; + result = _forwarders->isNullableType(_target, &exception, cls); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public TypeCompareState isEnum(CORINFO_CLASS_STRUCT_* cls, CORINFO_CLASS_STRUCT_** underlyingType) + { + IntPtr exception = 0; + TypeCompareState result; + result = _forwarders->isEnum(_target, &exception, cls, underlyingType); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public CORINFO_CLASS_STRUCT_* getParentType(CORINFO_CLASS_STRUCT_* cls) + { + IntPtr exception = 0; + CORINFO_CLASS_STRUCT_* result; + result = _forwarders->getParentType(_target, &exception, cls); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public CorInfoType getChildType(CORINFO_CLASS_STRUCT_* clsHnd, CORINFO_CLASS_STRUCT_** clsRet) + { + IntPtr exception = 0; + CorInfoType result; + result = _forwarders->getChildType(_target, &exception, clsHnd, clsRet); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public bool isSDArray(CORINFO_CLASS_STRUCT_* cls) + { + IntPtr exception = 0; + byte result; + result = _forwarders->isSDArray(_target, &exception, cls); + if (exception != 0) + throw new EEException(exception); + return result != 0; + } + + public uint getArrayRank(CORINFO_CLASS_STRUCT_* cls) + { + IntPtr exception = 0; + uint result; + result = _forwarders->getArrayRank(_target, &exception, cls); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public CorInfoArrayIntrinsic getArrayIntrinsicID(CORINFO_METHOD_STRUCT_* ftn) + { + IntPtr exception = 0; + CorInfoArrayIntrinsic result; + result = _forwarders->getArrayIntrinsicID(_target, &exception, ftn); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public void* getArrayInitializationData(CORINFO_FIELD_STRUCT_* field, uint size) + { + IntPtr exception = 0; + void* result; + result = _forwarders->getArrayInitializationData(_target, &exception, field, size); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public CorInfoIsAccessAllowedResult canAccessClass(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_HELPER_DESC pAccessHelper) + { + IntPtr exception = 0; + CorInfoIsAccessAllowedResult result; + fixed (CORINFO_RESOLVED_TOKEN* p_pResolvedToken = &pResolvedToken) + fixed (CORINFO_HELPER_DESC* p_pAccessHelper = &pAccessHelper) + result = _forwarders->canAccessClass(_target, &exception, p_pResolvedToken, callerHandle, p_pAccessHelper); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public nuint printFieldName(CORINFO_FIELD_STRUCT_* field, byte* buffer, nuint bufferSize, nuint* pRequiredBufferSize) + { + IntPtr exception = 0; + nuint result; + result = _forwarders->printFieldName(_target, &exception, field, buffer, bufferSize, pRequiredBufferSize); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public CORINFO_CLASS_STRUCT_* getFieldClass(CORINFO_FIELD_STRUCT_* field) + { + IntPtr exception = 0; + CORINFO_CLASS_STRUCT_* result; + result = _forwarders->getFieldClass(_target, &exception, field); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public CorInfoType getFieldType(CORINFO_FIELD_STRUCT_* field, CORINFO_CLASS_STRUCT_** structType, CORINFO_CLASS_STRUCT_* fieldOwnerHint) + { + IntPtr exception = 0; + CorInfoType result; + result = _forwarders->getFieldType(_target, &exception, field, structType, fieldOwnerHint); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public uint getFieldOffset(CORINFO_FIELD_STRUCT_* field) + { + IntPtr exception = 0; + uint result; + result = _forwarders->getFieldOffset(_target, &exception, field); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public void getFieldInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult) + { + IntPtr exception = 0; + fixed (CORINFO_RESOLVED_TOKEN* p_pResolvedToken = &pResolvedToken) + _forwarders->getFieldInfo(_target, &exception, p_pResolvedToken, callerHandle, flags, pResult); + if (exception != 0) + throw new EEException(exception); + } + + public uint getThreadLocalFieldInfo(CORINFO_FIELD_STRUCT_* field, bool isGCtype) + { + IntPtr exception = 0; + uint result; + result = _forwarders->getThreadLocalFieldInfo(_target, &exception, field, isGCtype ? (byte)1 : (byte)0); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public void getThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) + { + IntPtr exception = 0; + _forwarders->getThreadLocalStaticBlocksInfo(_target, &exception, pInfo); + if (exception != 0) + throw new EEException(exception); + } + + public void getThreadLocalStaticInfo_NativeAOT(CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo) + { + IntPtr exception = 0; + _forwarders->getThreadLocalStaticInfo_NativeAOT(_target, &exception, pInfo); + if (exception != 0) + throw new EEException(exception); + } + + public bool isFieldStatic(CORINFO_FIELD_STRUCT_* fldHnd) + { + IntPtr exception = 0; + byte result; + result = _forwarders->isFieldStatic(_target, &exception, fldHnd); + if (exception != 0) + throw new EEException(exception); + return result != 0; + } + + public int getArrayOrStringLength(CORINFO_OBJECT_STRUCT_* objHnd) + { + IntPtr exception = 0; + int result; + result = _forwarders->getArrayOrStringLength(_target, &exception, objHnd); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public void getBoundaries(CORINFO_METHOD_STRUCT_* ftn, ref uint cILOffsets, ref uint* pILOffsets, BoundaryTypes* implicitBoundaries) + { + IntPtr exception = 0; + fixed (uint* p_cILOffsets = &cILOffsets) + fixed (uint** p_pILOffsets = &pILOffsets) + _forwarders->getBoundaries(_target, &exception, ftn, p_cILOffsets, p_pILOffsets, implicitBoundaries); + if (exception != 0) + throw new EEException(exception); + } + + public void setBoundaries(CORINFO_METHOD_STRUCT_* ftn, uint cMap, OffsetMapping* pMap) + { + IntPtr exception = 0; + _forwarders->setBoundaries(_target, &exception, ftn, cMap, pMap); + if (exception != 0) + throw new EEException(exception); + } + + public void getVars(CORINFO_METHOD_STRUCT_* ftn, ref uint cVars, ILVarInfo** vars, ref bool extendOthers) + { + IntPtr exception = 0; + fixed (uint* p_cVars = &cVars) + fixed (bool* p_extendOthers = &extendOthers) + _forwarders->getVars(_target, &exception, ftn, p_cVars, vars, p_extendOthers); + if (exception != 0) + throw new EEException(exception); + } + + public void setVars(CORINFO_METHOD_STRUCT_* ftn, uint cVars, NativeVarInfo* vars) + { + IntPtr exception = 0; + _forwarders->setVars(_target, &exception, ftn, cVars, vars); + if (exception != 0) + throw new EEException(exception); + } + + public void reportRichMappings(InlineTreeNode* inlineTreeNodes, uint numInlineTreeNodes, RichOffsetMapping* mappings, uint numMappings) + { + IntPtr exception = 0; + _forwarders->reportRichMappings(_target, &exception, inlineTreeNodes, numInlineTreeNodes, mappings, numMappings); + if (exception != 0) + throw new EEException(exception); + } + + public void reportAsyncDebugInfo(AsyncInfo* asyncInfo, AsyncSuspensionPoint* suspensionPoints, AsyncContinuationVarInfo* vars, uint numVars) + { + IntPtr exception = 0; + _forwarders->reportAsyncDebugInfo(_target, &exception, asyncInfo, suspensionPoints, vars, numVars); + if (exception != 0) + throw new EEException(exception); + } + + public void reportMetadata(byte* key, void* value, nuint length) + { + IntPtr exception = 0; + _forwarders->reportMetadata(_target, &exception, key, value, length); + if (exception != 0) + throw new EEException(exception); + } + + public void* allocateArray(nuint cBytes) + { + IntPtr exception = 0; + void* result; + result = _forwarders->allocateArray(_target, &exception, cBytes); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public void freeArray(void* array) + { + IntPtr exception = 0; + _forwarders->freeArray(_target, &exception, array); + if (exception != 0) + throw new EEException(exception); + } + + public CORINFO_ARG_LIST_STRUCT_* getArgNext(CORINFO_ARG_LIST_STRUCT_* args) + { + IntPtr exception = 0; + CORINFO_ARG_LIST_STRUCT_* result; + result = _forwarders->getArgNext(_target, &exception, args); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public CorInfoTypeWithMod getArgType(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_STRUCT_* args, CORINFO_CLASS_STRUCT_** vcTypeRet) + { + IntPtr exception = 0; + CorInfoTypeWithMod result; + result = _forwarders->getArgType(_target, &exception, sig, args, vcTypeRet); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public int getExactClasses(CORINFO_CLASS_STRUCT_* baseType, int maxExactClasses, CORINFO_CLASS_STRUCT_** exactClsRet) + { + IntPtr exception = 0; + int result; + result = _forwarders->getExactClasses(_target, &exception, baseType, maxExactClasses, exactClsRet); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public CORINFO_CLASS_STRUCT_* getArgClass(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_STRUCT_* args) + { + IntPtr exception = 0; + CORINFO_CLASS_STRUCT_* result; + result = _forwarders->getArgClass(_target, &exception, sig, args); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public CorInfoHFAElemType getHFAType(CORINFO_CLASS_STRUCT_* hClass) + { + IntPtr exception = 0; + CorInfoHFAElemType result; + result = _forwarders->getHFAType(_target, &exception, hClass); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public bool runWithErrorTrap(void* function, void* parameter) + { + IntPtr exception = 0; + byte result; + result = _forwarders->runWithErrorTrap(_target, &exception, function, parameter); + if (exception != 0) + throw new EEException(exception); + return result != 0; + } + + public bool runWithSPMIErrorTrap(void* function, void* parameter) + { + IntPtr exception = 0; + byte result; + result = _forwarders->runWithSPMIErrorTrap(_target, &exception, function, parameter); + if (exception != 0) + throw new EEException(exception); + return result != 0; + } + + public void getEEInfo(ref CORINFO_EE_INFO pEEInfoOut) + { + IntPtr exception = 0; + fixed (CORINFO_EE_INFO* p_pEEInfoOut = &pEEInfoOut) + _forwarders->getEEInfo(_target, &exception, p_pEEInfoOut); + if (exception != 0) + throw new EEException(exception); + } + + public void getAsyncInfo(ref CORINFO_ASYNC_INFO pAsyncInfoOut) + { + IntPtr exception = 0; + fixed (CORINFO_ASYNC_INFO* p_pAsyncInfoOut = &pAsyncInfoOut) + _forwarders->getAsyncInfo(_target, &exception, p_pAsyncInfoOut); + if (exception != 0) + throw new EEException(exception); + } + + public CORINFO_METHOD_STRUCT_* getAwaitReturnCall(CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_CONTEXT_STRUCT** contextHandle, ref CORINFO_LOOKUP instArg) + { + IntPtr exception = 0; + CORINFO_METHOD_STRUCT_* result; + fixed (CORINFO_LOOKUP* p_instArg = &instArg) + result = _forwarders->getAwaitReturnCall(_target, &exception, callerHandle, contextHandle, p_instArg); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public CORINFO_METHOD_STRUCT_* getAwaitAwaiterInContinuationCall(CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool isUnsafe, CORINFO_CONTEXT_STRUCT** contextHandle, ref CORINFO_LOOKUP instArg) + { + IntPtr exception = 0; + CORINFO_METHOD_STRUCT_* result; + fixed (CORINFO_RESOLVED_TOKEN* p_pResolvedToken = &pResolvedToken) + fixed (CORINFO_LOOKUP* p_instArg = &instArg) + result = _forwarders->getAwaitAwaiterInContinuationCall(_target, &exception, callerHandle, p_pResolvedToken, isUnsafe ? (byte)1 : (byte)0, contextHandle, p_instArg); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public mdToken getMethodDefFromMethod(CORINFO_METHOD_STRUCT_* hMethod) + { + IntPtr exception = 0; + mdToken result; + result = _forwarders->getMethodDefFromMethod(_target, &exception, hMethod); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public nuint printMethodName(CORINFO_METHOD_STRUCT_* ftn, byte* buffer, nuint bufferSize, nuint* pRequiredBufferSize) + { + IntPtr exception = 0; + nuint result; + result = _forwarders->printMethodName(_target, &exception, ftn, buffer, bufferSize, pRequiredBufferSize); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public byte* getMethodNameFromMetadata(CORINFO_METHOD_STRUCT_* ftn, byte** className, byte** namespaceName, byte** enclosingClassNames, nuint maxEnclosingClassNames) + { + IntPtr exception = 0; + byte* result; + result = _forwarders->getMethodNameFromMetadata(_target, &exception, ftn, className, namespaceName, enclosingClassNames, maxEnclosingClassNames); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public uint getMethodHash(CORINFO_METHOD_STRUCT_* ftn) + { + IntPtr exception = 0; + uint result; + result = _forwarders->getMethodHash(_target, &exception, ftn); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public bool getSystemVAmd64PassStructInRegisterDescriptor(CORINFO_CLASS_STRUCT_* structHnd, SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr) + { + IntPtr exception = 0; + byte result; + result = _forwarders->getSystemVAmd64PassStructInRegisterDescriptor(_target, &exception, structHnd, structPassInRegDescPtr); + if (exception != 0) + throw new EEException(exception); + return result != 0; + } + + public void getSwiftLowering(CORINFO_CLASS_STRUCT_* structHnd, ref CORINFO_SWIFT_LOWERING pLowering) + { + IntPtr exception = 0; + fixed (CORINFO_SWIFT_LOWERING* p_pLowering = &pLowering) + _forwarders->getSwiftLowering(_target, &exception, structHnd, p_pLowering); + if (exception != 0) + throw new EEException(exception); + } + + public void getFpStructLowering(CORINFO_CLASS_STRUCT_* structHnd, ref CORINFO_FPSTRUCT_LOWERING pLowering) + { + IntPtr exception = 0; + fixed (CORINFO_FPSTRUCT_LOWERING* p_pLowering = &pLowering) + _forwarders->getFpStructLowering(_target, &exception, structHnd, p_pLowering); + if (exception != 0) + throw new EEException(exception); + } + + public CorInfoWasmType getWasmLowering(CORINFO_CLASS_STRUCT_* structHnd) + { + IntPtr exception = 0; + CorInfoWasmType result; + result = _forwarders->getWasmLowering(_target, &exception, structHnd); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public uint getAddressAlignment(void* address) + { + IntPtr exception = 0; + uint result; + result = _forwarders->getAddressAlignment(_target, &exception, address); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public void getWasmWellKnownGlobals(ref CORINFO_WASM_WELLKNOWN_GLOBALS pWellKnownGlobalsOut) + { + IntPtr exception = 0; + fixed (CORINFO_WASM_WELLKNOWN_GLOBALS* p_pWellKnownGlobalsOut = &pWellKnownGlobalsOut) + _forwarders->getWasmWellKnownGlobals(_target, &exception, p_pWellKnownGlobalsOut); + if (exception != 0) + throw new EEException(exception); + } + + public uint getThreadTLSIndex(ref void* ppIndirection) + { + IntPtr exception = 0; + uint result; + fixed (void** p_ppIndirection = &ppIndirection) + result = _forwarders->getThreadTLSIndex(_target, &exception, p_ppIndirection); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public int* getAddrOfCaptureThreadGlobal(ref void* ppIndirection) + { + IntPtr exception = 0; + int* result; + fixed (void** p_ppIndirection = &ppIndirection) + result = _forwarders->getAddrOfCaptureThreadGlobal(_target, &exception, p_ppIndirection); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public void getHelperFtn(CorInfoHelpFunc ftnNum, CORINFO_CONST_LOOKUP* pNativeEntrypoint, CORINFO_METHOD_STRUCT_** pMethod) + { + IntPtr exception = 0; + _forwarders->getHelperFtn(_target, &exception, ftnNum, pNativeEntrypoint, pMethod); + if (exception != 0) + throw new EEException(exception); + } + + public void getFunctionEntryPoint(CORINFO_METHOD_STRUCT_* ftn, ref CORINFO_CONST_LOOKUP pResult, CORINFO_ACCESS_FLAGS accessFlags) + { + IntPtr exception = 0; + fixed (CORINFO_CONST_LOOKUP* p_pResult = &pResult) + _forwarders->getFunctionEntryPoint(_target, &exception, ftn, p_pResult, accessFlags); + if (exception != 0) + throw new EEException(exception); + } + + public void getFunctionFixedEntryPoint(CORINFO_METHOD_STRUCT_* ftn, bool isUnsafeFunctionPointer, ref CORINFO_CONST_LOOKUP pResult) + { + IntPtr exception = 0; + fixed (CORINFO_CONST_LOOKUP* p_pResult = &pResult) + _forwarders->getFunctionFixedEntryPoint(_target, &exception, ftn, isUnsafeFunctionPointer ? (byte)1 : (byte)0, p_pResult); + if (exception != 0) + throw new EEException(exception); + } + + public CORINFO_MODULE_STRUCT_* embedModuleHandle(CORINFO_MODULE_STRUCT_* handle, ref void* ppIndirection) + { + IntPtr exception = 0; + CORINFO_MODULE_STRUCT_* result; + fixed (void** p_ppIndirection = &ppIndirection) + result = _forwarders->embedModuleHandle(_target, &exception, handle, p_ppIndirection); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public CORINFO_CLASS_STRUCT_* embedClassHandle(CORINFO_CLASS_STRUCT_* handle, ref void* ppIndirection) + { + IntPtr exception = 0; + CORINFO_CLASS_STRUCT_* result; + fixed (void** p_ppIndirection = &ppIndirection) + result = _forwarders->embedClassHandle(_target, &exception, handle, p_ppIndirection); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public CORINFO_METHOD_STRUCT_* embedMethodHandle(CORINFO_METHOD_STRUCT_* handle, ref void* ppIndirection) + { + IntPtr exception = 0; + CORINFO_METHOD_STRUCT_* result; + fixed (void** p_ppIndirection = &ppIndirection) + result = _forwarders->embedMethodHandle(_target, &exception, handle, p_ppIndirection); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public CORINFO_FIELD_STRUCT_* embedFieldHandle(CORINFO_FIELD_STRUCT_* handle, ref void* ppIndirection) + { + IntPtr exception = 0; + CORINFO_FIELD_STRUCT_* result; + fixed (void** p_ppIndirection = &ppIndirection) + result = _forwarders->embedFieldHandle(_target, &exception, handle, p_ppIndirection); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public void embedGenericHandle(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool fEmbedParent, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_GENERICHANDLE_RESULT pResult) + { + IntPtr exception = 0; + fixed (CORINFO_RESOLVED_TOKEN* p_pResolvedToken = &pResolvedToken) + fixed (CORINFO_GENERICHANDLE_RESULT* p_pResult = &pResult) + _forwarders->embedGenericHandle(_target, &exception, p_pResolvedToken, fEmbedParent ? (byte)1 : (byte)0, callerHandle, p_pResult); + if (exception != 0) + throw new EEException(exception); + } + + public void getLocationOfThisType(CORINFO_METHOD_STRUCT_* context, ref CORINFO_LOOKUP_KIND pLookupKind) + { + IntPtr exception = 0; + fixed (CORINFO_LOOKUP_KIND* p_pLookupKind = &pLookupKind) + _forwarders->getLocationOfThisType(_target, &exception, context, p_pLookupKind); + if (exception != 0) + throw new EEException(exception); + } + + public void getAddressOfPInvokeTarget(CORINFO_METHOD_STRUCT_* method, ref CORINFO_CONST_LOOKUP pLookup) + { + IntPtr exception = 0; + fixed (CORINFO_CONST_LOOKUP* p_pLookup = &pLookup) + _forwarders->getAddressOfPInvokeTarget(_target, &exception, method, p_pLookup); + if (exception != 0) + throw new EEException(exception); + } + + public void* GetCookieForInterpreterCalliSig(CORINFO_SIG_INFO* szMetaSig) + { + IntPtr exception = 0; + void* result; + result = _forwarders->GetCookieForInterpreterCalliSig(_target, &exception, szMetaSig); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public CORINFO_JUST_MY_CODE_HANDLE_* getJustMyCodeHandle(CORINFO_METHOD_STRUCT_* method, ref CORINFO_JUST_MY_CODE_HANDLE_* ppIndirection) + { + IntPtr exception = 0; + CORINFO_JUST_MY_CODE_HANDLE_* result; + fixed (CORINFO_JUST_MY_CODE_HANDLE_** p_ppIndirection = &ppIndirection) + result = _forwarders->getJustMyCodeHandle(_target, &exception, method, p_ppIndirection); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public void GetProfilingHandle(ref bool pbHookFunction, ref void* pProfilerHandle, ref bool pbIndirectedHandles) + { + IntPtr exception = 0; + fixed (bool* p_pbHookFunction = &pbHookFunction) + fixed (void** p_pProfilerHandle = &pProfilerHandle) + fixed (bool* p_pbIndirectedHandles = &pbIndirectedHandles) + _forwarders->GetProfilingHandle(_target, &exception, p_pbHookFunction, p_pProfilerHandle, p_pbIndirectedHandles); + if (exception != 0) + throw new EEException(exception); + } + + public void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_CALLINFO_FLAGS flags, CORINFO_CALL_INFO* pResult) + { + IntPtr exception = 0; + fixed (CORINFO_RESOLVED_TOKEN* p_pResolvedToken = &pResolvedToken) + _forwarders->getCallInfo(_target, &exception, p_pResolvedToken, pConstrainedResolvedToken, callerHandle, flags, pResult); + if (exception != 0) + throw new EEException(exception); + } + + public bool getStaticFieldContent(CORINFO_FIELD_STRUCT_* field, byte* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects) + { + IntPtr exception = 0; + byte result; + result = _forwarders->getStaticFieldContent(_target, &exception, field, buffer, bufferSize, valueOffset, ignoreMovableObjects ? (byte)1 : (byte)0); + if (exception != 0) + throw new EEException(exception); + return result != 0; + } + + public bool getObjectContent(CORINFO_OBJECT_STRUCT_* obj, byte* buffer, int bufferSize, int valueOffset) + { + IntPtr exception = 0; + byte result; + result = _forwarders->getObjectContent(_target, &exception, obj, buffer, bufferSize, valueOffset); + if (exception != 0) + throw new EEException(exception); + return result != 0; + } + + public CORINFO_CLASS_STRUCT_* getStaticFieldCurrentClass(CORINFO_FIELD_STRUCT_* field, byte* pIsSpeculative) + { + IntPtr exception = 0; + CORINFO_CLASS_STRUCT_* result; + result = _forwarders->getStaticFieldCurrentClass(_target, &exception, field, pIsSpeculative); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public IntPtr getVarArgsHandle(CORINFO_SIG_INFO* pSig, CORINFO_METHOD_STRUCT_* methHnd, ref void* ppIndirection) + { + IntPtr exception = 0; + IntPtr result; + fixed (void** p_ppIndirection = &ppIndirection) + result = _forwarders->getVarArgsHandle(_target, &exception, pSig, methHnd, p_ppIndirection); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public InfoAccessType constructStringLiteral(CORINFO_MODULE_STRUCT_* module, mdToken metaTok, ref void* ppValue) + { + IntPtr exception = 0; + InfoAccessType result; + fixed (void** p_ppValue = &ppValue) + result = _forwarders->constructStringLiteral(_target, &exception, module, metaTok, p_ppValue); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public InfoAccessType emptyStringLiteral(ref void* ppValue) + { + IntPtr exception = 0; + InfoAccessType result; + fixed (void** p_ppValue = &ppValue) + result = _forwarders->emptyStringLiteral(_target, &exception, p_ppValue); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public uint getFieldThreadLocalStoreID(CORINFO_FIELD_STRUCT_* field, ref void* ppIndirection) + { + IntPtr exception = 0; + uint result; + fixed (void** p_ppIndirection = &ppIndirection) + result = _forwarders->getFieldThreadLocalStoreID(_target, &exception, field, p_ppIndirection); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public CORINFO_METHOD_STRUCT_* GetDelegateCtor(CORINFO_METHOD_STRUCT_* methHnd, CORINFO_CLASS_STRUCT_* clsHnd, CORINFO_METHOD_STRUCT_* targetMethodHnd, ref DelegateCtorArgs pCtorData) + { + IntPtr exception = 0; + CORINFO_METHOD_STRUCT_* result; + fixed (DelegateCtorArgs* p_pCtorData = &pCtorData) + result = _forwarders->GetDelegateCtor(_target, &exception, methHnd, clsHnd, targetMethodHnd, p_pCtorData); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public void MethodCompileComplete(CORINFO_METHOD_STRUCT_* methHnd) + { + IntPtr exception = 0; + _forwarders->MethodCompileComplete(_target, &exception, methHnd); + if (exception != 0) + throw new EEException(exception); + } + + public bool getTailCallHelpers(ref CORINFO_RESOLVED_TOKEN callToken, CORINFO_SIG_INFO* sig, CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, ref CORINFO_TAILCALL_HELPERS pResult) + { + IntPtr exception = 0; + byte result; + fixed (CORINFO_RESOLVED_TOKEN* p_callToken = &callToken) + fixed (CORINFO_TAILCALL_HELPERS* p_pResult = &pResult) + result = _forwarders->getTailCallHelpers(_target, &exception, p_callToken, sig, flags, p_pResult); + if (exception != 0) + throw new EEException(exception); + return result != 0; + } + + public CORINFO_CLASS_STRUCT_* getContinuationType(nuint dataSize, ref bool objRefs, nuint objRefsSize) + { + IntPtr exception = 0; + CORINFO_CLASS_STRUCT_* result; + fixed (bool* p_objRefs = &objRefs) + result = _forwarders->getContinuationType(_target, &exception, dataSize, p_objRefs, objRefsSize); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public CORINFO_METHOD_STRUCT_* getAsyncResumptionStub(ref void* entryPoint) + { + IntPtr exception = 0; + CORINFO_METHOD_STRUCT_* result; + fixed (void** p_entryPoint = &entryPoint) + result = _forwarders->getAsyncResumptionStub(_target, &exception, p_entryPoint); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public bool convertPInvokeCalliToCall(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool mustConvert) + { + IntPtr exception = 0; + byte result; + fixed (CORINFO_RESOLVED_TOKEN* p_pResolvedToken = &pResolvedToken) + result = _forwarders->convertPInvokeCalliToCall(_target, &exception, p_pResolvedToken, mustConvert ? (byte)1 : (byte)0); + if (exception != 0) + throw new EEException(exception); + return result != 0; + } + + public bool notifyInstructionSetUsage(InstructionSet instructionSet, bool supportEnabled, bool preserveNegativeDependency) + { + IntPtr exception = 0; + byte result; + result = _forwarders->notifyInstructionSetUsage(_target, &exception, instructionSet, supportEnabled ? (byte)1 : (byte)0, preserveNegativeDependency ? (byte)1 : (byte)0); + if (exception != 0) + throw new EEException(exception); + return result != 0; + } + + public void updateEntryPointForTailCall(ref CORINFO_CONST_LOOKUP entryPoint) + { + IntPtr exception = 0; + fixed (CORINFO_CONST_LOOKUP* p_entryPoint = &entryPoint) + _forwarders->updateEntryPointForTailCall(_target, &exception, p_entryPoint); + if (exception != 0) + throw new EEException(exception); + } + + public void allocMem(ref AllocMemArgs pArgs) + { + IntPtr exception = 0; + fixed (AllocMemArgs* p_pArgs = &pArgs) + _forwarders->allocMem(_target, &exception, p_pArgs); + if (exception != 0) + throw new EEException(exception); + } + + public void reserveUnwindInfo(bool isFunclet, bool isColdCode, uint unwindSize) + { + IntPtr exception = 0; + _forwarders->reserveUnwindInfo(_target, &exception, isFunclet ? (byte)1 : (byte)0, isColdCode ? (byte)1 : (byte)0, unwindSize); + if (exception != 0) + throw new EEException(exception); + } + + public void allocUnwindInfo(byte* pHotCode, byte* pColdCode, uint startOffset, uint endOffset, uint unwindSize, byte* pUnwindBlock, CorJitFuncKind funcKind) + { + IntPtr exception = 0; + _forwarders->allocUnwindInfo(_target, &exception, pHotCode, pColdCode, startOffset, endOffset, unwindSize, pUnwindBlock, funcKind); + if (exception != 0) + throw new EEException(exception); + } + + public void* allocGCInfo(nuint size) + { + IntPtr exception = 0; + void* result; + result = _forwarders->allocGCInfo(_target, &exception, size); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public void setEHcount(uint cEH) + { + IntPtr exception = 0; + _forwarders->setEHcount(_target, &exception, cEH); + if (exception != 0) + throw new EEException(exception); + } + + public void setEHinfo(uint EHnumber, ref CORINFO_EH_CLAUSE clause) + { + IntPtr exception = 0; + fixed (CORINFO_EH_CLAUSE* p_clause = &clause) + _forwarders->setEHinfo(_target, &exception, EHnumber, p_clause); + if (exception != 0) + throw new EEException(exception); + } + + public bool logMsg(uint level, byte* fmt, IntPtr args) + { + IntPtr exception = 0; + byte result; + result = _forwarders->logMsg(_target, &exception, level, fmt, args); + if (exception != 0) + throw new EEException(exception); + return result != 0; + } + + public int doAssert(byte* szFile, int iLine, byte* szExpr) + { + IntPtr exception = 0; + int result; + result = _forwarders->doAssert(_target, &exception, szFile, iLine, szExpr); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public void reportFatalError(CorJitResult result) + { + IntPtr exception = 0; + _forwarders->reportFatalError(_target, &exception, result); + if (exception != 0) + throw new EEException(exception); + } + + public HRESULT getPgoInstrumentationResults(CORINFO_METHOD_STRUCT_* ftnHnd, ref PgoInstrumentationSchema* pSchema, ref uint pCountSchemaItems, byte** pInstrumentationData, ref PgoSource pPgoSource, ref bool pDynamicPgo) + { + IntPtr exception = 0; + HRESULT result; + fixed (PgoInstrumentationSchema** p_pSchema = &pSchema) + fixed (uint* p_pCountSchemaItems = &pCountSchemaItems) + fixed (PgoSource* p_pPgoSource = &pPgoSource) + fixed (bool* p_pDynamicPgo = &pDynamicPgo) + result = _forwarders->getPgoInstrumentationResults(_target, &exception, ftnHnd, p_pSchema, p_pCountSchemaItems, pInstrumentationData, p_pPgoSource, p_pDynamicPgo); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public HRESULT allocPgoInstrumentationBySchema(CORINFO_METHOD_STRUCT_* ftnHnd, PgoInstrumentationSchema* pSchema, uint countSchemaItems, byte** pInstrumentationData) + { + IntPtr exception = 0; + HRESULT result; + result = _forwarders->allocPgoInstrumentationBySchema(_target, &exception, ftnHnd, pSchema, countSchemaItems, pInstrumentationData); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public void recordCallSite(uint instrOffset, CORINFO_SIG_INFO* callSig, CORINFO_METHOD_STRUCT_* methodHandle) + { + IntPtr exception = 0; + _forwarders->recordCallSite(_target, &exception, instrOffset, callSig, methodHandle); + if (exception != 0) + throw new EEException(exception); + } + + public void recordWasmManagedCallSig(CORINFO_SIG_INFO* callSig) + { + IntPtr exception = 0; + _forwarders->recordWasmManagedCallSig(_target, &exception, callSig); + if (exception != 0) + throw new EEException(exception); + } + + public void recordRelocation(void* location, void* locationRW, void* target, CorInfoReloc fRelocType, int addlDelta) + { + IntPtr exception = 0; + _forwarders->recordRelocation(_target, &exception, location, locationRW, target, fRelocType, addlDelta); + if (exception != 0) + throw new EEException(exception); + } + + public CorInfoReloc getRelocTypeHint(void* target) + { + IntPtr exception = 0; + CorInfoReloc result; + result = _forwarders->getRelocTypeHint(_target, &exception, target); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public uint getExpectedTargetArchitecture() + { + IntPtr exception = 0; + uint result; + result = _forwarders->getExpectedTargetArchitecture(_target, &exception); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public uint getJitFlags(ref CORJIT_FLAGS flags, uint sizeInBytes) + { + IntPtr exception = 0; + uint result; + fixed (CORJIT_FLAGS* p_flags = &flags) + result = _forwarders->getJitFlags(_target, &exception, p_flags, sizeInBytes); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public CORINFO_WASM_TYPE_SYMBOL_STRUCT_* getWasmTypeSymbol(CorInfoWasmType* types, nuint typesSize) + { + IntPtr exception = 0; + CORINFO_WASM_TYPE_SYMBOL_STRUCT_* result; + result = _forwarders->getWasmTypeSymbol(_target, &exception, types, typesSize); + if (exception != 0) + throw new EEException(exception); + return result; + } + + public CORINFO_METHOD_STRUCT_* getSpecialCopyHelper(CORINFO_CLASS_STRUCT_* type) + { + IntPtr exception = 0; + CORINFO_METHOD_STRUCT_* result; + result = _forwarders->getSpecialCopyHelper(_target, &exception, type); + if (exception != 0) + throw new EEException(exception); + return result; + } +} diff --git a/src/coreclr/tools/superpmi/managed/shim/Shim.props b/src/coreclr/tools/superpmi/managed/shim/Shim.props new file mode 100644 index 00000000000000..91423dba374e57 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/shim/Shim.props @@ -0,0 +1,27 @@ + + + + Library + Shared + true + true + $(PortableOS)-$(TargetArchitecture) + $(RuntimeBinDir) + + true + true + + + + + + + + + + + + + + + diff --git a/src/coreclr/tools/superpmi/managed/shim/ShimEnvironment.cs b/src/coreclr/tools/superpmi/managed/shim/ShimEnvironment.cs new file mode 100644 index 00000000000000..871acaaf1b15fe --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/shim/ShimEnvironment.cs @@ -0,0 +1,119 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.IO; +using System.Runtime.InteropServices; +using System.Security.Cryptography; +using System.Text; + +namespace SuperPmi.Shim; + +// The settings that the shims read from the environment, and the real JIT that they load. +internal static partial class ShimEnvironment +{ + private const int MAX_PATH = 260; + + private static readonly string s_defaultRealJitName = + OperatingSystem.IsWindows() ? "clrjit2.dll" : OperatingSystem.IsMacOS() ? "libclrjit2.dylib" : "libclrjit2.so"; + + private static string s_homeDirectory; + private static string s_defaultRealJitPath; + + public static string RealJitPath { get; private set; } + + public static string LogPath { get; private set; } + + public static IntPtr RealJit { get; private set; } + + private static string GetEnvWithDefault(string name, string defaultValue) => Environment.GetEnvironmentVariable(name) ?? defaultValue; + + public static void SetDefaultPaths() + { + s_homeDirectory ??= GetEnvWithDefault("HOME", "."); + s_defaultRealJitPath ??= s_homeDirectory + Path.DirectorySeparatorChar + s_defaultRealJitName; + } + + public static void SetLibName() => RealJitPath ??= GetEnvWithDefault("SuperPMIShimPath", s_defaultRealJitPath); + + public static void SetLogPath() => LogPath ??= GetEnvWithDefault("SuperPMIShimLogPath", s_homeDirectory); + + public static bool LoadRealJitLib() + { + if (RealJit != 0) + return true; + + if (string.IsNullOrEmpty(RealJitPath)) + { + Logger.LogError("LoadRealJitLib - No real jit path"); + return false; + } + + try + { + RealJit = NativeLibrary.Load(RealJitPath); + } + catch (Exception e) when (e is DllNotFoundException or BadImageFormatException) + { + Logger.LogError($"LoadRealJitLib - {(OperatingSystem.IsWindows() ? "LoadLibrary" : "dlopen")} failed to load '{RealJitPath}' ({e.Message})"); + return false; + } + return true; + } + + public static IntPtr GetRealJitExport(string name) => NativeLibrary.TryGetExport(RealJit, name, out IntPtr address) ? address : 0; + + // A file name in 'folderPath' from 'fileName' (made a legal file name) and a random suffix, for uniqueness. + public static string GetResultFileName(string folderPath, string fileName, string extension) + { + string suffix = RandomNumberGenerator.GetHexString(8, lowercase: true) + extension; + + // Limit the total file name length to MAX_PATH - 50. + int usableLength = MAX_PATH - 50 - Encoding.UTF8.GetByteCount(folderPath) - suffix.Length; + if (usableLength < 0) + { + Logger.LogError($"GetResultFileName - folder path '{folderPath}' length + minimal file name exceeds limit {MAX_PATH - 50}"); + return ""; + } + + byte[] copy = Encoding.UTF8.GetBytes(fileName); + if (copy.Length > usableLength) + Array.Resize(ref copy, usableLength); + + ReplaceIllegalCharacters(copy); + return folderPath + Path.DirectorySeparatorChar + Encoding.ASCII.GetString(copy) + suffix; + } + + // Makes the bytes textual ASCII characters, without the illegal or annoying ones for file names. + private static void ReplaceIllegalCharacters(byte[] fileName) + { + for (int i = 0; i < fileName.Length; i++) + { + byte ch = fileName[i]; + if (ch <= 32 || ch >= 127 || "()=<>:/\\|?!*.,".Contains((char)ch)) + fileName[i] = (byte)'_'; + else if (ch == '"') + fileName[i] = (byte)' '; + } + } + + // The command line as the process got it: Environment.CommandLine is rebuilt from the arguments. + [LibraryImport("kernel32.dll")] + private static partial IntPtr GetCommandLineW(); + + public static string GetProcessCommandLine() + { + if (OperatingSystem.IsWindows()) + return Marshal.PtrToStringUni(GetCommandLineW()); + + try + { + // The arguments are separated by NULs, which are converted to spaces. + return File.ReadAllText("/proc/self/cmdline").TrimEnd('\0').Replace('\0', ' '); + } + catch (Exception e) when (e is IOException or UnauthorizedAccessException) + { + return ""; + } + } +} diff --git a/src/coreclr/tools/superpmi/managed/shim/ShimInterop.cs b/src/coreclr/tools/superpmi/managed/shim/ShimInterop.cs new file mode 100644 index 00000000000000..fdac9dca024759 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/shim/ShimInterop.cs @@ -0,0 +1,131 @@ +// 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.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; +using Internal.JitInterface; + +namespace SuperPmi.Shim; + +// The native side of the shims (superpmi/jitinterface/shim.cpp), statically linked into each of them. +internal static unsafe partial class ShimInterop +{ + private const string Library = "superpmi-shim-jitinterface"; + + public static readonly IntPtr Forwarders = Shim_GetForwarders(); + + [StructLayout(LayoutKind.Sequential)] + public struct JitCompilerCallbacks + { + public delegate* unmanaged compileMethod; + public delegate* unmanaged ProcessShutdownWork; + public delegate* unmanaged getVersionIdentifier; + public delegate* unmanaged setTargetOS; + } + + [StructLayout(LayoutKind.Sequential)] + public struct JitHostCallbacks + { + public delegate* unmanaged getIntConfigValue; + public delegate* unmanaged getStringConfigValue; + public delegate* unmanaged freeStringConfigValue; + } + + [LibraryImport(Library)] + private static partial IntPtr Shim_GetForwarders(); + + [LibraryImport(Library)] + public static partial void Shim_SetUnloadCallback(delegate* unmanaged callback); + + [LibraryImport(Library)] + public static partial IntPtr Shim_AllocError(uint code); + + [LibraryImport(Library)] + public static partial uint Shim_GetExceptionCode(IntPtr exception); + + [LibraryImport(Library)] + public static partial void Shim_FreeException(IntPtr exception); + + [LibraryImport(Library)] + public static partial IntPtr Shim_CreateJitCompiler(IntPtr thisHandle, JitCompilerCallbacks* callbacks); + + [LibraryImport(Library)] + public static partial IntPtr Shim_CreateJitHost(IntPtr original, IntPtr thisHandle, JitHostCallbacks* callbacks); + + [LibraryImport(Library)] + public static partial CorJitResult Shim_CompileMethod(IntPtr* exception, IntPtr jit, IntPtr comp, CORINFO_METHOD_INFO* info, + uint flags, byte** nativeEntry, uint* nativeSizeOfCode); + + [LibraryImport(Library)] + public static partial CorJitResult Shim_CompileMethodWithJitInfo(IntPtr* exception, IntPtr jit, IntPtr thisHandle, IntPtr callbacks, + CORINFO_METHOD_INFO* info, uint flags, byte** nativeEntry, uint* nativeSizeOfCode); + + [LibraryImport(Library)] + public static partial void Shim_ProcessShutdownWork(IntPtr jit, IntPtr info); + + [LibraryImport(Library)] + public static partial void Shim_GetVersionIdentifier(IntPtr jit, Guid* versionIdentifier); + + [LibraryImport(Library)] + public static partial void Shim_SetTargetOS(IntPtr jit, CORINFO_OS os); + + [LibraryImport(Library)] + public static partial byte Shim_RunWithSPMIErrorTrap(IntPtr* exception, void* function, void* parameter, uint errorCode); + + [LibraryImport(Library)] + public static partial int Shim_HostGetIntConfigValue(IntPtr host, byte* name, int defaultValue); + + [LibraryImport(Library)] + public static partial byte* Shim_HostGetStringConfigValue(IntPtr host, byte* name); + + [LibraryImport(Library)] + public static partial void Shim_HostFreeStringConfigValue(IntPtr host, byte* value); + + // Allocated once, for the lifetime of the process. + public static T* Allocate(T value) where T : unmanaged + { + var p = (T*)NativeMemory.Alloc((nuint)sizeof(T)); + *p = value; + return p; + } + + // Compiles the method with the real JIT, rethrowing what escapes it. + public static CorJitResult CompileMethod(IntPtr jit, IntPtr comp, CORINFO_METHOD_INFO* info, uint flags, byte** nativeEntry, uint* nativeSizeOfCode) + { + IntPtr exception = 0; + CorJitResult result = Shim_CompileMethod(&exception, jit, comp, info, flags, nativeEntry, nativeSizeOfCode); + if (exception != 0) + throw new EEException(exception); + return result; + } + + // The native exception to rethrow through the JIT (and to the EE) for an exception of the managed shim. + public static IntPtr ToNativeException(Exception ex) => ex switch + { + EEException e => e.NativeException, + SpmiException e => Shim_AllocError(e.Code), + _ => Fail(ex), + }; + + // An unexpected failure of the shim, which ends the process as an unhandled exception would. + [DoesNotReturn] + private static IntPtr Fail(Exception ex) + { + Logger.Flush(); + Environment.FailFast($"SuperPMI shim failure: {ex}"); + return 0; + } +} + +// An exception that the EE (or the JIT) threw, captured by the native shim to be rethrown where the call returns to +// the EE; or an error of the shim, such as a method context error, that escaped the JIT. +internal sealed class EEException : Exception +{ + public EEException(IntPtr nativeException) => NativeException = nativeException; + + public IntPtr NativeException { get; } + + // The exception code that the method contexts record. + public uint Code => ShimInterop.Shim_GetExceptionCode(NativeException); +} diff --git a/src/coreclr/tools/superpmi/managed/superpmi-shim-collector/Collector.cs b/src/coreclr/tools/superpmi/managed/superpmi-shim-collector/Collector.cs new file mode 100644 index 00000000000000..6d3e411b808435 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/superpmi-shim-collector/Collector.cs @@ -0,0 +1,362 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; +using Internal.JitInterface; + +namespace SuperPmi.Shim; + +// superpmi-shim-collector: a JIT that compiles with the real JIT (SuperPMIShimPath), and records the JIT-EE +// interface calls of each compilation as a method context, appended to a file in SuperPMIShimLogPath. +internal static unsafe class Collector +{ + private static string s_collectionFilter; + + static Collector() + { + string logFilePath = Environment.GetEnvironmentVariable("SuperPMIShimLogFilePath"); + if (logFilePath != null) + Logger.OpenLogFile(logFilePath); + } + + // The global context records the JIT's configuration queries, which are copied to each method context. + public static MethodContext GlobalContext { get; private set; } + + public static string CollectionFilter => s_collectionFilter; + + private static void SetCollectionFilter() + { + s_collectionFilter = Environment.GetEnvironmentVariable("SuperPMIShimFilter"); + if (s_collectionFilter != null) + Logger.Error.WriteLine($"*** SPMI filter '{s_collectionFilter}'"); + } + + [UnmanagedCallersOnly(EntryPoint = "jitStartup")] + private static void jitStartup(IntPtr host) + { + ShimEnvironment.SetDefaultPaths(); + ShimEnvironment.SetLibName(); + SetCollectionFilter(); + + if (!ShimEnvironment.LoadRealJitLib()) + return; + + var realJitStartup = (delegate* unmanaged)ShimEnvironment.GetRealJitExport("jitStartup"); + if (realJitStartup == null) + { + // This portion of the interface is not used by the JIT under test. + return; + } + + GlobalContext = new MethodContext(); + realJitStartup(CollectorJitHost.Create(host)); + } + + [UnmanagedCallersOnly(EntryPoint = "getJit")] + private static IntPtr getJit() + { + ShimEnvironment.SetDefaultPaths(); + ShimEnvironment.SetLibName(); + ShimEnvironment.SetLogPath(); + string dataFileName = ShimEnvironment.GetResultFileName(ShimEnvironment.LogPath, ShimEnvironment.GetProcessCommandLine(), ".mc"); + + if (!ShimEnvironment.LoadRealJitLib()) + return 0; + + var realGetJit = (delegate* unmanaged)ShimEnvironment.GetRealJitExport("getJit"); + if (realGetJit == null) + { + Logger.LogError("getJit() - GetProcAddress 'getJit' failed (0x0000007f)"); + return 0; + } + + IntPtr original = realGetJit(); + if (original == 0) + { + Logger.LogError("getJit() - pngetJit gave us null"); + return 0; + } + + return new CollectorJitCompiler(original, dataFileName).Native; + } +} + +// The ICorJitCompiler that the runtime calls, which records each compilation into a method context. +internal sealed unsafe class CollectorJitCompiler +{ + private static readonly ShimInterop.JitCompilerCallbacks* s_callbacks = ShimInterop.Allocate(new ShimInterop.JitCompilerCallbacks + { + compileMethod = &CompileMethodCallback, + ProcessShutdownWork = &ProcessShutdownWorkCallback, + getVersionIdentifier = &GetVersionIdentifierCallback, + setTargetOS = &SetTargetOSCallback, + }); + + private readonly IntPtr _original; + private readonly FileStream _file; + private CORINFO_OS _currentOs = OperatingSystem.IsWindows() ? CORINFO_OS.CORINFO_WINNT : + OperatingSystem.IsMacOS() ? CORINFO_OS.CORINFO_APPLE : CORINFO_OS.CORINFO_UNIX; + + public CollectorJitCompiler(IntPtr original, string dataFileName) + { + _original = original; + try + { + _file = new FileStream(dataFileName, FileMode.Create, FileAccess.ReadWrite, FileShare.None, 1, FileOptions.SequentialScan); + } + catch (Exception e) when (e is IOException or UnauthorizedAccessException or ArgumentException) + { + Logger.LogError($"Couldn't open file '{dataFileName}': error {ErrorHandling.LastError(e)}"); + } + + // The JIT is used for the lifetime of the process. + Native = ShimInterop.Shim_CreateJitCompiler(GCHandle.ToIntPtr(GCHandle.Alloc(this)), s_callbacks); + } + + public IntPtr Native { get; } + + private static CollectorJitCompiler Get(IntPtr thisHandle) => (CollectorJitCompiler)GCHandle.FromIntPtr(thisHandle).Target; + + [UnmanagedCallersOnly] + private static CorJitResult CompileMethodCallback(IntPtr thisHandle, IntPtr* ppException, IntPtr comp, CORINFO_METHOD_INFO* info, + uint flags, byte** nativeEntry, uint* nativeSizeOfCode) + { + try + { + return Get(thisHandle).compileMethod(comp, info, flags, nativeEntry, nativeSizeOfCode); + } + catch (Exception ex) + { + *ppException = ShimInterop.ToNativeException(ex); + return CorJitResult.CORJIT_INTERNALERROR; + } + } + + [UnmanagedCallersOnly] + private static void ProcessShutdownWorkCallback(IntPtr thisHandle, IntPtr info) + => ShimInterop.Shim_ProcessShutdownWork(Get(thisHandle)._original, info); + + [UnmanagedCallersOnly] + private static void GetVersionIdentifierCallback(IntPtr thisHandle, Guid* versionIdentifier) + => ShimInterop.Shim_GetVersionIdentifier(Get(thisHandle)._original, versionIdentifier); + + [UnmanagedCallersOnly] + private static void SetTargetOSCallback(IntPtr thisHandle, CORINFO_OS os) + { + CollectorJitCompiler compiler = Get(thisHandle); + compiler._currentOs = os; + ShimInterop.Shim_SetTargetOS(compiler._original, os); + } + + private CorJitResult compileMethod(IntPtr comp, CORINFO_METHOD_INFO* info, uint flags, byte** nativeEntry, uint* nativeSizeOfCode) + { + var original = new OriginalJitInfo(comp, ShimInterop.Forwarders); + + // See if we are filtering the collection (currently by simple substring match). + if (Collector.CollectionFilter != null) + { + byte* className = null; + byte* methodName = original.getMethodNameFromMetadata(info->ftn, &className, null, null, 0); + if (!Contains(methodName, Collector.CollectionFilter) && !Contains(className, Collector.CollectionFilter)) + return ShimInterop.CompileMethod(_original, comp, info, flags, nativeEntry, nativeSizeOfCode); + } + + var mc = new MethodContext(); + var ourJitInfo = new CorInfoImpl(this, original, mc); + + mc.cr.recProcessName(ShimEnvironment.GetProcessCommandLine()); + mc.recCompileMethod(info, flags, _currentOs); + ourJitInfo.RecordExtraData(info); + + // Record data from the global context, if any. + if (Collector.GlobalContext != null) + mc.recGlobalContext(Collector.GlobalContext); + + *nativeEntry = null; + *nativeSizeOfCode = 0; + + CorJitResult result = CorJitResult.CORJIT_INTERNALERROR; + IntPtr exception = 0; + try + { + result = ourJitInfo.CompileMethod(_original, info, flags, nativeEntry, nativeSizeOfCode, out exception); + } + finally + { + if (!ourJitInfo.SavedCollectionEarly) + finalizeAndCommitCollection(mc, result, *nativeEntry, *nativeSizeOfCode); + } + + if (exception != 0) + throw new EEException(exception); + return result; + } + + public void finalizeAndCommitCollection(MethodContext mc, CorJitResult result, byte* nativeEntry, uint nativeSizeOfCode) + { + mc.cr.recCompileMethod(nativeEntry, nativeSizeOfCode, result); + + if (result == CorJitResult.CORJIT_OK) + { + mc.cr.recAllocMemCapture(); + mc.cr.recAllocGCInfoCapture(); + } + + if (_file != null) + { + // The JIT compiles methods concurrently; each method context is written at once. + lock (_file) + { + mc.saveToFile(_file); + } + } + } + + private static bool Contains(byte* s, string value) + => s != null && MemoryMarshal.CreateReadOnlySpanFromNullTerminated(s).IndexOf(Encoding.UTF8.GetBytes(value)) >= 0; +} + +// The ICorJitHost that the real JIT gets: its configuration queries are recorded in the global method context. +// +// This works because the JIT eagerly asks for all config values once, in jitStartup. If the JIT were to ask for +// config values later, during the compilations, they would get recorded in the global context too, and copied +// to all the later method contexts, which would be incorrect. +internal static unsafe class CollectorJitHost +{ + private static readonly ShimInterop.JitHostCallbacks* s_callbacks = ShimInterop.Allocate(new ShimInterop.JitHostCallbacks + { + getIntConfigValue = &GetIntConfigValue, + getStringConfigValue = &GetStringConfigValue, + freeStringConfigValue = &FreeStringConfigValue, + }); + + private static IntPtr s_original; + + // The DOTNET variables that aren't recorded: those of file paths, and those it doesn't make sense to replay with. + private static readonly string[] s_ignoredVars = + [ + "EnableExtraSuperPmiQueries", + "JitDisasm", + "JitDump", + "JitDisasmWithAlignmentBoundaries", + "JitDumpASCII", + "JitHashBreak", + "JitHashDump", + "JitHashHalt", + "JitOrder", + "JitPrintInlinedMethods", + "JitPrintDevirtualizedMethods", + "JitBreak", + "JitDebugBreak", + "JitDisasmAssemblies", + "JitDisasmWithGC", + "JitDisasmWithDebugInfo", + "JitDisasmSpilled", + "JitDumpTier0", + "JitDumpAtOSROffset", + "JitDumpInlinePhases", + "JitEHDump", + "JitExclude", + "JitGCDump", + "JitDebugDump", + "JitHalt", + "JitImportBreak", + "JitInclude", + "JitLateDisasm", + "JitUnwindDump", + "JitDumpFg", + "JitDumpFgDir", + "JitDumpFgPhase", + "JitDumpFgPrePhase", + "JitDumpFgDot", + "JitDumpFgEH", + "JitDumpFgLoops", + "JitDumpFgConstrained", + "JitDumpFgBlockID", + "JitDumpFgBlockFlags", + "JitDumpFgLoopFlags", + "JitDumpFgBlockOrder", + "JITLateDisasmTo", + "JitDisasmSummary", + "JitStdOutFile", + "WriteRichDebugInfoFile", + "JitFuncInfoLogFile", + "JitTimeLogCsv", + "JitMeasureNowayAssertFile", + "JitInlineDumpData", + "JitInlineDumpXml", + "JitInlineDumpXmlFile", + "JitInlinePolicyDumpXml", + "JitInlineReplayFile", + "JitFunctionFile", + "JitRawHexCode", + "JitRawHexCodeFile", + ]; + + public static IntPtr Create(IntPtr original) + { + s_original = original; + return ShimInterop.Shim_CreateJitHost(original, 0, s_callbacks); + } + + private static bool RecordVariable(byte* key) + { + string name = Marshal.PtrToStringUTF8((IntPtr)key); + foreach (string ignoredVar in s_ignoredVars) + { + if (string.Equals(name, ignoredVar, StringComparison.OrdinalIgnoreCase)) + return false; + } + return true; + } + + private static bool IsKey(byte* key, ReadOnlySpan name) => MemoryMarshal.CreateReadOnlySpanFromNullTerminated(key).SequenceEqual(name); + + [UnmanagedCallersOnly] + private static int GetIntConfigValue(IntPtr thisHandle, byte* key, int defaultValue) + { + // Don't collect these pseudo-variables, and don't even record that they were asked for: superpmi + // answers them itself. + if (IsKey(key, "SuperPMIMethodContextNumber"u8) || IsKey(key, "JitReportMetrics"u8)) + return defaultValue; + + MethodContext mc = Collector.GlobalContext; + lock (mc) + { + mc.cr.AddCall("getIntConfigValue"); + int result = ShimInterop.Shim_HostGetIntConfigValue(s_original, key, defaultValue); + + // The JIT eagerly asks about every config value. If we store all these queries, it takes almost half the + // MC file space. So only store the non-default answers. + if (RecordVariable(key) && result != defaultValue) + mc.recGetIntConfigValue(key, defaultValue, result); + return result; + } + } + + [UnmanagedCallersOnly] + private static byte* GetStringConfigValue(IntPtr thisHandle, byte* key) + { + MethodContext mc = Collector.GlobalContext; + lock (mc) + { + mc.cr.AddCall("getStringConfigValue"); + byte* result = ShimInterop.Shim_HostGetStringConfigValue(s_original, key); + + // Don't store null returns, which is the default. + if (RecordVariable(key) && result != null) + mc.recGetStringConfigValue(key, result); + return result; + } + } + + [UnmanagedCallersOnly] + private static void FreeStringConfigValue(IntPtr thisHandle, byte* value) + { + Collector.GlobalContext.cr.AddCall("freeStringConfigValue"); + ShimInterop.Shim_HostFreeStringConfigValue(s_original, value); + } +} diff --git a/src/coreclr/tools/superpmi/managed/superpmi-shim-collector/CorInfoImpl.Collector.cs b/src/coreclr/tools/superpmi/managed/superpmi-shim-collector/CorInfoImpl.Collector.cs new file mode 100644 index 00000000000000..8ed697cacb0095 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/superpmi-shim-collector/CorInfoImpl.Collector.cs @@ -0,0 +1,1635 @@ +// 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 Internal.Pgo; +using SuperPmi; +using SuperPmi.Shim; + +namespace Internal.JitInterface; + +// The JIT-EE interface for collection: forwards the JIT's calls to the EE, and records them (with what the EE +// answered) into the method context. +internal sealed unsafe partial class CorInfoImpl +{ + private readonly CollectorJitCompiler m_compiler; + private readonly OriginalJitInfo _original; + private readonly MethodContext mc; + private bool m_savedCollectionEarly; + + public CorInfoImpl(CollectorJitCompiler compiler, OriginalJitInfo original, MethodContext mc) + { + m_compiler = compiler; + _original = original; + this.mc = mc; + } + + private CompileResult cr => mc.cr; + + public bool SavedCollectionEarly => m_savedCollectionEarly; + + private static CorInfoImpl GetThis(IntPtr thisHandle) => Unsafe.Read((void*)thisHandle); + + private IntPtr AllocException(Exception ex) => ShimInterop.ToNativeException(ex); + + private void AddCall(string name) => cr.AddCall(name); + + private static T* P(ref T value) where T : unmanaged => (T*)Unsafe.AsPointer(ref value); + + // The by-ref parameters of pointer types, which refer to the JIT's memory. + private static void** P(ref void* value) + { + fixed (void** p = &value) + return p; + } + + private static uint** P(ref uint* value) + { + fixed (uint** p = &value) + return p; + } + + private static PgoInstrumentationSchema** P(ref PgoInstrumentationSchema* value) + { + fixed (PgoInstrumentationSchema** p = &value) + return p; + } + + private static CORINFO_JUST_MY_CODE_HANDLE_** P(ref CORINFO_JUST_MY_CODE_HANDLE_* value) + { + fixed (CORINFO_JUST_MY_CODE_HANDLE_** p = &value) + return p; + } + + // An exception filter that records the code of the exception and lets it continue, so that the call is + // recorded with it (and replayed by throwing). + private static bool CaptureExceptionCode(Exception e, ref uint exceptionCode) + { + exceptionCode = e switch + { + EEException ee => ee.Code, + SpmiException se => se.Code, + _ => 1, + }; + return false; + } + + // Compiles the method with the real JIT through this JIT-EE interface. What escaped the JIT is returned in 'exception'. + public CorJitResult CompileMethod(IntPtr jit, CORINFO_METHOD_INFO* info, uint flags, byte** nativeEntry, uint* nativeSizeOfCode, out IntPtr exception) + { + CorInfoImpl _this = this; + IntPtr captured = 0; + CorJitResult result = ShimInterop.Shim_CompileMethodWithJitInfo(&captured, jit, (IntPtr)Unsafe.AsPointer(ref _this), + GetUnmanagedCallbacks(), info, flags, nativeEntry, nativeSizeOfCode); + exception = captured; + return result; + } + + // Forces some extra data into the method context ("fat" method contexts), which ildump needs. + public void RecordExtraData(CORINFO_METHOD_INFO* info) + { + getBuiltinClass(CorInfoClassId.CLASSID_SYSTEM_OBJECT); + getBuiltinClass(CorInfoClassId.CLASSID_TYPED_BYREF); + getBuiltinClass(CorInfoClassId.CLASSID_TYPE_HANDLE); + getBuiltinClass(CorInfoClassId.CLASSID_FIELD_HANDLE); + getBuiltinClass(CorInfoClassId.CLASSID_METHOD_HANDLE); + getBuiltinClass(CorInfoClassId.CLASSID_STRING); + getBuiltinClass(CorInfoClassId.CLASSID_RUNTIME_TYPE); + + CORINFO_CLASS_STRUCT_* ourClass = getMethodClass(info->ftn); + getClassAttribs(ourClass); + isValueClass(ourClass); + asCorInfoType(ourClass); + + PrintInFull((buffer, bufferSize, requiredBufferSize) => printClassName(ourClass, buffer, bufferSize, requiredBufferSize)); + PrintInFull((buffer, bufferSize, requiredBufferSize) => printMethodName(info->ftn, buffer, bufferSize, requiredBufferSize)); + } + + private delegate nuint Printer(byte* buffer, nuint bufferSize, nuint* pRequiredBufferSize); + + private static void PrintInFull(Printer print) + { + byte* buffer = stackalloc byte[256]; + nuint requiredSize; + print(buffer, 256, &requiredSize); + + if (requiredSize > 256) + { + fixed (byte* fullBuffer = new byte[requiredSize]) + print(fullBuffer, requiredSize, null); + } + } + + private bool getMethodInfo(CORINFO_METHOD_STRUCT_* ftn, CORINFO_METHOD_INFO* info, CORINFO_CONTEXT_STRUCT* context) + { + bool temp = false; + uint exceptionCode = 0; + try + { + AddCall("getMethodInfo"); + temp = _original.getMethodInfo(ftn, info, context); + } + catch (Exception e) when (CaptureExceptionCode(e, ref exceptionCode)) + { + } + finally + { + mc.recGetMethodInfo(ftn, info, context, temp, exceptionCode); + } + return temp; + } + + private CorInfoInline canInline(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* calleeHnd) + { + CorInfoInline temp = CorInfoInline.INLINE_NEVER; + uint exceptionCode = 0; + try + { + AddCall("canInline"); + temp = _original.canInline(callerHnd, calleeHnd); + } + catch (Exception e) when (CaptureExceptionCode(e, ref exceptionCode)) + { + } + finally + { + mc.recCanInline(callerHnd, calleeHnd, temp, exceptionCode); + } + return temp; + } + + private void resolveToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken) + { + uint exceptionCode = 0; + try + { + AddCall("resolveToken"); + _original.resolveToken(ref pResolvedToken); + } + catch (Exception e) when (CaptureExceptionCode(e, ref exceptionCode)) + { + } + finally + { + mc.recResolveToken(P(ref pResolvedToken), exceptionCode); + } + } + + private bool canCast(CORINFO_CLASS_STRUCT_* child, CORINFO_CLASS_STRUCT_* parent) + { + AddCall("canCast"); + bool temp = _original.canCast(child, parent); + mc.recCanCast(child, parent, temp); + return temp; + } + + private uint getClassGClayout(CORINFO_CLASS_STRUCT_* cls, byte* gcPtrs) + { + AddCall("getClassGClayout"); + uint temp = _original.getClassGClayout(cls, gcPtrs); + + // Use the target's pointer size, not the host's, so cross-target collections + // (e.g., wasm32 on an x64 host) record the full GC-layout buffer. + uint targetPointerSize = (CorInfoArch)_original.getExpectedTargetArchitecture() switch + { + CorInfoArch.CORINFO_ARCH_X86 or CorInfoArch.CORINFO_ARCH_ARM or CorInfoArch.CORINFO_ARCH_WASM32 => 4, + _ => 8, + }; + + uint len = isValueClass(cls) + ? (getClassSize(cls) + targetPointerSize - 1) / targetPointerSize + : (getHeapClassSize(cls) + targetPointerSize - 1) / targetPointerSize; + mc.recGetClassGClayout(cls, gcPtrs, len, temp); + return temp; + } + + private CorInfoHelpFunc getNewHelper(CORINFO_CLASS_STRUCT_* classHandle, ref bool pHasSideEffects) + { + CorInfoHelpFunc result = CorInfoHelpFunc.CORINFO_HELP_UNDEF; + bool hasSideEffects = false; + uint exceptionCode = 0; + try + { + AddCall("getNewHelper"); + result = _original.getNewHelper(classHandle, ref hasSideEffects); + } + catch (Exception e) when (CaptureExceptionCode(e, ref exceptionCode)) + { + } + finally + { + mc.recGetNewHelper(classHandle, hasSideEffects, result, exceptionCode); + } + + if (!Unsafe.IsNullRef(ref pHasSideEffects)) + pHasSideEffects = hasSideEffects; + + return result; + } + + private TypeCompareState isEnum(CORINFO_CLASS_STRUCT_* cls, CORINFO_CLASS_STRUCT_** underlyingType) + { + AddCall("isEnum"); + CORINFO_CLASS_STRUCT_* tempUnderlyingType = null; + TypeCompareState temp = _original.isEnum(cls, &tempUnderlyingType); + mc.recIsEnum(cls, tempUnderlyingType, temp); + if (underlyingType != null) + *underlyingType = tempUnderlyingType; + return temp; + } + + private CorInfoTypeWithMod getArgType(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_STRUCT_* args, CORINFO_CLASS_STRUCT_** vcTypeRet) + { + CorInfoTypeWithMod temp = (CorInfoTypeWithMod)CorInfoType.CORINFO_TYPE_UNDEF; + uint exceptionCode = 0; + try + { + AddCall("getArgType"); + temp = _original.getArgType(sig, args, vcTypeRet); + + // For a "fat" method context. + getArgClass(sig, args); + } + catch (Exception e) when (CaptureExceptionCode(e, ref exceptionCode)) + { + } + finally + { + mc.recGetArgType(sig, args, vcTypeRet, temp, exceptionCode); + } + return temp; + } + + private int getExactClasses(CORINFO_CLASS_STRUCT_* baseType, int maxExactClasses, CORINFO_CLASS_STRUCT_** exactClsRet) + { + AddCall("getExactClasses"); + int result = _original.getExactClasses(baseType, maxExactClasses, exactClsRet); + mc.recGetExactClasses(baseType, maxExactClasses, exactClsRet, result); + return result; + } + + private CORINFO_CLASS_STRUCT_* getArgClass(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_STRUCT_* args) + { + CORINFO_CLASS_STRUCT_* temp = null; + uint exceptionCode = 0; + try + { + AddCall("getArgClass"); + temp = _original.getArgClass(sig, args); + } + catch (Exception e) when (CaptureExceptionCode(e, ref exceptionCode)) + { + } + finally + { + mc.recGetArgClass(sig, args, temp, exceptionCode); + } + return temp; + } + + private void getHelperFtn(CorInfoHelpFunc ftnNum, CORINFO_CONST_LOOKUP* pNativeEntrypoint, CORINFO_METHOD_STRUCT_** pMethod) + { + AddCall("getHelperFtn"); + CORINFO_CONST_LOOKUP localNativeEntrypoint; + CORINFO_METHOD_STRUCT_* localMethodHandle; + _original.getHelperFtn(ftnNum, &localNativeEntrypoint, &localMethodHandle); + mc.recGetHelperFtn(ftnNum, localNativeEntrypoint, localMethodHandle); + if (pNativeEntrypoint != null) + *pNativeEntrypoint = localNativeEntrypoint; + if (pMethod != null) + *pMethod = localMethodHandle; + } + + private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, + CORINFO_CALLINFO_FLAGS flags, CORINFO_CALL_INFO* pResult) + { + uint exceptionCode = 0; + try + { + AddCall("getCallInfo"); + _original.getCallInfo(ref pResolvedToken, pConstrainedResolvedToken, callerHandle, flags, pResult); + } + catch (Exception e) when (CaptureExceptionCode(e, ref exceptionCode)) + { + } + finally + { + mc.recGetCallInfo(P(ref pResolvedToken), pConstrainedResolvedToken, callerHandle, flags, pResult, exceptionCode); + } + } + + private bool getTailCallHelpers(ref CORINFO_RESOLVED_TOKEN callToken, CORINFO_SIG_INFO* sig, CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, ref CORINFO_TAILCALL_HELPERS pResult) + { + AddCall("getTailCallHelpers"); + bool result = _original.getTailCallHelpers(ref callToken, sig, flags, ref pResult); + mc.recGetTailCallHelpers(P(ref callToken), sig, flags, result ? P(ref pResult) : null); + return result; + } + + private void updateEntryPointForTailCall(ref CORINFO_CONST_LOOKUP entryPoint) + { + AddCall("updateEntryPointForTailCall"); + CORINFO_CONST_LOOKUP origEntryPoint = entryPoint; + _original.updateEntryPointForTailCall(ref entryPoint); + mc.recUpdateEntryPointForTailCall(origEntryPoint, entryPoint); + } + + // Allocates memory that is handed to the EE; not recorded. + private void* allocateArray(nuint cBytes) + { + AddCall("allocateArray"); + return _original.allocateArray(cBytes); + } + + private void freeArray(void* array) + { + AddCall("freeArray"); + _original.freeArray(array); + } + + private void recordWasmManagedCallSig(CORINFO_SIG_INFO* callSig) + { + AddCall("recordWasmManagedCallSig"); + _original.recordWasmManagedCallSig(callSig); + // No-op in the VM, nothing to record for replay. + } + + // The results of the error traps aren't recorded: when the call is replayed, its result depends on whether + // 'function' calls something that throws at replay time rather than at recording time. + private bool runWithErrorTrap(void* function, void* parameter) + { + AddCall("runWithErrorTrap"); + return _original.runWithErrorTrap(function, parameter); + } + + // The error trap for the method context errors of the shim itself. + private bool runWithSPMIErrorTrap(void* function, void* parameter) + { + IntPtr exception = 0; + bool result = ShimInterop.Shim_RunWithSPMIErrorTrap(&exception, function, parameter, ExceptionCodes.MC) != 0; + if (exception != 0) + throw new EEException(exception); + return result; + } + + private int doAssert(byte* szFile, int iLine, byte* szExpr) + { + AddCall("doAssert"); + + m_compiler.finalizeAndCommitCollection(mc, CorJitResult.CORJIT_INTERNALERROR, null, 0); + // The following assert may not always fail fast, so make sure we do not + // save the collection twice if it throws an unwindable exception. + m_savedCollectionEarly = true; + + return _original.doAssert(szFile, iLine, szExpr); + } + + private HRESULT getPgoInstrumentationResults(CORINFO_METHOD_STRUCT_* ftnHnd, ref PgoInstrumentationSchema* pSchema, ref uint pCountSchemaItems, + byte** pInstrumentationData, ref PgoSource pPgoSource, ref bool pDynamicPgo) + { + AddCall("getPgoInstrumentationResults"); + HRESULT temp = _original.getPgoInstrumentationResults(ftnHnd, ref pSchema, ref pCountSchemaItems, pInstrumentationData, ref pPgoSource, ref pDynamicPgo); + mc.recGetPgoInstrumentationResults(ftnHnd, P(ref pSchema), P(ref pCountSchemaItems), pInstrumentationData, P(ref pPgoSource), P(ref pDynamicPgo), (int)temp); + return temp; + } + + private bool isIntrinsic(CORINFO_METHOD_STRUCT_* ftn) + { + AddCall("isIntrinsic"); + var temp = _original.isIntrinsic(ftn); + mc.recIsIntrinsic(ftn, temp); + return temp; + } + + private bool canValueClassInstancePointerEscape(CORINFO_METHOD_STRUCT_* ftn) + { + AddCall("canValueClassInstancePointerEscape"); + var temp = _original.canValueClassInstancePointerEscape(ftn); + mc.recCanValueClassInstancePointerEscape(ftn, temp); + return temp; + } + + private bool notifyMethodInfoUsage(CORINFO_METHOD_STRUCT_* ftn) + { + AddCall("notifyMethodInfoUsage"); + var temp = _original.notifyMethodInfoUsage(ftn); + mc.recNotifyMethodInfoUsage(ftn, temp); + return temp; + } + + private uint getMethodAttribs(CORINFO_METHOD_STRUCT_* ftn) + { + AddCall("getMethodAttribs"); + var temp = _original.getMethodAttribs(ftn); + mc.recGetMethodAttribs(ftn, temp); + return temp; + } + + private void setMethodAttribs(CORINFO_METHOD_STRUCT_* ftn, CorInfoMethodRuntimeFlags attribs) + { + AddCall("setMethodAttribs"); + _original.setMethodAttribs(ftn, attribs); + cr.recSetMethodAttribs(ftn, attribs); + } + + private void getMethodSig(CORINFO_METHOD_STRUCT_* ftn, CORINFO_SIG_INFO* sig, CORINFO_CLASS_STRUCT_* memberParent) + { + AddCall("getMethodSig"); + _original.getMethodSig(ftn, sig, memberParent); + mc.recGetMethodSig(ftn, sig, memberParent); + } + + private bool haveSameMethodDefinition(CORINFO_METHOD_STRUCT_* methHnd1, CORINFO_METHOD_STRUCT_* methHnd2) + { + var result = _original.haveSameMethodDefinition(methHnd1, methHnd2); + mc.recHaveSameMethodDefinition(methHnd1, methHnd2, result); + return result; + } + + private CORINFO_CLASS_STRUCT_* getTypeDefinition(CORINFO_CLASS_STRUCT_* type) + { + var result = _original.getTypeDefinition(type); + mc.recGetTypeDefinition(type, result); + return result; + } + + private void beginInlining(CORINFO_METHOD_STRUCT_* inlinerHnd, CORINFO_METHOD_STRUCT_* inlineeHnd) + { + AddCall("beginInlining"); + _original.beginInlining(inlinerHnd, inlineeHnd); + } + + private void reportInliningDecision(CORINFO_METHOD_STRUCT_* inlinerHnd, CORINFO_METHOD_STRUCT_* inlineeHnd, CorInfoInline inlineResult, byte* reason) + { + AddCall("reportInliningDecision"); + _original.reportInliningDecision(inlinerHnd, inlineeHnd, inlineResult, reason); + cr.recReportInliningDecision(inlinerHnd, inlineeHnd, inlineResult, reason); + } + + private bool canTailCall(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* declaredCalleeHnd, CORINFO_METHOD_STRUCT_* exactCalleeHnd, bool fIsTailPrefix) + { + AddCall("canTailCall"); + var temp = _original.canTailCall(callerHnd, declaredCalleeHnd, exactCalleeHnd, fIsTailPrefix); + mc.recCanTailCall(callerHnd, declaredCalleeHnd, exactCalleeHnd, fIsTailPrefix, temp); + return temp; + } + + private void reportTailCallDecision(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* calleeHnd, bool fIsTailPrefix, CorInfoTailCall tailCallResult, byte* reason) + { + AddCall("reportTailCallDecision"); + _original.reportTailCallDecision(callerHnd, calleeHnd, fIsTailPrefix, tailCallResult, reason); + cr.recReportTailCallDecision(callerHnd, calleeHnd, fIsTailPrefix, tailCallResult, reason); + } + + private void getEHinfo(CORINFO_METHOD_STRUCT_* ftn, uint EHnumber, ref CORINFO_EH_CLAUSE clause) + { + AddCall("getEHinfo"); + _original.getEHinfo(ftn, EHnumber, ref clause); + mc.recGetEHinfo(ftn, EHnumber, P(ref clause)); + } + + private CORINFO_CLASS_STRUCT_* getMethodClass(CORINFO_METHOD_STRUCT_* method) + { + AddCall("getMethodClass"); + var temp = _original.getMethodClass(method); + mc.recGetMethodClass(method, temp); + return temp; + } + + private void getMethodVTableOffset(CORINFO_METHOD_STRUCT_* method, ref uint offsetOfIndirection, ref uint offsetAfterIndirection, ref bool isRelative) + { + AddCall("getMethodVTableOffset"); + _original.getMethodVTableOffset(method, ref offsetOfIndirection, ref offsetAfterIndirection, ref isRelative); + mc.recGetMethodVTableOffset(method, P(ref offsetOfIndirection), P(ref offsetAfterIndirection), P(ref isRelative)); + } + + private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) + { + AddCall("resolveVirtualMethod"); + var result = _original.resolveVirtualMethod(info); + mc.recResolveVirtualMethod(info, result); + return result; + } + + private CORINFO_METHOD_STRUCT_* getAsyncOtherVariant(CORINFO_METHOD_STRUCT_* ftn, ref bool variantIsThunk) + { + AddCall("getAsyncOtherVariant"); + var result = _original.getAsyncOtherVariant(ftn, ref variantIsThunk); + mc.recGetAsyncOtherVariant(ftn, variantIsThunk, result); + return result; + } + + private CORINFO_CLASS_STRUCT_* getDefaultComparerClass(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("getDefaultComparerClass"); + var result = _original.getDefaultComparerClass(cls); + mc.recGetDefaultComparerClass(cls, result); + return result; + } + + private CORINFO_CLASS_STRUCT_* getDefaultEqualityComparerClass(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("getDefaultEqualityComparerClass"); + var result = _original.getDefaultEqualityComparerClass(cls); + mc.recGetDefaultEqualityComparerClass(cls, result); + return result; + } + + private CORINFO_CLASS_STRUCT_* getSZArrayHelperEnumeratorClass(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("getSZArrayHelperEnumeratorClass"); + var result = _original.getSZArrayHelperEnumeratorClass(cls); + mc.recGetSZArrayHelperEnumeratorClass(cls, result); + return result; + } + + private void expandRawHandleIntrinsic(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_GENERICHANDLE_RESULT pResult) + { + AddCall("expandRawHandleIntrinsic"); + _original.expandRawHandleIntrinsic(ref pResolvedToken, callerHandle, ref pResult); + mc.recExpandRawHandleIntrinsic(P(ref pResolvedToken), callerHandle, P(ref pResult)); + } + + private bool isIntrinsicType(CORINFO_CLASS_STRUCT_* classHnd) + { + AddCall("isIntrinsicType"); + var temp = _original.isIntrinsicType(classHnd); + mc.recIsIntrinsicType(classHnd, temp); + return temp; + } + + private CorInfoCallConvExtension getUnmanagedCallConv(CORINFO_METHOD_STRUCT_* method, CORINFO_SIG_INFO* callSiteSig, ref bool pSuppressGCTransition) + { + AddCall("getUnmanagedCallConv"); + var temp = _original.getUnmanagedCallConv(method, callSiteSig, ref pSuppressGCTransition); + mc.recGetUnmanagedCallConv(method, callSiteSig, temp, pSuppressGCTransition); + return temp; + } + + private bool pInvokeMarshalingRequired(CORINFO_METHOD_STRUCT_* method, CORINFO_SIG_INFO* callSiteSig) + { + AddCall("pInvokeMarshalingRequired"); + var temp = _original.pInvokeMarshalingRequired(method, callSiteSig); + mc.recPInvokeMarshalingRequired(method, callSiteSig, temp); + return temp; + } + + private bool satisfiesMethodConstraints(CORINFO_CLASS_STRUCT_* parent, CORINFO_METHOD_STRUCT_* method) + { + AddCall("satisfiesMethodConstraints"); + var temp = _original.satisfiesMethodConstraints(parent, method); + mc.recSatisfiesMethodConstraints(parent, method, temp); + return temp; + } + + private void getGSCookie(IntPtr* pCookieVal, IntPtr** ppCookieVal) + { + AddCall("getGSCookie"); + _original.getGSCookie(pCookieVal, ppCookieVal); + mc.recGetGSCookie(pCookieVal, ppCookieVal); + } + + private void setPatchpointInfo(PatchpointInfo* patchpointInfo) + { + AddCall("setPatchpointInfo"); + cr.recSetPatchpointInfo(patchpointInfo); + _original.setPatchpointInfo(patchpointInfo); + } + + private PatchpointInfo* getOSRInfo(ref uint ilOffset) + { + AddCall("getOSRInfo"); + var patchpointInfo = _original.getOSRInfo(ref ilOffset); + mc.recGetOSRInfo(patchpointInfo, P(ref ilOffset)); + return patchpointInfo; + } + + private void findSig(CORINFO_MODULE_STRUCT_* module, uint sigTOK, CORINFO_CONTEXT_STRUCT* context, CORINFO_SIG_INFO* sig) + { + AddCall("findSig"); + _original.findSig(module, sigTOK, context, sig); + mc.recFindSig(module, sigTOK, context, sig); + } + + private void findCallSiteSig(CORINFO_MODULE_STRUCT_* module, uint methTOK, CORINFO_CONTEXT_STRUCT* context, CORINFO_SIG_INFO* sig) + { + AddCall("findCallSiteSig"); + _original.findCallSiteSig(module, methTOK, context, sig); + mc.recFindCallSiteSig(module, methTOK, context, sig); + } + + private CORINFO_CLASS_STRUCT_* getTokenTypeAsHandle(ref CORINFO_RESOLVED_TOKEN pResolvedToken) + { + AddCall("getTokenTypeAsHandle"); + var temp = _original.getTokenTypeAsHandle(ref pResolvedToken); + mc.recGetTokenTypeAsHandle(P(ref pResolvedToken), temp); + return temp; + } + + private int getStringLiteral(CORINFO_MODULE_STRUCT_* module, uint metaTOK, char* buffer, int bufferSize, int startIndex) + { + AddCall("getStringLiteral"); + var temp = _original.getStringLiteral(module, metaTOK, buffer, bufferSize, startIndex); + mc.recGetStringLiteral(module, metaTOK, buffer, bufferSize, startIndex, temp); + return temp; + } + + private nuint printObjectDescription(CORINFO_OBJECT_STRUCT_* handle, byte* buffer, nuint bufferSize, nuint* pRequiredBufferSize) + { + AddCall("printObjectDescription"); + var temp = _original.printObjectDescription(handle, buffer, bufferSize, pRequiredBufferSize); + mc.recPrintObjectDescription(handle, buffer, bufferSize, pRequiredBufferSize, temp); + return temp; + } + + private CorInfoType asCorInfoType(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("asCorInfoType"); + var temp = _original.asCorInfoType(cls); + mc.recAsCorInfoType(cls, temp); + return temp; + } + + private byte* getClassNameFromMetadata(CORINFO_CLASS_STRUCT_* cls, byte** namespaceName) + { + AddCall("getClassNameFromMetadata"); + var temp = _original.getClassNameFromMetadata(cls, namespaceName); + mc.recGetClassNameFromMetadata(cls, temp, namespaceName); + return temp; + } + + private CORINFO_CLASS_STRUCT_* getTypeInstantiationArgument(CORINFO_CLASS_STRUCT_* cls, uint index) + { + AddCall("getTypeInstantiationArgument"); + var result = _original.getTypeInstantiationArgument(cls, index); + mc.recGetTypeInstantiationArgument(cls, index, result); + return result; + } + + private CORINFO_CLASS_STRUCT_* getMethodInstantiationArgument(CORINFO_METHOD_STRUCT_* ftn, uint index) + { + AddCall("getMethodInstantiationArgument"); + var result = _original.getMethodInstantiationArgument(ftn, index); + mc.recGetMethodInstantiationArgument(ftn, index, result); + return result; + } + + private nuint printClassName(CORINFO_CLASS_STRUCT_* cls, byte* buffer, nuint bufferSize, nuint* pRequiredBufferSize) + { + AddCall("printClassName"); + var bytesWritten = _original.printClassName(cls, buffer, bufferSize, pRequiredBufferSize); + mc.recPrintClassName(cls, buffer, bufferSize, pRequiredBufferSize, bytesWritten); + return bytesWritten; + } + + private bool isValueClass(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("isValueClass"); + var temp = _original.isValueClass(cls); + mc.recIsValueClass(cls, temp); + return temp; + } + + private bool isByRefLike(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("isByRefLike"); + var result = _original.isByRefLike(cls); + mc.recIsByRefLike(cls, result); + return result; + } + + private bool isSharedInst(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("isSharedInst"); + var result = _original.isSharedInst(cls); + mc.recIsSharedInst(cls, result); + return result; + } + + private uint getClassAttribs(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("getClassAttribs"); + var temp = _original.getClassAttribs(cls); + mc.recGetClassAttribs(cls, temp); + return temp; + } + + private byte* getClassAssemblyName(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("getClassAssemblyName"); + var temp = _original.getClassAssemblyName(cls); + mc.recGetClassAssemblyName(cls, temp); + return temp; + } + + private void* LongLifetimeMalloc(nuint sz) + { + AddCall("LongLifetimeMalloc"); + return _original.LongLifetimeMalloc(sz); + } + + private void LongLifetimeFree(void* obj) + { + AddCall("LongLifetimeFree"); + _original.LongLifetimeFree(obj); + } + + private bool getIsClassInitedFlagAddress(CORINFO_CLASS_STRUCT_* cls, ref CORINFO_CONST_LOOKUP addr, ref int offset) + { + AddCall("getIsClassInitedFlagAddress"); + var temp = _original.getIsClassInitedFlagAddress(cls, ref addr, ref offset); + mc.recGetIsClassInitedFlagAddress(cls, P(ref addr), P(ref offset), temp); + return temp; + } + + private void* getClassThreadStaticDynamicInfo(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("getClassThreadStaticDynamicInfo"); + var temp = _original.getClassThreadStaticDynamicInfo(cls); + mc.recGetClassThreadStaticDynamicInfo(cls, temp); + return temp; + } + + private void* getClassStaticDynamicInfo(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("getClassStaticDynamicInfo"); + var temp = _original.getClassStaticDynamicInfo(cls); + mc.recGetClassStaticDynamicInfo(cls, temp); + return temp; + } + + private bool getStaticBaseAddress(CORINFO_CLASS_STRUCT_* cls, bool isGc, ref CORINFO_CONST_LOOKUP addr) + { + AddCall("getStaticBaseAddress"); + var temp = _original.getStaticBaseAddress(cls, isGc, ref addr); + mc.recGetStaticBaseAddress(cls, isGc, P(ref addr), temp); + return temp; + } + + private uint getClassSize(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("getClassSize"); + var temp = _original.getClassSize(cls); + mc.recGetClassSize(cls, temp); + return temp; + } + + private uint getHeapClassSize(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("getHeapClassSize"); + var temp = _original.getHeapClassSize(cls); + mc.recGetHeapClassSize(cls, temp); + return temp; + } + + private bool canAllocateOnStack(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("canAllocateOnStack"); + var temp = _original.canAllocateOnStack(cls); + mc.recCanAllocateOnStack(cls, temp); + return temp; + } + + private uint getClassAlignmentRequirement(CORINFO_CLASS_STRUCT_* cls, bool fDoubleAlignHint) + { + AddCall("getClassAlignmentRequirement"); + var temp = _original.getClassAlignmentRequirement(cls, fDoubleAlignHint); + mc.recGetClassAlignmentRequirement(cls, fDoubleAlignHint, temp); + return temp; + } + + private uint getClassNumInstanceFields(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("getClassNumInstanceFields"); + var temp = _original.getClassNumInstanceFields(cls); + mc.recGetClassNumInstanceFields(cls, temp); + return temp; + } + + private CORINFO_FIELD_STRUCT_* getFieldInClass(CORINFO_CLASS_STRUCT_* clsHnd, int num) + { + AddCall("getFieldInClass"); + var temp = _original.getFieldInClass(clsHnd, num); + mc.recGetFieldInClass(clsHnd, num, temp); + return temp; + } + + private GetTypeLayoutResult getTypeLayout(CORINFO_CLASS_STRUCT_* typeHnd, CORINFO_TYPE_LAYOUT_NODE* nodes, nuint* numNodes) + { + AddCall("getTypeLayout"); + var result = _original.getTypeLayout(typeHnd, nodes, numNodes); + mc.recGetTypeLayout(result, typeHnd, nodes, *numNodes); + return result; + } + + private bool checkMethodModifier(CORINFO_METHOD_STRUCT_* hMethod, byte* modifier, bool fOptional) + { + AddCall("checkMethodModifier"); + var result = _original.checkMethodModifier(hMethod, modifier, fOptional); + mc.recCheckMethodModifier(hMethod, modifier, fOptional, result); + return result; + } + + private CorInfoHelpFunc getNewArrHelper(CORINFO_CLASS_STRUCT_* arrayCls) + { + AddCall("getNewArrHelper"); + var temp = _original.getNewArrHelper(arrayCls); + mc.recGetNewArrHelper(arrayCls, temp); + return temp; + } + + private CorInfoHelpFunc getCastingHelper(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool fThrowing) + { + AddCall("getCastingHelper"); + var temp = _original.getCastingHelper(ref pResolvedToken, fThrowing); + mc.recGetCastingHelper(P(ref pResolvedToken), fThrowing, temp); + return temp; + } + + private CorInfoHelpFunc getSharedCCtorHelper(CORINFO_CLASS_STRUCT_* clsHnd) + { + AddCall("getSharedCCtorHelper"); + var temp = _original.getSharedCCtorHelper(clsHnd); + mc.recGetSharedCCtorHelper(clsHnd, temp); + return temp; + } + + private CORINFO_CLASS_STRUCT_* getTypeForBox(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("getTypeForBox"); + var temp = _original.getTypeForBox(cls); + mc.recGetTypeForBox(cls, temp); + return temp; + } + + private CorInfoHelpFunc getBoxHelper(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("getBoxHelper"); + var temp = _original.getBoxHelper(cls); + mc.recGetBoxHelper(cls, temp); + return temp; + } + + private CorInfoHelpFunc getUnBoxHelper(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("getUnBoxHelper"); + var temp = _original.getUnBoxHelper(cls); + mc.recGetUnBoxHelper(cls, temp); + return temp; + } + + private CORINFO_OBJECT_STRUCT_* getRuntimeTypePointer(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("getRuntimeTypePointer"); + var temp = _original.getRuntimeTypePointer(cls); + mc.recGetRuntimeTypePointer(cls, temp); + return temp; + } + + private bool isObjectImmutable(CORINFO_OBJECT_STRUCT_* typeObj) + { + AddCall("isObjectImmutable"); + var temp = _original.isObjectImmutable(typeObj); + mc.recIsObjectImmutable(typeObj, temp); + return temp; + } + + private bool getStringChar(CORINFO_OBJECT_STRUCT_* strObj, int index, ushort* value) + { + AddCall("getStringChar"); + var temp = _original.getStringChar(strObj, index, value); + mc.recGetStringChar(strObj, index, value, temp); + return temp; + } + + private CORINFO_CLASS_STRUCT_* getObjectType(CORINFO_OBJECT_STRUCT_* typeObj) + { + AddCall("getObjectType"); + var temp = _original.getObjectType(typeObj); + mc.recGetObjectType(typeObj, temp); + return temp; + } + + private bool getReadyToRunHelper(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CorInfoHelpFunc id, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_CONST_LOOKUP pLookup) + { + AddCall("getReadyToRunHelper"); + var result = _original.getReadyToRunHelper(ref pResolvedToken, id, callerHandle, ref pLookup); + mc.recGetReadyToRunHelper(P(ref pResolvedToken), id, callerHandle, P(ref pLookup), result); + return result; + } + + private void getReadyToRunDelegateCtorHelper(ref CORINFO_RESOLVED_TOKEN pTargetMethod, mdToken targetConstraint, CORINFO_CLASS_STRUCT_* delegateType, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_LOOKUP pLookup) + { + AddCall("getReadyToRunDelegateCtorHelper"); + _original.getReadyToRunDelegateCtorHelper(ref pTargetMethod, targetConstraint, delegateType, callerHandle, ref pLookup); + mc.recGetReadyToRunDelegateCtorHelper(P(ref pTargetMethod), (uint)targetConstraint, delegateType, callerHandle, P(ref pLookup)); + } + + private CorInfoInitClassResult initClass(CORINFO_FIELD_STRUCT_* field, CORINFO_METHOD_STRUCT_* method, CORINFO_CONTEXT_STRUCT* context) + { + AddCall("initClass"); + var temp = _original.initClass(field, method, context); + mc.recInitClass(field, method, context, temp); + return temp; + } + + private CORINFO_CLASS_STRUCT_* getBuiltinClass(CorInfoClassId classId) + { + AddCall("getBuiltinClass"); + var temp = _original.getBuiltinClass(classId); + mc.recGetBuiltinClass(classId, temp); + return temp; + } + + private CorInfoType getTypeForPrimitiveValueClass(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("getTypeForPrimitiveValueClass"); + var temp = _original.getTypeForPrimitiveValueClass(cls); + mc.recGetTypeForPrimitiveValueClass(cls, temp); + return temp; + } + + private CorInfoType getTypeForPrimitiveNumericClass(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("getTypeForPrimitiveNumericClass"); + var temp = _original.getTypeForPrimitiveNumericClass(cls); + mc.recGetTypeForPrimitiveNumericClass(cls, temp); + return temp; + } + + private TypeCompareState compareTypesForCast(CORINFO_CLASS_STRUCT_* fromClass, CORINFO_CLASS_STRUCT_* toClass) + { + AddCall("compareTypesForCast"); + var temp = _original.compareTypesForCast(fromClass, toClass); + mc.recCompareTypesForCast(fromClass, toClass, temp); + return temp; + } + + private TypeCompareState compareTypesForEquality(CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2) + { + AddCall("compareTypesForEquality"); + var temp = _original.compareTypesForEquality(cls1, cls2); + mc.recCompareTypesForEquality(cls1, cls2, temp); + return temp; + } + + private bool isMoreSpecificType(CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2) + { + AddCall("isMoreSpecificType"); + var temp = _original.isMoreSpecificType(cls1, cls2); + mc.recIsMoreSpecificType(cls1, cls2, temp); + return temp; + } + + private bool isExactType(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("isExactType"); + var temp = _original.isExactType(cls); + mc.recIsExactType(cls, temp); + return temp; + } + + private TypeCompareState isGenericType(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("isGenericType"); + var temp = _original.isGenericType(cls); + mc.recIsGenericType(cls, temp); + return temp; + } + + private TypeCompareState isNullableType(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("isNullableType"); + var temp = _original.isNullableType(cls); + mc.recIsNullableType(cls, temp); + return temp; + } + + private CORINFO_CLASS_STRUCT_* getParentType(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("getParentType"); + var temp = _original.getParentType(cls); + mc.recGetParentType(cls, temp); + return temp; + } + + private CorInfoType getChildType(CORINFO_CLASS_STRUCT_* clsHnd, CORINFO_CLASS_STRUCT_** clsRet) + { + AddCall("getChildType"); + var temp = _original.getChildType(clsHnd, clsRet); + mc.recGetChildType(clsHnd, clsRet, temp); + return temp; + } + + private bool isSDArray(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("isSDArray"); + var temp = _original.isSDArray(cls); + mc.recIsSDArray(cls, temp); + return temp; + } + + private uint getArrayRank(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("getArrayRank"); + var result = _original.getArrayRank(cls); + mc.recGetArrayRank(cls, result); + return result; + } + + private CorInfoArrayIntrinsic getArrayIntrinsicID(CORINFO_METHOD_STRUCT_* ftn) + { + AddCall("getArrayIntrinsicID"); + var result = _original.getArrayIntrinsicID(ftn); + mc.recGetArrayIntrinsicID(ftn, result); + return result; + } + + private void* getArrayInitializationData(CORINFO_FIELD_STRUCT_* field, uint size) + { + AddCall("getArrayInitializationData"); + var temp = _original.getArrayInitializationData(field, size); + mc.recGetArrayInitializationData(field, size, temp); + return temp; + } + + private CorInfoIsAccessAllowedResult canAccessClass(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_HELPER_DESC pAccessHelper) + { + AddCall("canAccessClass"); + var temp = _original.canAccessClass(ref pResolvedToken, callerHandle, ref pAccessHelper); + mc.recCanAccessClass(P(ref pResolvedToken), callerHandle, P(ref pAccessHelper), temp); + return temp; + } + + private nuint printFieldName(CORINFO_FIELD_STRUCT_* ftn, byte* buffer, nuint bufferSize, nuint* pRequiredBufferSize) + { + AddCall("printFieldName"); + var temp = _original.printFieldName(ftn, buffer, bufferSize, pRequiredBufferSize); + mc.recPrintFieldName(ftn, buffer, bufferSize, pRequiredBufferSize, temp); + return temp; + } + + private CORINFO_CLASS_STRUCT_* getFieldClass(CORINFO_FIELD_STRUCT_* field) + { + AddCall("getFieldClass"); + var temp = _original.getFieldClass(field); + mc.recGetFieldClass(field, temp); + return temp; + } + + private CorInfoType getFieldType(CORINFO_FIELD_STRUCT_* field, CORINFO_CLASS_STRUCT_** structType, CORINFO_CLASS_STRUCT_* fieldOwnerHint) + { + AddCall("getFieldType"); + var temp = _original.getFieldType(field, structType, fieldOwnerHint); + mc.recGetFieldType(field, structType, fieldOwnerHint, temp); + return temp; + } + + private uint getFieldOffset(CORINFO_FIELD_STRUCT_* field) + { + AddCall("getFieldOffset"); + var temp = _original.getFieldOffset(field); + mc.recGetFieldOffset(field, temp); + return temp; + } + + private void getFieldInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult) + { + AddCall("getFieldInfo"); + _original.getFieldInfo(ref pResolvedToken, callerHandle, flags, pResult); + mc.recGetFieldInfo(P(ref pResolvedToken), callerHandle, flags, pResult); + } + + private uint getThreadLocalFieldInfo(CORINFO_FIELD_STRUCT_* field, bool isGCType) + { + AddCall("getThreadLocalFieldInfo"); + var result = _original.getThreadLocalFieldInfo(field, isGCType); + mc.recGetThreadLocalFieldInfo(field, isGCType, result); + return result; + } + + private void getThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) + { + AddCall("getThreadLocalStaticBlocksInfo"); + _original.getThreadLocalStaticBlocksInfo(pInfo); + mc.recGetThreadLocalStaticBlocksInfo(pInfo); + } + + private void getThreadLocalStaticInfo_NativeAOT(CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo) + { + AddCall("getThreadLocalStaticInfo_NativeAOT"); + _original.getThreadLocalStaticInfo_NativeAOT(pInfo); + mc.recGetThreadLocalStaticInfo_NativeAOT(pInfo); + } + + private bool isFieldStatic(CORINFO_FIELD_STRUCT_* fldHnd) + { + AddCall("isFieldStatic"); + var result = _original.isFieldStatic(fldHnd); + mc.recIsFieldStatic(fldHnd, result); + return result; + } + + private int getArrayOrStringLength(CORINFO_OBJECT_STRUCT_* objHnd) + { + AddCall("getArrayOrStringLength"); + var result = _original.getArrayOrStringLength(objHnd); + mc.recGetArrayOrStringLength(objHnd, result); + return result; + } + + private void getBoundaries(CORINFO_METHOD_STRUCT_* ftn, ref uint cILOffsets, ref uint* pILOffsets, BoundaryTypes* implicitBoundaries) + { + AddCall("getBoundaries"); + _original.getBoundaries(ftn, ref cILOffsets, ref pILOffsets, implicitBoundaries); + mc.recGetBoundaries(ftn, P(ref cILOffsets), P(ref pILOffsets), implicitBoundaries); + } + + private void setBoundaries(CORINFO_METHOD_STRUCT_* ftn, uint cMap, OffsetMapping* pMap) + { + AddCall("setBoundaries"); + cr.recSetBoundaries(ftn, cMap, pMap); + _original.setBoundaries(ftn, cMap, pMap); + } + + private void getVars(CORINFO_METHOD_STRUCT_* ftn, ref uint cVars, ILVarInfo** vars, ref bool extendOthers) + { + AddCall("getVars"); + _original.getVars(ftn, ref cVars, vars, ref extendOthers); + mc.recGetVars(ftn, P(ref cVars), vars, P(ref extendOthers)); + } + + private void setVars(CORINFO_METHOD_STRUCT_* ftn, uint cVars, NativeVarInfo* vars) + { + AddCall("setVars"); + cr.recSetVars(ftn, cVars, vars); + _original.setVars(ftn, cVars, vars); + } + + private void reportRichMappings(InlineTreeNode* inlineTreeNodes, uint numInlineTreeNodes, RichOffsetMapping* mappings, uint numMappings) + { + AddCall("reportRichMappings"); + _original.reportRichMappings(inlineTreeNodes, numInlineTreeNodes, mappings, numMappings); + } + + private void reportAsyncDebugInfo(AsyncInfo* asyncInfo, AsyncSuspensionPoint* suspensionPoints, AsyncContinuationVarInfo* vars, uint numVars) + { + AddCall("reportAsyncDebugInfo"); + _original.reportAsyncDebugInfo(asyncInfo, suspensionPoints, vars, numVars); + } + + private void reportMetadata(byte* key, void* value, nuint length) + { + AddCall("reportMetadata"); + _original.reportMetadata(key, value, length); + } + + private CORINFO_ARG_LIST_STRUCT_* getArgNext(CORINFO_ARG_LIST_STRUCT_* args) + { + AddCall("getArgNext"); + var temp = _original.getArgNext(args); + mc.recGetArgNext(args, temp); + return temp; + } + + private CorInfoHFAElemType getHFAType(CORINFO_CLASS_STRUCT_* hClass) + { + AddCall("getHFAType"); + var temp = _original.getHFAType(hClass); + mc.recGetHFAType(hClass, temp); + return temp; + } + + private void getEEInfo(ref CORINFO_EE_INFO pEEInfoOut) + { + AddCall("getEEInfo"); + _original.getEEInfo(ref pEEInfoOut); + mc.recGetEEInfo(P(ref pEEInfoOut)); + } + + private void getAsyncInfo(ref CORINFO_ASYNC_INFO pAsyncInfo) + { + AddCall("getAsyncInfo"); + _original.getAsyncInfo(ref pAsyncInfo); + mc.recGetAsyncInfo(P(ref pAsyncInfo)); + } + + private CORINFO_METHOD_STRUCT_* getAwaitReturnCall(CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_CONTEXT_STRUCT** contextHandle, ref CORINFO_LOOKUP instArg) + { + AddCall("getAwaitReturnCall"); + var result = _original.getAwaitReturnCall(callerHandle, contextHandle, ref instArg); + mc.recGetAwaitReturnCall(callerHandle, contextHandle, P(ref instArg), result); + return result; + } + + private CORINFO_METHOD_STRUCT_* getAwaitAwaiterInContinuationCall(CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool isUnsafe, CORINFO_CONTEXT_STRUCT** contextHandle, ref CORINFO_LOOKUP instArg) + { + AddCall("getAwaitAwaiterInContinuationCall"); + var result = _original.getAwaitAwaiterInContinuationCall(callerHandle, ref pResolvedToken, isUnsafe, contextHandle, ref instArg); + mc.recGetAwaitAwaiterInContinuationCall(callerHandle, P(ref pResolvedToken), isUnsafe, contextHandle, P(ref instArg), result); + return result; + } + + private mdToken getMethodDefFromMethod(CORINFO_METHOD_STRUCT_* hMethod) + { + AddCall("getMethodDefFromMethod"); + var result = _original.getMethodDefFromMethod(hMethod); + mc.recGetMethodDefFromMethod(hMethod, (uint)result); + return result; + } + + private nuint printMethodName(CORINFO_METHOD_STRUCT_* ftn, byte* buffer, nuint bufferSize, nuint* pRequiredBufferSize) + { + AddCall("printMethodName"); + var temp = _original.printMethodName(ftn, buffer, bufferSize, pRequiredBufferSize); + mc.recPrintMethodName(ftn, buffer, bufferSize, pRequiredBufferSize, temp); + return temp; + } + + private byte* getMethodNameFromMetadata(CORINFO_METHOD_STRUCT_* ftn, byte** className, byte** namespaceName, byte** enclosingClassNames, nuint maxEnclosingClassNames) + { + AddCall("getMethodNameFromMetadata"); + var temp = _original.getMethodNameFromMetadata(ftn, className, namespaceName, enclosingClassNames, maxEnclosingClassNames); + mc.recGetMethodNameFromMetadata(ftn, temp, className, namespaceName, enclosingClassNames, maxEnclosingClassNames); + return temp; + } + + private uint getMethodHash(CORINFO_METHOD_STRUCT_* ftn) + { + AddCall("getMethodHash"); + var temp = _original.getMethodHash(ftn); + mc.recGetMethodHash(ftn, temp); + return temp; + } + + private bool getSystemVAmd64PassStructInRegisterDescriptor(CORINFO_CLASS_STRUCT_* structHnd, SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr) + { + AddCall("getSystemVAmd64PassStructInRegisterDescriptor"); + var result = _original.getSystemVAmd64PassStructInRegisterDescriptor(structHnd, structPassInRegDescPtr); + mc.recGetSystemVAmd64PassStructInRegisterDescriptor(structHnd, structPassInRegDescPtr, result); + return result; + } + + private void getSwiftLowering(CORINFO_CLASS_STRUCT_* structHnd, ref CORINFO_SWIFT_LOWERING pLowering) + { + AddCall("getSwiftLowering"); + _original.getSwiftLowering(structHnd, ref pLowering); + mc.recGetSwiftLowering(structHnd, P(ref pLowering)); + } + + private void getFpStructLowering(CORINFO_CLASS_STRUCT_* structHnd, ref CORINFO_FPSTRUCT_LOWERING pLowering) + { + AddCall("getFpStructLowering"); + _original.getFpStructLowering(structHnd, ref pLowering); + mc.recGetFpStructLowering(structHnd, P(ref pLowering)); + } + + private CorInfoWasmType getWasmLowering(CORINFO_CLASS_STRUCT_* structHnd) + { + AddCall("getWasmLowering"); + var result = _original.getWasmLowering(structHnd); + mc.recGetWasmLowering(structHnd, result); + return result; + } + + private uint getAddressAlignment(void* address) + { + AddCall("getAddressAlignment"); + var result = _original.getAddressAlignment(address); + mc.recGetAddressAlignment(address, result); + return result; + } + + private void getWasmWellKnownGlobals(ref CORINFO_WASM_WELLKNOWN_GLOBALS pWellKnownGlobalsOut) + { + AddCall("getWasmWellKnownGlobals"); + _original.getWasmWellKnownGlobals(ref pWellKnownGlobalsOut); + mc.recGetWasmWellKnownGlobals(P(ref pWellKnownGlobalsOut)); + } + + private uint getThreadTLSIndex(ref void* ppIndirection) + { + AddCall("getThreadTLSIndex"); + var temp = _original.getThreadTLSIndex(ref ppIndirection); + mc.recGetThreadTLSIndex(P(ref ppIndirection), temp); + return temp; + } + + private int* getAddrOfCaptureThreadGlobal(ref void* ppIndirection) + { + AddCall("getAddrOfCaptureThreadGlobal"); + var temp = _original.getAddrOfCaptureThreadGlobal(ref ppIndirection); + mc.recGetAddrOfCaptureThreadGlobal(P(ref ppIndirection), temp); + return temp; + } + + private void getFunctionEntryPoint(CORINFO_METHOD_STRUCT_* ftn, ref CORINFO_CONST_LOOKUP pResult, CORINFO_ACCESS_FLAGS accessFlags) + { + AddCall("getFunctionEntryPoint"); + _original.getFunctionEntryPoint(ftn, ref pResult, accessFlags); + mc.recGetFunctionEntryPoint(ftn, P(ref pResult), accessFlags); + } + + private void getFunctionFixedEntryPoint(CORINFO_METHOD_STRUCT_* ftn, bool isUnsafeFunctionPointer, ref CORINFO_CONST_LOOKUP pResult) + { + AddCall("getFunctionFixedEntryPoint"); + _original.getFunctionFixedEntryPoint(ftn, isUnsafeFunctionPointer, ref pResult); + mc.recGetFunctionFixedEntryPoint(ftn, P(ref pResult)); + } + + private CORINFO_MODULE_STRUCT_* embedModuleHandle(CORINFO_MODULE_STRUCT_* handle, ref void* ppIndirection) + { + AddCall("embedModuleHandle"); + var temp = _original.embedModuleHandle(handle, ref ppIndirection); + mc.recEmbedModuleHandle(handle, P(ref ppIndirection), temp); + return temp; + } + + private CORINFO_CLASS_STRUCT_* embedClassHandle(CORINFO_CLASS_STRUCT_* handle, ref void* ppIndirection) + { + AddCall("embedClassHandle"); + var temp = _original.embedClassHandle(handle, ref ppIndirection); + mc.recEmbedClassHandle(handle, P(ref ppIndirection), temp); + return temp; + } + + private CORINFO_METHOD_STRUCT_* embedMethodHandle(CORINFO_METHOD_STRUCT_* handle, ref void* ppIndirection) + { + AddCall("embedMethodHandle"); + var temp = _original.embedMethodHandle(handle, ref ppIndirection); + mc.recEmbedMethodHandle(handle, P(ref ppIndirection), temp); + return temp; + } + + private CORINFO_FIELD_STRUCT_* embedFieldHandle(CORINFO_FIELD_STRUCT_* handle, ref void* ppIndirection) + { + AddCall("embedFieldHandle"); + var temp = _original.embedFieldHandle(handle, ref ppIndirection); + mc.recEmbedFieldHandle(handle, P(ref ppIndirection), temp); + return temp; + } + + private void embedGenericHandle(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool fEmbedParent, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_GENERICHANDLE_RESULT pResult) + { + AddCall("embedGenericHandle"); + _original.embedGenericHandle(ref pResolvedToken, fEmbedParent, callerHandle, ref pResult); + mc.recEmbedGenericHandle(P(ref pResolvedToken), fEmbedParent, callerHandle, P(ref pResult)); + } + + private void getLocationOfThisType(CORINFO_METHOD_STRUCT_* context, ref CORINFO_LOOKUP_KIND pLookupKind) + { + AddCall("getLocationOfThisType"); + _original.getLocationOfThisType(context, ref pLookupKind); + mc.recGetLocationOfThisType(context, P(ref pLookupKind)); + } + + private void getAddressOfPInvokeTarget(CORINFO_METHOD_STRUCT_* method, ref CORINFO_CONST_LOOKUP pLookup) + { + AddCall("getAddressOfPInvokeTarget"); + _original.getAddressOfPInvokeTarget(method, ref pLookup); + mc.recGetAddressOfPInvokeTarget(method, P(ref pLookup)); + } + + private void* GetCookieForInterpreterCalliSig(CORINFO_SIG_INFO* szMetaSig) + { + AddCall("GetCookieForInterpreterCalliSig"); + var temp = _original.GetCookieForInterpreterCalliSig(szMetaSig); + mc.recGetCookieForInterpreterCalliSig(szMetaSig, temp); + return temp; + } + + private CORINFO_JUST_MY_CODE_HANDLE_* getJustMyCodeHandle(CORINFO_METHOD_STRUCT_* method, ref CORINFO_JUST_MY_CODE_HANDLE_* ppIndirection) + { + AddCall("getJustMyCodeHandle"); + var temp = _original.getJustMyCodeHandle(method, ref ppIndirection); + mc.recGetJustMyCodeHandle(method, P(ref ppIndirection), temp); + return temp; + } + + private void GetProfilingHandle(ref bool pbHookFunction, ref void* pProfilerHandle, ref bool pbIndirectedHandles) + { + AddCall("GetProfilingHandle"); + _original.GetProfilingHandle(ref pbHookFunction, ref pProfilerHandle, ref pbIndirectedHandles); + mc.recGetProfilingHandle(P(ref pbHookFunction), P(ref pProfilerHandle), P(ref pbIndirectedHandles)); + } + + private bool getStaticFieldContent(CORINFO_FIELD_STRUCT_* field, byte* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects) + { + AddCall("getStaticFieldContent"); + var result = _original.getStaticFieldContent(field, buffer, bufferSize, valueOffset, ignoreMovableObjects); + mc.recGetStaticFieldContent(field, buffer, bufferSize, valueOffset, ignoreMovableObjects, result); + return result; + } + + private bool getObjectContent(CORINFO_OBJECT_STRUCT_* obj, byte* buffer, int bufferSize, int valueOffset) + { + AddCall("getObjectContent"); + var result = _original.getObjectContent(obj, buffer, bufferSize, valueOffset); + mc.recGetObjectContent(obj, buffer, bufferSize, valueOffset, result); + return result; + } + + private CORINFO_CLASS_STRUCT_* getStaticFieldCurrentClass(CORINFO_FIELD_STRUCT_* field, byte* pIsSpeculative) + { + AddCall("getStaticFieldCurrentClass"); + var result = _original.getStaticFieldCurrentClass(field, pIsSpeculative); + mc.recGetStaticFieldCurrentClass(field, (bool*)pIsSpeculative, result); + return result; + } + + private IntPtr getVarArgsHandle(CORINFO_SIG_INFO* pSig, CORINFO_METHOD_STRUCT_* methHnd, ref void* ppIndirection) + { + AddCall("getVarArgsHandle"); + var temp = _original.getVarArgsHandle(pSig, methHnd, ref ppIndirection); + mc.recGetVarArgsHandle(pSig, methHnd, P(ref ppIndirection), (void*)temp); + return temp; + } + + private InfoAccessType constructStringLiteral(CORINFO_MODULE_STRUCT_* module, mdToken metaTok, ref void* ppValue) + { + AddCall("constructStringLiteral"); + var temp = _original.constructStringLiteral(module, metaTok, ref ppValue); + mc.recConstructStringLiteral(module, (uint)metaTok, ppValue, temp); + return temp; + } + + private InfoAccessType emptyStringLiteral(ref void* ppValue) + { + AddCall("emptyStringLiteral"); + var temp = _original.emptyStringLiteral(ref ppValue); + mc.recEmptyStringLiteral(P(ref ppValue), temp); + return temp; + } + + private uint getFieldThreadLocalStoreID(CORINFO_FIELD_STRUCT_* field, ref void* ppIndirection) + { + AddCall("getFieldThreadLocalStoreID"); + var temp = _original.getFieldThreadLocalStoreID(field, ref ppIndirection); + mc.recGetFieldThreadLocalStoreID(field, P(ref ppIndirection), temp); + return temp; + } + + private CORINFO_METHOD_STRUCT_* GetDelegateCtor(CORINFO_METHOD_STRUCT_* methHnd, CORINFO_CLASS_STRUCT_* clsHnd, CORINFO_METHOD_STRUCT_* targetMethodHnd, ref DelegateCtorArgs pCtorData) + { + AddCall("GetDelegateCtor"); + var temp = _original.GetDelegateCtor(methHnd, clsHnd, targetMethodHnd, ref pCtorData); + mc.recGetDelegateCtor(methHnd, clsHnd, targetMethodHnd, P(ref pCtorData), temp); + return temp; + } + + private void MethodCompileComplete(CORINFO_METHOD_STRUCT_* methHnd) + { + AddCall("MethodCompileComplete"); + _original.MethodCompileComplete(methHnd); + } + + private CORINFO_CLASS_STRUCT_* getContinuationType(nuint dataSize, ref bool objRefs, nuint objRefsSize) + { + AddCall("getContinuationType"); + var result = _original.getContinuationType(dataSize, ref objRefs, objRefsSize); + mc.recGetContinuationType(dataSize, P(ref objRefs), objRefsSize, result); + return result; + } + + private CORINFO_METHOD_STRUCT_* getAsyncResumptionStub(ref void* entryPoint) + { + AddCall("getAsyncResumptionStub"); + var stub = _original.getAsyncResumptionStub(ref entryPoint); + mc.recGetAsyncResumptionStub(stub, entryPoint); + return stub; + } + + private bool convertPInvokeCalliToCall(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool fMustConvert) + { + AddCall("convertPInvokeCalliToCall"); + var result = _original.convertPInvokeCalliToCall(ref pResolvedToken, fMustConvert); + mc.recConvertPInvokeCalliToCall(P(ref pResolvedToken), fMustConvert, result); + return result; + } + + private bool notifyInstructionSetUsage(InstructionSet instructionSet, bool supported, bool preserveNegativeDependency) + { + AddCall("notifyInstructionSetUsage"); + var result = _original.notifyInstructionSetUsage(instructionSet, supported, preserveNegativeDependency); + mc.recNotifyInstructionSetUsage(instructionSet, supported, preserveNegativeDependency, result); + return result; + } + + private void allocMem(ref AllocMemArgs pArgs) + { + AddCall("allocMem"); + _original.allocMem(ref pArgs); + } + + private void reserveUnwindInfo(bool isFunclet, bool isColdCode, uint unwindSize) + { + AddCall("reserveUnwindInfo"); + _original.reserveUnwindInfo(isFunclet, isColdCode, unwindSize); + cr.recReserveUnwindInfo(isFunclet, isColdCode, unwindSize); + } + + private void allocUnwindInfo(byte* pHotCode, byte* pColdCode, uint startOffset, uint endOffset, uint unwindSize, byte* pUnwindBlock, CorJitFuncKind funcKind) + { + AddCall("allocUnwindInfo"); + _original.allocUnwindInfo(pHotCode, pColdCode, startOffset, endOffset, unwindSize, pUnwindBlock, funcKind); + cr.recAllocUnwindInfo(pHotCode, pColdCode, startOffset, endOffset, unwindSize, pUnwindBlock, funcKind); + } + + private void* allocGCInfo(nuint size) + { + AddCall("allocGCInfo"); + var temp = _original.allocGCInfo(size); + cr.recAllocGCInfo(size, temp); + return temp; + } + + private void setEHcount(uint cEH) + { + AddCall("setEHcount"); + _original.setEHcount(cEH); + cr.recSetEHcount(cEH); + } + + private void setEHinfo(uint EHnumber, ref CORINFO_EH_CLAUSE clause) + { + AddCall("setEHinfo"); + _original.setEHinfo(EHnumber, ref clause); + cr.recSetEHinfo(EHnumber, P(ref clause)); + } + + private bool logMsg(uint level, byte* fmt, IntPtr args) + { + AddCall("logMsg"); + return _original.logMsg(level, fmt, args); + } + + private void reportFatalError(CorJitResult result) + { + AddCall("reportFatalError"); + _original.reportFatalError(result); + cr.recReportFatalError(result); + } + + private HRESULT allocPgoInstrumentationBySchema(CORINFO_METHOD_STRUCT_* ftnHnd, PgoInstrumentationSchema* pSchema, uint countSchemaItems, byte** pInstrumentationData) + { + AddCall("allocPgoInstrumentationBySchema"); + var result = _original.allocPgoInstrumentationBySchema(ftnHnd, pSchema, countSchemaItems, pInstrumentationData); + mc.recAllocPgoInstrumentationBySchema(ftnHnd, pSchema, countSchemaItems, pInstrumentationData, (int)result); + return result; + } + + private void recordCallSite(uint instrOffset, CORINFO_SIG_INFO* callSig, CORINFO_METHOD_STRUCT_* methodHandle) + { + AddCall("recordCallSite"); + _original.recordCallSite(instrOffset, callSig, methodHandle); + cr.recRecordCallSite(instrOffset, callSig, methodHandle); + } + + private void recordRelocation(void* location, void* locationRW, void* target, CorInfoReloc fRelocType, int addlDelta) + { + AddCall("recordRelocation"); + _original.recordRelocation(location, locationRW, target, fRelocType, addlDelta); + cr.recRecordRelocation(location, target, fRelocType, addlDelta); + } + + private CorInfoReloc getRelocTypeHint(void* target) + { + AddCall("getRelocTypeHint"); + var result = _original.getRelocTypeHint(target); + mc.recGetRelocTypeHint(target, result); + return result; + } + + private uint getExpectedTargetArchitecture() + { + AddCall("getExpectedTargetArchitecture"); + var result = _original.getExpectedTargetArchitecture(); + mc.recGetExpectedTargetArchitecture(result); + return result; + } + + private uint getJitFlags(ref CORJIT_FLAGS jitFlags, uint sizeInBytes) + { + AddCall("getJitFlags"); + var result = _original.getJitFlags(ref jitFlags, sizeInBytes); + mc.recGetJitFlags(P(ref jitFlags), sizeInBytes, result); + return result; + } + + private CORINFO_WASM_TYPE_SYMBOL_STRUCT_* getWasmTypeSymbol(CorInfoWasmType* types, nuint typesSize) + { + AddCall("getWasmTypeSymbol"); + var temp = _original.getWasmTypeSymbol(types, typesSize); + mc.recGetWasmTypeSymbol(types, typesSize, temp); + return temp; + } + + private CORINFO_METHOD_STRUCT_* getSpecialCopyHelper(CORINFO_CLASS_STRUCT_* type) + { + AddCall("getSpecialCopyHelper"); + var temp = _original.getSpecialCopyHelper(type); + mc.recGetSpecialCopyHelper(type, temp); + return temp; + } +} diff --git a/src/coreclr/tools/superpmi/managed/superpmi-shim-collector/superpmi-shim-collector.csproj b/src/coreclr/tools/superpmi/managed/superpmi-shim-collector/superpmi-shim-collector.csproj new file mode 100644 index 00000000000000..fed2e59b178e21 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/superpmi-shim-collector/superpmi-shim-collector.csproj @@ -0,0 +1,7 @@ + + + + + superpmi-shim-collector + + diff --git a/src/coreclr/tools/superpmi/managed/superpmi-shim-counter/CorInfoImpl.Counter.cs b/src/coreclr/tools/superpmi/managed/superpmi-shim-counter/CorInfoImpl.Counter.cs new file mode 100644 index 00000000000000..4ada525b039cbe --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/superpmi-shim-counter/CorInfoImpl.Counter.cs @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using SuperPmi.Shim; + +namespace Internal.JitInterface; + +internal sealed partial class CorInfoImpl +{ + partial void OnCall(string name) => Counter.AddCall(name); +} diff --git a/src/coreclr/tools/superpmi/managed/superpmi-shim-counter/Counter.cs b/src/coreclr/tools/superpmi/managed/superpmi-shim-counter/Counter.cs new file mode 100644 index 00000000000000..161a122d5af2d4 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/superpmi-shim-counter/Counter.cs @@ -0,0 +1,68 @@ +// 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.IO; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Threading; +using Internal.JitInterface; + +namespace SuperPmi.Shim; + +// superpmi-shim-counter: a JIT that forwards the JIT-EE interface calls to the real JIT (SuperPMIShimPath), and +// counts them; the counts are written to a .csv file in SuperPMIShimLogPath when the shim is unloaded. +internal static unsafe class Counter +{ + private static MethodCallSummarizer s_summarizer; + + static Counter() => ForwardingShim.OnStartup = static () => + { + if (s_summarizer != null) + return; + + ShimEnvironment.SetLogPath(); + s_summarizer = new MethodCallSummarizer(ShimEnvironment.LogPath); + ForwardingShim.OnCall = s_summarizer.AddCall; + ShimInterop.Shim_SetUnloadCallback(&SaveTextFile); + }; + + public static void AddCall(string name) => s_summarizer.AddCall(name); + + [UnmanagedCallersOnly(EntryPoint = "jitStartup")] + private static void jitStartup(IntPtr host) => ForwardingShim.JitStartup(host); + + [UnmanagedCallersOnly(EntryPoint = "getJit")] + private static IntPtr getJit() => ForwardingShim.GetJit(); + + [UnmanagedCallersOnly] + private static void SaveTextFile() => s_summarizer.SaveTextFile(); +} + +internal sealed class MethodCallSummarizer +{ + private readonly string _dataFileName; + private readonly ConcurrentDictionary> _namesAndCounts = new(StringComparer.Ordinal); + + public MethodCallSummarizer(string logPath) + => _dataFileName = ShimEnvironment.GetResultFileName(logPath, ShimEnvironment.GetProcessCommandLine(), ".csv"); + + public void AddCall(string name) => Interlocked.Increment(ref _namesAndCounts.GetOrAdd(name, static _ => new StrongBox()).Value); + + public void SaveTextFile() + { + try + { + using var writer = new StreamWriter(_dataFileName); + writer.WriteLine("FunctionName,Count"); + foreach ((string name, StrongBox count) in _namesAndCounts.OrderBy(entry => entry.Key, StringComparer.Ordinal)) + writer.WriteLine($"{name},{count.Value}"); + } + catch (Exception e) when (e is IOException or UnauthorizedAccessException) + { + Logger.LogError($"Couldn't open file '{_dataFileName}': error {ErrorHandling.LastError(e)}"); + } + } +} diff --git a/src/coreclr/tools/superpmi/managed/superpmi-shim-counter/superpmi-shim-counter.csproj b/src/coreclr/tools/superpmi/managed/superpmi-shim-counter/superpmi-shim-counter.csproj new file mode 100644 index 00000000000000..7a9b65b481c876 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/superpmi-shim-counter/superpmi-shim-counter.csproj @@ -0,0 +1,13 @@ + + + + + superpmi-shim-counter + + + + + + + + diff --git a/src/coreclr/tools/superpmi/managed/superpmi-shim-simple/Simple.cs b/src/coreclr/tools/superpmi/managed/superpmi-shim-simple/Simple.cs new file mode 100644 index 00000000000000..716628bfde73e2 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/superpmi-shim-simple/Simple.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.InteropServices; + +namespace SuperPmi.Shim; + +// superpmi-shim-simple: a JIT that only forwards the JIT-EE interface calls to the real JIT (SuperPMIShimPath), +// to measure the cost of the shims. +internal static class Simple +{ + [UnmanagedCallersOnly(EntryPoint = "jitStartup")] + private static void jitStartup(IntPtr host) => ForwardingShim.JitStartup(host); + + [UnmanagedCallersOnly(EntryPoint = "getJit")] + private static IntPtr getJit() => ForwardingShim.GetJit(); +} diff --git a/src/coreclr/tools/superpmi/managed/superpmi-shim-simple/superpmi-shim-simple.csproj b/src/coreclr/tools/superpmi/managed/superpmi-shim-simple/superpmi-shim-simple.csproj new file mode 100644 index 00000000000000..2360124415f2b8 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/superpmi-shim-simple/superpmi-shim-simple.csproj @@ -0,0 +1,13 @@ + + + + + superpmi-shim-simple + + + + + + + + diff --git a/src/coreclr/tools/superpmi/managed/superpmi-tools.proj b/src/coreclr/tools/superpmi/managed/superpmi-tools.proj new file mode 100644 index 00000000000000..eff903025add18 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/superpmi-tools.proj @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/coreclr/tools/superpmi/managed/superpmi/CommandLine.cs b/src/coreclr/tools/superpmi/managed/superpmi/CommandLine.cs new file mode 100644 index 00000000000000..12b71183dd5d56 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/superpmi/CommandLine.cs @@ -0,0 +1,650 @@ +// 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.CommandLine; +using System.IO; +using System.Text; +using Internal.TypeSystem; + +namespace SuperPmi.Replay; + +internal sealed class Options +{ + public string nameOfJit; + public string nameOfJit2; + public string nameOfInputMethodContextFile; + public string verbosity; + public string writeLogFile; + public string reproName; + public bool breakOnError; + public bool breakOnAssert; + public bool breakOnException; + public bool ignoreStoredConfig; + public bool applyDiff; + public bool parallel; + public string streamFile; + public bool skipCleanup; + public int workerCount = -1; // -1 (or 1) means not to use parallel mode. + public int indexCount = -1; // With indexCount == -1 and no hash, everything is compiled. + public int failureLimit = -1; + public int repeatCount = 1; + public int[] indexes; + public string hash; + public string methodStatsTypes; + public string details; + public string mclFilename; + public string targetArchitecture; + public string compileList; + public int offset = -1; + public int increment = -1; + public LightWeightMap forceJitOptions; + public LightWeightMap forceJit2Options; + public LightWeightMap jitOptions; + public LightWeightMap jit2Options; +} + +// The SuperPMI command line: switches are matched case-insensitively, in order, mostly by any prefix +// of their name (so "-v" is "-verbosity" and "-p" is "-parallel"), and files are told apart by extension. +internal static class CommandLine +{ + // Parallel mode parses this to detect usage errors in the child processes. + public const string UsageFirstLine = "SuperPMI is a JIT compiler testing tool."; + + // CoreCLR's MAXIMUM_WAIT_OBJECTS. + private const int MaximumWaitObjects = 64; + + private const int MM3_HASH_BUFFER_SIZE = 33; + + private static readonly string s_sharedLibSuffix = OperatingSystem.IsWindows() ? ".dll" : OperatingSystem.IsMacOS() ? ".dylib" : ".so"; + + private static string DllName(string name) => OperatingSystem.IsWindows() ? name + ".dll" : "lib" + name + s_sharedLibSuffix; + + public static void DumpHelp(string program) + { + var help = new StringBuilder(); + void P(string line = "") => help.Append(line).Append('\n'); + + P(UsageFirstLine); + P(); + P($"Usage: {program} [options] [jitname] [jitname2] filename.mc"); + P($" jitname{s_sharedLibSuffix} - optional path of jit to be tested (default is JIT in same directory as {program})"); + P($" jitname2{s_sharedLibSuffix} - optional path of second jit to be tested"); + P(" filename.mc - load method contexts from filename.mc"); + P(" -j[it] Name - optionally -jit can be used to specify jits"); + P(" -l[oad] filename - optionally -load can be used to specify method contexts"); + P(); + P("Options:"); + P(); + P(" -boe"); + P(" Break on error return from compileMethod"); + P(); + P(" -boa"); + P(" Break on assert from the JIT"); + P(); + P(" -box"); + P(" Break on exception thrown, such as for missing data during replay"); + P(); + P(" -ignoreStoredConfig"); + P(" On replay, ignore any stored configuration variables. Useful for Checked/Release asm diffs."); + P(); + P(" -v[erbosity] messagetypes"); + P(" Controls which types of messages SuperPMI logs. Specify a string of"); + P(" characters representing message categories to enable, where:"); + P(" e - errors (internal fatal errors that are non-recoverable)"); + P(" w - warnings (internal conditions that are unusual, but not serious)"); + P(" m - missing (failures due to missing JIT-EE interface details)"); + P(" i - issues (issues found with the JIT, e.g. asm diffs, asserts)"); + P(" n - information (notifications/summaries, e.g. 'Loaded 5 Jitted 4 FailedCompile 1')"); + P(" v - verbose (status messages, e.g. 'Jit startup took '151.12ms')"); + P(" d - debug (lots of detailed output)"); + P(" a - all (enable all message types; overrides other enable message types)"); + P(" q - quiet (disable all output; overrides all others)"); + P(" e.g. '-v ew' only writes error and warning messages to the console."); + P(" 'q' takes precedence over any other message type specified."); + P(" Default set of messages enabled is 'ewminv'."); + P(); + P(" -w[riteLogFile] logfile"); + P(" Write log messages to the specified file."); + P(); + P(" -c[ompile] "); + P(" Compile only those method contexts whose indices are specified."); + P(" Indices can be either a single index, comma separated values,"); + P(" a range, or the name of a .MCL file with newline delimited indices."); + P(" e.g. -compile 20"); + P(" e.g. -compile 20,25,30,32"); + P(" e.g. -compile 10-99"); + P(" e.g. -compile 5,10-99,101,201-300"); + P(" e.g. -compile failed.mcl"); + P(); + P(" -m[atchHash] "); + P(" Compile only method context with specific MD5 hash"); + P(); + P(" -e[mitMethodStats] "); + P(" Emit method statistics in CSV format to filename.mc.stats."); + P(" Specify a string of characters representing statistics to emit, where:"); + P(" i - method IL code size"); + P(" a - method compiled ASM code size"); + P(" h - method hash to uniquely identify a method across MCH files"); + P(" n - method number inside the source MCH"); + P(" t - method throughput time"); + P(" * - all available method stats"); + P(); + P(" -details "); + P(" Emit detailed information about the replay/diff of each context into the specified file"); + P(); + P(" -a[pplyDiff]"); + P(" Compare the compile result generated from the provided JIT with the"); + P(" compile result stored with the MC. If two JITs are provided, this"); + P(" compares the compile results generated by the two JITs."); + P(); + P(" -r[eproName] prefix"); + P(" Write out failing methods to prefix-n.mc"); + P(); + P(" -f[ailingMCList] mclfilename"); + P(" Write out failing methods to mclfilename."); + P(" If using -applyDiff and no -diffMCList is specified,"); + P(" comparison failures also get written to mclfilename."); + P(); + P(" -diffMCList diffMCLfilename"); + P(" Write out methods that differ between compilations to diffMCLfilename."); + P(" This only works with -applyDiff."); + P(); + P(" -p[arallel] [workerCount]"); + P(" Run in parallel mode by spawning 'workerCount' processes to do processing."); + P(" If 'workerCount' is not specified, the number of workers used is"); + P(" the number of processors on the machine."); + P(); + P(" -streaming filename"); + P(" Streaming mode. Read and execute work requests from indicated file (can be 'stdin')."); + P(" Each line is a method context number and additional force jit options for that method."); + P(" Blank line or EOF terminates"); + P(); + P(" -failureLimit "); + P(" For a positive 'limit' number, replay and asm diffs will exit if it sees more than 'limit' failures."); + P(" Otherwise, all methods will be compiled."); + P(); + P(" -skipCleanup"); + P(" Skip deletion of temporary files created by child SuperPMI processes with -parallel."); + P(); + P(" -repeatCount "); + P(" Number of times compilation should repeat for each method context. Usually used when"); + P(" trying to measure JIT throughput for a specific set of methods. Default=1."); + P(); + P(" -target "); + P(" Specifies the target architecture if doing cross-compilation."); + P(" Allowed values: x64, x86, arm, arm64, loongarch64, riscv64, wasm"); + P(" Used by the assembly differences calculator; to determine a default JIT dll name;"); + P(" and to avoid treating mismatched cross-compilation replay as failure."); + P(); + P(" -coredistools"); + P(" Use disassembly tools from the CoreDisTools library"); + P(" Ignored: MSVCDIS is not available, so CoreDisTools will be used."); + P(); + P(" -jitoption [force] key=value"); + P(" Set the JIT option named \"key\" to \"value\" for JIT 1 if the option was not set."); + P(" With optional force flag overwrites the existing value if it was already set."); + P(" NOTE: do not use a \"DOTNET_\" prefix. \"key\" and \"value\" are case sensitive."); + P(" \"key#value\" is also accepted."); + P(); + P(" -jit2option [force] key=value"); + P(" Set the JIT option named \"key\" to \"value\" for JIT 2 if the option was not set."); + P(" With optional force flag overwrites the existing value if it was already set."); + P(" NOTE: do not use a \"DOTNET_\" prefix. \"key\" and \"value\" are case sensitive."); + P(" \"key#value\" is also accepted."); + P(); + P("Inputs are case sensitive."); + P(); + P("SuperPMI method contexts are stored in files with extension .MC, implying"); + P("a single method context, or .MCH, implying a set of method contexts. Either"); + P("extension works equivalently."); + P(); + P("Exit codes:"); + P("0 : success"); + P("-1 : general fatal error (e.g., failed to initialize, failed to read files)"); + P("-2 : JIT failed to initialize"); + P("1 : there were compilation failures"); + P("2 : there were assembly diffs"); + P("3 : there were missing values in method context"); + P(); + P("Examples:"); + P($" {program} {DllName("clrjit")} test.mch"); + P($" ; compile all functions in test.mch using {DllName("clrjit")}"); + P($" {program} -p {DllName("clrjit")} test.mch"); + P(" ; same as above, but use all available processors to compile in parallel"); + P($" {program} -f fail.mcl {DllName("clrjit")} test.mch"); + P(" ; if there are any failures, record their MC numbers in the file fail.mcl"); + + Logger.Out.Write(help.ToString()); + } + + // Splits "key=value" (or "key#value"). + public static bool ParseJitOption(string optionString, out string key, out string value) + { + int i = optionString.IndexOfAny(['=', '#']); + if (i < 0 || i >= 1023) + { + key = value = null; + return false; + } + + key = optionString.Substring(0, i); + value = optionString.Substring(i + 1); + return true; + } + + public static void AddJitOption(LightWeightMap map, string key, string value) + => map.Add(map.AddBuffer(NulTerminated(key)), map.AddBuffer(NulTerminated(value))); + + private static byte[] NulTerminated(string s) + { + byte[] bytes = new byte[Encoding.UTF8.GetByteCount(s) + 1]; + Encoding.UTF8.GetBytes(s, bytes); + return bytes; + } + + private enum Match + { + Prefix, // the argument is any prefix of the name + Full, // the argument starts with the whole name + Exact, + } + + private static readonly (string Name, Match Match)[] s_switches = + [ + ("help", Match.Prefix), ("HELP", Match.Prefix), ("?", Match.Prefix), ("load", Match.Prefix), ("jit", Match.Prefix), + ("reproName", Match.Prefix), ("failingMCList", Match.Prefix), ("target", Match.Full), ("boe", Match.Full), ("boa", Match.Full), + ("box", Match.Full), ("ignoreStoredConfig", Match.Full), ("verbosity", Match.Prefix), ("writeLogFile", Match.Prefix), + ("emitMethodStats", Match.Prefix), ("details", Match.Prefix), ("applyDiff", Match.Prefix), ("compile", Match.Prefix), + ("coredistools", Match.Prefix), ("matchHash", Match.Prefix), ("streaming", Match.Prefix), ("parallel", Match.Prefix), + ("failureLimit", Match.Prefix), ("skipCleanup", Match.Exact), ("repeatCount", Match.Exact), ("stride", Match.Prefix), + ("jitoption", Match.Prefix), ("jit2option", Match.Prefix), + ]; + + private static string FindSwitch(string arg) + { + foreach ((string name, Match match) in s_switches) + { + bool matches = match switch + { + Match.Prefix => name.StartsWith(arg, StringComparison.OrdinalIgnoreCase), + Match.Full => arg.StartsWith(name, StringComparison.OrdinalIgnoreCase), + _ => string.Equals(arg, name, StringComparison.OrdinalIgnoreCase), + }; + if (matches) + return name; + } + return null; + } + + // Like the C atoi: leading whitespace, an optional sign, then digits. + public static int Atoi(string s) + { + int i = 0; + while (i < s.Length && char.IsWhiteSpace(s[i])) + i++; + bool negative = i < s.Length && s[i] == '-'; + if (i < s.Length && (s[i] == '-' || s[i] == '+')) + i++; + long value = 0; + for (; i < s.Length && char.IsAsciiDigit(s[i]); i++) + value = unchecked(value * 10 + (s[i] - '0')); + return unchecked((int)(negative ? -value : value)); + } + + private static bool AllDigits(string s) + { + foreach (char c in s) + { + if (!char.IsAsciiDigit(c)) + return false; + } + return true; + } + + public static bool Parse(string[] argv, Options o) + { + string program = argv[0]; + bool foundJit = false; + + bool Fail(string error = null) + { + if (error != null) + Logger.LogError(error); + DumpHelp(program); + return false; + } + + if (argv.Length == 1) // Print the help when no arguments are passed. + return Fail(); + + for (int i = 1; i < argv.Length; i++) + { + string arg = argv[i]; + bool isASwitch = arg.StartsWith('-') || (OperatingSystem.IsWindows() && arg.StartsWith('/')); + + if (!isASwitch) + { + // Process an input file name. Extensions are compared case-insensitively, since this runs on Windows. + int lastdot = arg.LastIndexOf('.'); + if (lastdot < 0) + return Fail(); + + string extension = arg.Substring(lastdot); + if (string.Equals(extension, s_sharedLibSuffix, StringComparison.OrdinalIgnoreCase)) + { + if (!SetJit(arg)) + return false; + } + else if (extension.Equals(".mc", StringComparison.OrdinalIgnoreCase) || extension.Equals(".mch", StringComparison.OrdinalIgnoreCase) || + extension.Equals(".mct", StringComparison.OrdinalIgnoreCase)) + { + o.nameOfInputMethodContextFile = arg; + } + else + { + return Fail($"Unknown file type passed as argument, '{arg}'."); + } + continue; + } + + if (arg.Length == 1) + return Fail(); + + bool NextArg(out string value) + { + value = ++i < argv.Length ? argv[i] : null; + return value != null; + } + + string value; + switch (FindSwitch(arg.Substring(1))) + { + case "help" or "HELP" or "?": + return Fail(); + + case "load": + if (!NextArg(out value)) + return Fail(); + if (value.Length == 0) + return Fail($"Arg '{value}' is invalid, name of file missing."); + o.nameOfInputMethodContextFile = value; + break; + + case "jit": + if (!NextArg(out value)) + return Fail(); + if (!SetJit(value)) + return false; + break; + + case "reproName": + if (!NextArg(out value)) + return Fail(); + if (value.Length == 0) + return Fail($"Arg '{value}' is invalid, name of prefix missing."); + o.reproName = value; + break; + + case "failingMCList": + if (!NextArg(out o.mclFilename)) + return Fail(); + break; + + case "target": + if (!NextArg(out o.targetArchitecture)) + return Fail(); + break; + + case "boe": + o.breakOnError = true; + break; + + case "boa": + o.breakOnAssert = true; + break; + + case "box": + o.breakOnException = true; + break; + + case "ignoreStoredConfig": + o.ignoreStoredConfig = true; + break; + + case "verbosity": + if (!NextArg(out o.verbosity)) + return Fail(); + Logger.SetLogLevel(Logger.ParseLogLevelString(o.verbosity)); + break; + + case "writeLogFile": + if (!NextArg(out o.writeLogFile)) + return Fail(); + Logger.OpenLogFile(o.writeLogFile); + break; + + case "emitMethodStats": + if (!NextArg(out o.methodStatsTypes)) + return Fail(); + break; + + case "details": + if (!NextArg(out o.details)) + return Fail(); + break; + + case "applyDiff": + o.applyDiff = true; + break; + + case "compile": + if (!NextArg(out value)) + return Fail(); + if (!MCList.TryParse(value, out o.indexes, out string error)) + { + if (error != null) + Logger.LogError(error); + return Fail($"Arg '{value}' is invalid, needed method context list."); + } + o.indexCount = o.indexes.Length; + if (o.hash != null) + return Fail("Cannot use both method context list and method context hash."); + if (o.offset > 0 && o.increment > 0) + return Fail("Cannot use method context list in parallel mode."); + o.compileList = value; // Saved for -parallel. + break; + + case "coredistools": + // CoreDisTools is always used, so the switch is allowed and ignored. + break; + + case "matchHash": + if (!NextArg(out value)) + return Fail(); + if (value.Length != MM3_HASH_BUFFER_SIZE - 1) + return Fail($"Arg '{value}' is invalid, needed a valid method context hash."); + if (o.indexCount > 0) + return Fail("Cannot use both method context list and method context hash."); + if (o.offset > 0 && o.increment > 0) + return Fail("Cannot use method context hash in parallel mode."); + o.hash = value; + break; + + case "streaming": + if (!NextArg(out o.streamFile)) + return Fail("'-streaming' must be followed by a file name or 'stdin'."); + break; + + case "parallel": + o.parallel = true; + + // Is the next argument a worker count? + if (i + 1 < argv.Length && AllDigits(argv[i + 1])) + { + o.workerCount = Atoi(argv[++i]); + if (o.workerCount < 1) + return Fail("Invalid workers count specified, workers count must be at least 1."); + if (o.workerCount > MaximumWaitObjects) + return Fail($"Invalid workers count specified, workers count cannot be more than {MaximumWaitObjects}."); + } + break; + + case "failureLimit": + if (!NextArg(out value)) + return Fail(); + o.failureLimit = Atoi(value); + if (o.failureLimit < 1) + return Fail("Incorrect limit specified for -failureLimit. Limit must be > 0."); + break; + + case "skipCleanup": + o.skipCleanup = true; + break; + + case "repeatCount": + if (!NextArg(out value)) + return Fail(); + o.repeatCount = AllDigits(value) ? Atoi(value) : 0; + if (o.repeatCount < 1) + return Fail("Invalid repeat count specified. Repeat count must be between 1 and INT_MAX."); + break; + + case "stride": + // An internal switch used by -parallel: "-stride offset increment" compiles the methods + // offset, offset+increment, offset+2*increment, ... until the end of the file. + if (!NextArg(out value)) + return Fail(); + o.offset = Atoi(value); + if (!NextArg(out value)) + return Fail(); + o.increment = Atoi(value); + if (o.offset < 1 || o.increment < 1) + return Fail("Incorrect offset/increment specified for -stride. Offset and increment both must be > 0."); + if (o.indexCount > 0) + return Fail("Cannot use method context list in parallel mode."); + if (o.hash != null) + return Fail("Cannot use method context hash in parallel mode."); + break; + + case "jitoption": + if (!AddJitOption(argv, ref i, ref o.jitOptions, ref o.forceJitOptions)) + return Fail(); + break; + + case "jit2option": + if (!AddJitOption(argv, ref i, ref o.jit2Options, ref o.forceJit2Options)) + return Fail(); + break; + + default: + return Fail($"Unknown switch '{arg}' passed as argument."); + } + } + + bool SetJit(string name) + { + if (name.Length == 0) + return Fail($"Arg '{name}' is invalid, name of jit missing."); + if (!foundJit) + { + o.nameOfJit = name; + foundJit = true; + } + else + { + if (o.nameOfJit2 != null) + return Fail("Too many JITs specified."); + o.nameOfJit2 = name; + } + return true; + } + + // Do some argument validation. + if (o.targetArchitecture != null && Helpers.TryGetTargetArchitecture(o.targetArchitecture) == null) + return Fail("Illegal target architecture specified with -target."); + + if (o.streamFile != null) + { + if (o.parallel) + { + Logger.LogError("streaming mode and parallel mode are incompatible."); + return false; + } + if (o.nameOfJit2 != null) + { + Logger.LogError("streaming mode and diff mode are incompatible."); + return false; + } + } + + TargetArchitecture defaultSpmiTargetArchitecture = SpmiUtil.GetSpmiTargetArchitecture(); + if (o.targetArchitecture != null) + SpmiUtil.SetSpmiTargetArchitecture(Helpers.TryGetTargetArchitecture(o.targetArchitecture).Value); + + if (o.nameOfInputMethodContextFile == null) + return Fail("Missing name of an input file."); + + if (o.nameOfJit == null) + { + o.nameOfJit = GetDefaultJit(program, defaultSpmiTargetArchitecture); + if (o.nameOfJit == null) + return Fail("Missing name of a Jit."); + Logger.LogInfo($"Using default JIT: {o.nameOfJit}"); + } + + if (o.skipCleanup && !o.parallel) + return Fail("-skipCleanup requires -parallel."); + + return true; + } + + // "-jitoption [force] key=value" + private static bool AddJitOption(string[] argv, ref int i, ref LightWeightMap jitOptions, ref LightWeightMap forceJitOptions) + { + if (++i >= argv.Length) + return false; + + LightWeightMap target; + if ("force".StartsWith(argv[i], StringComparison.OrdinalIgnoreCase)) + { + target = forceJitOptions ??= new LightWeightMap(); + i++; + } + else + { + target = jitOptions ??= new LightWeightMap(); + } + + if (i >= argv.Length || !ParseJitOption(argv[i], out string key, out string value)) + return false; + + AddJitOption(target, key, value); + return true; + } + + // The JIT next to superpmi for the target: clrjit when it's the host, and otherwise a cross-targeting JIT + // such as clrjit_universal_arm64_x64. SuperPMI doesn't know about the target OS, so the host's is assumed. + private static string GetDefaultJit(string program, TargetArchitecture defaultTargetArchitecture) + { + TargetArchitecture target = SpmiUtil.GetSpmiTargetArchitecture(); + int lastSlash = program.LastIndexOf(Path.DirectorySeparatorChar); + if (defaultTargetArchitecture == TargetArchitecture.Wasm32 || target == TargetArchitecture.Wasm32 || lastSlash < 0) + return null; + + string jitName = "clrjit"; + if (defaultTargetArchitecture != target) + { + string jitOSName = target switch + { + TargetArchitecture.X64 or TargetArchitecture.X86 => OperatingSystem.IsWindows() ? "win" : "unix", + TargetArchitecture.ARM or TargetArchitecture.ARM64 => "universal", + _ => "unix", + }; + // The JIT names have the TargetArchitecture names in lowercase, such as clrjit_universal_arm64_x64. + jitName = $"clrjit_{jitOSName}_{target.ToString().ToLowerInvariant()}_{defaultTargetArchitecture.ToString().ToLowerInvariant()}"; + } + + return program.Substring(0, lastSlash) + Path.DirectorySeparatorChar + DllName(jitName); + } +} diff --git a/src/coreclr/tools/superpmi/managed/superpmi/CorInfoImpl.SuperPmi.cs b/src/coreclr/tools/superpmi/managed/superpmi/CorInfoImpl.SuperPmi.cs new file mode 100644 index 00000000000000..8ab555128d2371 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/superpmi/CorInfoImpl.SuperPmi.cs @@ -0,0 +1,1323 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Runtime.ExceptionServices; +using System.Runtime.InteropServices; +using System.Text; +using Internal.Pgo; +using SuperPmi; +using SuperPmi.Replay; + +namespace Internal.JitInterface; + +// The JIT-EE interface for replay: answers the JIT's queries from the method context being replayed, and +// records what the JIT reports into its compile result. +internal sealed unsafe partial class CorInfoImpl +{ + private readonly JitInstance jitInstance; + private readonly List<(IntPtr Native, Exception Managed)> _exceptions = []; + private int m_metricSearchStart; + + public CorInfoImpl(JitInstance jitInstance) => this.jitInstance = jitInstance; + + private MethodContext mc => jitInstance.mc; + + private CompileResult cr => jitInstance.mc.cr; + + private static CorInfoImpl GetThis(IntPtr thisHandle) => Unsafe.Read((void*)thisHandle); + + // Rethrown through the JIT as a C++ exception, whose kind decides the error traps that catch it. + private IntPtr AllocException(Exception ex) + { + SpmiJitInterface.ExceptionKind kind = ex switch + { + SpmiException { Code: ExceptionCodes.RECORDED_EXCEPTION } => SpmiJitInterface.ExceptionKind.EEException, + SpmiException => SpmiJitInterface.ExceptionKind.SuperPmiException, + _ => SpmiJitInterface.ExceptionKind.HostFailure, + }; + IntPtr nativeException = SpmiJitInterface.AllocException(kind); + _exceptions.Add((nativeException, ex)); + return nativeException; + } + + // Compiles the method, rethrowing any exception that escaped the JIT. + public CorJitResult CompileMethod(IntPtr jit, CORINFO_METHOD_INFO* info, uint flags, out byte* nativeEntry, out uint nativeSizeOfCode) + { + CorInfoImpl _this = this; + IntPtr exception; + uint exceptionCode; + byte* entry; + uint size; + CorJitResult result = SpmiJitInterface.JitCompileMethod(&exception, &exceptionCode, jit, (IntPtr)Unsafe.AsPointer(ref _this), + GetUnmanagedCallbacks(), info, flags, &entry, &size); + + Exception escaped = null; + foreach ((IntPtr native, Exception managed) in _exceptions) + { + if (native == exception) + escaped = managed; + SpmiJitInterface.FreeException(native); + } + _exceptions.Clear(); + + if (escaped != null) + ExceptionDispatchInfo.Throw(escaped); + if (exceptionCode != 0) + throw new NativeException(exceptionCode); + + nativeEntry = entry; + nativeSizeOfCode = size; + return result; + } + + private void AddCall(string name) => cr.AddCall(name); + + // Rethrows an exception that the EE threw during recording. The JIT doesn't look closely at the exceptions + // that the EE throws, so changing their code is fine. + private static void ThrowRecordedException(uint innerExceptionCode) + { + if (SpmiUtil.BreakOnException) + System.Diagnostics.Debugger.Break(); + throw new SpmiException(ExceptionCodes.RECORDED_EXCEPTION, $"Recorded exception 0x{innerExceptionCode:x}"); + } + + private static T* P(ref T value) where T : unmanaged => (T*)Unsafe.AsPointer(ref value); + + private static nuint AlignUp(nuint value, nuint alignment) => (value + (alignment - 1)) & ~(alignment - 1); + + private bool isIntrinsic(CORINFO_METHOD_STRUCT_* ftn) + { + AddCall("isIntrinsic"); + return mc.repIsIntrinsic(ftn); + } + + private bool canValueClassInstancePointerEscape(CORINFO_METHOD_STRUCT_* ftn) + { + AddCall("canValueClassInstancePointerEscape"); + return mc.repCanValueClassInstancePointerEscape(ftn); + } + + private bool notifyMethodInfoUsage(CORINFO_METHOD_STRUCT_* ftn) + { + AddCall("notifyMethodInfoUsage"); + return mc.repNotifyMethodInfoUsage(ftn); + } + + private uint getMethodAttribs(CORINFO_METHOD_STRUCT_* ftn) + { + AddCall("getMethodAttribs"); + return mc.repGetMethodAttribs(ftn); + } + + private void setMethodAttribs(CORINFO_METHOD_STRUCT_* ftn, CorInfoMethodRuntimeFlags attribs) + { + AddCall("setMethodAttribs"); + cr.recSetMethodAttribs(ftn, attribs); + } + + private void getMethodSig(CORINFO_METHOD_STRUCT_* ftn, CORINFO_SIG_INFO* sig, CORINFO_CLASS_STRUCT_* memberParent) + { + AddCall("getMethodSig"); + mc.repGetMethodSig(ftn, sig, memberParent); + } + + private bool getMethodInfo(CORINFO_METHOD_STRUCT_* ftn, CORINFO_METHOD_INFO* info, CORINFO_CONTEXT_STRUCT* context) + { + AddCall("getMethodInfo"); + bool value = mc.repGetMethodInfo(ftn, info, context, out uint exceptionCode); + if (exceptionCode != 0) + ThrowRecordedException(exceptionCode); + return value; + } + + private bool haveSameMethodDefinition(CORINFO_METHOD_STRUCT_* meth1Hnd, CORINFO_METHOD_STRUCT_* meth2Hnd) + { + AddCall("haveSameMethodDefinition"); + return mc.repHaveSameMethodDefinition(meth1Hnd, meth2Hnd); + } + + private CORINFO_CLASS_STRUCT_* getTypeDefinition(CORINFO_CLASS_STRUCT_* type) + { + AddCall("getTypeDefinition"); + return mc.repGetTypeDefinition(type); + } + + private CorInfoInline canInline(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* calleeHnd) + { + AddCall("canInline"); + uint exceptionCode = 0; + CorInfoInline result = mc.repCanInline(callerHnd, calleeHnd, ref exceptionCode); + if (exceptionCode != 0) + ThrowRecordedException(exceptionCode); + return result; + } + + private void beginInlining(CORINFO_METHOD_STRUCT_* inlinerHnd, CORINFO_METHOD_STRUCT_* inlineeHnd) + { + } + + private void reportInliningDecision(CORINFO_METHOD_STRUCT_* inlinerHnd, CORINFO_METHOD_STRUCT_* inlineeHnd, CorInfoInline inlineResult, byte* reason) + { + AddCall("reportInliningDecision"); + cr.recReportInliningDecision(inlinerHnd, inlineeHnd, inlineResult, reason); + } + + private bool canTailCall(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* declaredCalleeHnd, CORINFO_METHOD_STRUCT_* exactCalleeHnd, bool fIsTailPrefix) + { + AddCall("canTailCall"); + return mc.repCanTailCall(callerHnd, declaredCalleeHnd, exactCalleeHnd, fIsTailPrefix); + } + + private void reportTailCallDecision(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* calleeHnd, bool fIsTailPrefix, CorInfoTailCall tailCallResult, byte* reason) + { + AddCall("reportTailCallDecision"); + cr.recReportTailCallDecision(callerHnd, calleeHnd, fIsTailPrefix, tailCallResult, reason); + } + + private void getEHinfo(CORINFO_METHOD_STRUCT_* ftn, uint EHnumber, ref CORINFO_EH_CLAUSE clause) + { + AddCall("getEHinfo"); + mc.repGetEHinfo(ftn, EHnumber, P(ref clause)); + } + + private CORINFO_CLASS_STRUCT_* getMethodClass(CORINFO_METHOD_STRUCT_* method) + { + AddCall("getMethodClass"); + return mc.repGetMethodClass(method); + } + + private void getMethodVTableOffset(CORINFO_METHOD_STRUCT_* method, ref uint offsetOfIndirection, ref uint offsetAfterIndirection, ref bool isRelative) + { + AddCall("getMethodVTableOffset"); + mc.repGetMethodVTableOffset(method, P(ref offsetOfIndirection), P(ref offsetAfterIndirection), P(ref isRelative)); + } + + private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) + { + AddCall("resolveVirtualMethod"); + return mc.repResolveVirtualMethod(info); + } + + private CORINFO_METHOD_STRUCT_* getAsyncOtherVariant(CORINFO_METHOD_STRUCT_* ftn, ref bool variantIsThunk) + { + AddCall("getAsyncOtherVariant"); + return mc.repGetAsyncOtherVariant(ftn, P(ref variantIsThunk)); + } + + private CORINFO_CLASS_STRUCT_* getDefaultComparerClass(CORINFO_CLASS_STRUCT_* elemType) + { + AddCall("getDefaultComparerClass"); + return mc.repGetDefaultComparerClass(elemType); + } + + private CORINFO_CLASS_STRUCT_* getDefaultEqualityComparerClass(CORINFO_CLASS_STRUCT_* elemType) + { + AddCall("getDefaultEqualityComparerClass"); + return mc.repGetDefaultEqualityComparerClass(elemType); + } + + private CORINFO_CLASS_STRUCT_* getSZArrayHelperEnumeratorClass(CORINFO_CLASS_STRUCT_* elemType) + { + AddCall("getSZArrayHelperEnumeratorClass"); + return mc.repGetSZArrayHelperEnumeratorClass(elemType); + } + + private void expandRawHandleIntrinsic(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_GENERICHANDLE_RESULT pResult) + { + AddCall("expandRawHandleIntrinsic"); + mc.repExpandRawHandleIntrinsic(P(ref pResolvedToken), callerHandle, P(ref pResult)); + } + + private bool isIntrinsicType(CORINFO_CLASS_STRUCT_* classHnd) + { + AddCall("isIntrinsicType"); + return mc.repIsIntrinsicType(classHnd); + } + + private CorInfoCallConvExtension getUnmanagedCallConv(CORINFO_METHOD_STRUCT_* method, CORINFO_SIG_INFO* callSiteSig, ref bool pSuppressGCTransition) + { + AddCall("getUnmanagedCallConv"); + return mc.repGetUnmanagedCallConv(method, callSiteSig, P(ref pSuppressGCTransition)); + } + + private bool pInvokeMarshalingRequired(CORINFO_METHOD_STRUCT_* method, CORINFO_SIG_INFO* callSiteSig) + { + AddCall("pInvokeMarshalingRequired"); + return mc.repPInvokeMarshalingRequired(method, callSiteSig); + } + + private bool satisfiesMethodConstraints(CORINFO_CLASS_STRUCT_* parent, CORINFO_METHOD_STRUCT_* method) + { + AddCall("satisfiesMethodConstraints"); + return mc.repSatisfiesMethodConstraints(parent, method); + } + + private void getGSCookie(IntPtr* pCookieVal, IntPtr** ppCookieVal) + { + AddCall("getGSCookie"); + mc.repGetGSCookie(pCookieVal, (nint**)ppCookieVal); + } + + private void setPatchpointInfo(PatchpointInfo* patchpointInfo) + { + AddCall("setPatchpointInfo"); + cr.recSetPatchpointInfo(patchpointInfo); + freeArray(patchpointInfo); // Ownership of the array is ours. + } + + private PatchpointInfo* getOSRInfo(ref uint ilOffset) + { + AddCall("getOSRInfo"); + return mc.repGetOSRInfo(P(ref ilOffset)); + } + + private void resolveToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken) + { + AddCall("resolveToken"); + mc.repResolveToken(P(ref pResolvedToken), out uint exceptionCode); + if (exceptionCode != 0) + ThrowRecordedException(exceptionCode); + } + + private void findSig(CORINFO_MODULE_STRUCT_* module, uint sigTOK, CORINFO_CONTEXT_STRUCT* context, CORINFO_SIG_INFO* sig) + { + AddCall("findSig"); + mc.repFindSig(module, sigTOK, context, sig); + } + + private void findCallSiteSig(CORINFO_MODULE_STRUCT_* module, uint methTOK, CORINFO_CONTEXT_STRUCT* context, CORINFO_SIG_INFO* sig) + { + AddCall("findCallSiteSig"); + mc.repFindCallSiteSig(module, methTOK, context, sig); + } + + private CORINFO_CLASS_STRUCT_* getTokenTypeAsHandle(ref CORINFO_RESOLVED_TOKEN pResolvedToken) + { + AddCall("getTokenTypeAsHandle"); + return mc.repGetTokenTypeAsHandle(P(ref pResolvedToken)); + } + + private int getStringLiteral(CORINFO_MODULE_STRUCT_* module, uint metaTOK, char* buffer, int bufferSize, int startIndex) + { + AddCall("getStringLiteral"); + return mc.repGetStringLiteral(module, metaTOK, buffer, bufferSize, startIndex); + } + + private nuint printObjectDescription(CORINFO_OBJECT_STRUCT_* handle, byte* buffer, nuint bufferSize, nuint* pRequiredBufferSize) + { + AddCall("printObjectDescription"); + return mc.repPrintObjectDescription(handle, buffer, bufferSize, pRequiredBufferSize); + } + + private CorInfoType asCorInfoType(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("asCorInfoType"); + return mc.repAsCorInfoType(cls); + } + + private byte* getClassNameFromMetadata(CORINFO_CLASS_STRUCT_* cls, byte** namespaceName) + { + AddCall("getClassNameFromMetadata"); + return mc.repGetClassNameFromMetadata(cls, namespaceName); + } + + private CORINFO_CLASS_STRUCT_* getTypeInstantiationArgument(CORINFO_CLASS_STRUCT_* cls, uint index) + { + AddCall("getTypeInstantiationArgument"); + return mc.repGetTypeInstantiationArgument(cls, index); + } + + private CORINFO_CLASS_STRUCT_* getMethodInstantiationArgument(CORINFO_METHOD_STRUCT_* ftn, uint index) + { + AddCall("getMethodInstantiationArgument"); + return mc.repGetMethodInstantiationArgument(ftn, index); + } + + private nuint printClassName(CORINFO_CLASS_STRUCT_* cls, byte* buffer, nuint bufferSize, nuint* pRequiredBufferSize) + { + AddCall("printClassName"); + return mc.repPrintClassName(cls, buffer, bufferSize, pRequiredBufferSize); + } + + private bool isValueClass(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("isValueClass"); + return mc.repIsValueClass(cls); + } + + private bool isByRefLike(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("isByRefLike"); + return mc.repIsByRefLike(cls); + } + + private bool isSharedInst(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("isSharedInst"); + return mc.repIsSharedInst(cls); + } + + private uint getClassAttribs(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("getClassAttribs"); + return mc.repGetClassAttribs(cls); + } + + private byte* getClassAssemblyName(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("getClassAssemblyName"); + return mc.repGetClassAssemblyName(cls); + } + + private void* LongLifetimeMalloc(nuint sz) + { + AddCall("LongLifetimeMalloc"); + Logger.LogError("Hit unimplemented LongLifetimeMalloc"); + SpmiUtil.DebugBreakorAV(32); + return null; + } + + private void LongLifetimeFree(void* obj) + { + AddCall("LongLifetimeFree"); + Logger.LogError("Hit unimplemented LongLifetimeFree"); + SpmiUtil.DebugBreakorAV(33); + } + + private bool getIsClassInitedFlagAddress(CORINFO_CLASS_STRUCT_* cls, ref CORINFO_CONST_LOOKUP addr, ref int offset) + { + AddCall("getIsClassInitedFlagAddress"); + return mc.repGetIsClassInitedFlagAddress(cls, P(ref addr), P(ref offset)); + } + + private void* getClassThreadStaticDynamicInfo(CORINFO_CLASS_STRUCT_* clr) + { + AddCall("getClassThreadStaticDynamicInfo"); + return mc.repGetClassThreadStaticDynamicInfo(clr); + } + + private void* getClassStaticDynamicInfo(CORINFO_CLASS_STRUCT_* clr) + { + AddCall("getClassStaticDynamicInfo"); + return mc.repGetClassStaticDynamicInfo(clr); + } + + private bool getStaticBaseAddress(CORINFO_CLASS_STRUCT_* cls, bool isGc, ref CORINFO_CONST_LOOKUP addr) + { + AddCall("getStaticBaseAddress"); + return mc.repGetStaticBaseAddress(cls, isGc, P(ref addr)); + } + + private uint getClassSize(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("getClassSize"); + return mc.repGetClassSize(cls); + } + + private uint getHeapClassSize(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("getHeapClassSize"); + return mc.repGetHeapClassSize(cls); + } + + private bool canAllocateOnStack(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("canAllocateOnStack"); + return mc.repCanAllocateOnStack(cls); + } + + private uint getClassAlignmentRequirement(CORINFO_CLASS_STRUCT_* cls, bool fDoubleAlignHint) + { + AddCall("getClassAlignmentRequirement"); + return mc.repGetClassAlignmentRequirement(cls, fDoubleAlignHint); + } + + private uint getClassGClayout(CORINFO_CLASS_STRUCT_* cls, byte* gcPtrs) + { + AddCall("getClassGClayout"); + return mc.repGetClassGClayout(cls, gcPtrs); + } + + private uint getClassNumInstanceFields(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("getClassNumInstanceFields"); + return mc.repGetClassNumInstanceFields(cls); + } + + private CORINFO_FIELD_STRUCT_* getFieldInClass(CORINFO_CLASS_STRUCT_* clsHnd, int num) + { + AddCall("getFieldInClass"); + return mc.repGetFieldInClass(clsHnd, num); + } + + private GetTypeLayoutResult getTypeLayout(CORINFO_CLASS_STRUCT_* typeHnd, CORINFO_TYPE_LAYOUT_NODE* treeNodes, nuint* numTreeNodes) + { + AddCall("getTypeLayout"); + return mc.repGetTypeLayout(typeHnd, treeNodes, numTreeNodes); + } + + private bool checkMethodModifier(CORINFO_METHOD_STRUCT_* hMethod, byte* modifier, bool fOptional) + { + AddCall("checkMethodModifier"); + return mc.repCheckMethodModifier(hMethod, modifier, fOptional); + } + + private CorInfoHelpFunc getNewHelper(CORINFO_CLASS_STRUCT_* classHandle, ref bool pHasSideEffects) + { + AddCall("getNewHelper"); + CorInfoHelpFunc result = mc.repGetNewHelper(classHandle, P(ref pHasSideEffects), out uint exceptionCode); + if (exceptionCode != 0) + ThrowRecordedException(exceptionCode); + return result; + } + + private CorInfoHelpFunc getNewArrHelper(CORINFO_CLASS_STRUCT_* arrayCls) + { + AddCall("getNewArrHelper"); + return mc.repGetNewArrHelper(arrayCls); + } + + private CorInfoHelpFunc getCastingHelper(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool fThrowing) + { + AddCall("getCastingHelper"); + return mc.repGetCastingHelper(P(ref pResolvedToken), fThrowing); + } + + private CorInfoHelpFunc getSharedCCtorHelper(CORINFO_CLASS_STRUCT_* clsHnd) + { + AddCall("getSharedCCtorHelper"); + return mc.repGetSharedCCtorHelper(clsHnd); + } + + private CORINFO_CLASS_STRUCT_* getTypeForBox(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("getTypeForBox"); + return mc.repGetTypeForBox(cls); + } + + private CorInfoHelpFunc getBoxHelper(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("getBoxHelper"); + return mc.repGetBoxHelper(cls); + } + + private CorInfoHelpFunc getUnBoxHelper(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("getUnBoxHelper"); + return mc.repGetUnBoxHelper(cls); + } + + private CORINFO_OBJECT_STRUCT_* getRuntimeTypePointer(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("getRuntimeTypePointer"); + return mc.repGetRuntimeTypePointer(cls); + } + + private bool isObjectImmutable(CORINFO_OBJECT_STRUCT_* objPtr) + { + AddCall("isObjectImmutable"); + return mc.repIsObjectImmutable(objPtr); + } + + private bool getStringChar(CORINFO_OBJECT_STRUCT_* strObj, int index, ushort* value) + { + AddCall("getStringChar"); + return mc.repGetStringChar(strObj, index, value); + } + + private CORINFO_CLASS_STRUCT_* getObjectType(CORINFO_OBJECT_STRUCT_* objPtr) + { + AddCall("getObjectType"); + return mc.repGetObjectType(objPtr); + } + + private bool getReadyToRunHelper(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CorInfoHelpFunc id, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_CONST_LOOKUP pLookup) + { + AddCall("getReadyToRunHelper"); + return mc.repGetReadyToRunHelper(P(ref pResolvedToken), id, callerHandle, P(ref pLookup)); + } + + private void getReadyToRunDelegateCtorHelper(ref CORINFO_RESOLVED_TOKEN pTargetMethod, mdToken targetConstraint, CORINFO_CLASS_STRUCT_* delegateType, + CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_LOOKUP pLookup) + { + AddCall("getReadyToRunDelegateCtorHelper"); + mc.repGetReadyToRunDelegateCtorHelper(P(ref pTargetMethod), targetConstraint, delegateType, callerHandle, P(ref pLookup)); + } + + private CorInfoInitClassResult initClass(CORINFO_FIELD_STRUCT_* field, CORINFO_METHOD_STRUCT_* method, CORINFO_CONTEXT_STRUCT* context) + { + AddCall("initClass"); + return mc.repInitClass(field, method, context); + } + + private CORINFO_CLASS_STRUCT_* getBuiltinClass(CorInfoClassId classId) + { + AddCall("getBuiltinClass"); + return mc.repGetBuiltinClass(classId); + } + + private CorInfoType getTypeForPrimitiveValueClass(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("getTypeForPrimitiveValueClass"); + return mc.repGetTypeForPrimitiveValueClass(cls); + } + + private CorInfoType getTypeForPrimitiveNumericClass(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("getTypeForPrimitiveNumericClass"); + return mc.repGetTypeForPrimitiveNumericClass(cls); + } + + private bool canCast(CORINFO_CLASS_STRUCT_* child, CORINFO_CLASS_STRUCT_* parent) + { + AddCall("canCast"); + return mc.repCanCast(child, parent); + } + + private TypeCompareState compareTypesForCast(CORINFO_CLASS_STRUCT_* fromClass, CORINFO_CLASS_STRUCT_* toClass) + { + AddCall("compareTypesForCast"); + return mc.repCompareTypesForCast(fromClass, toClass); + } + + private TypeCompareState compareTypesForEquality(CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2) + { + AddCall("compareTypesForEquality"); + return mc.repCompareTypesForEquality(cls1, cls2); + } + + private bool isMoreSpecificType(CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2) + { + AddCall("isMoreSpecificType"); + return mc.repIsMoreSpecificType(cls1, cls2); + } + + private bool isExactType(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("isExactType"); + return mc.repIsExactType(cls); + } + + private TypeCompareState isGenericType(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("isGenericType"); + return mc.repIsGenericType(cls); + } + + private TypeCompareState isNullableType(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("isNullableType"); + return mc.repIsNullableType(cls); + } + + private TypeCompareState isEnum(CORINFO_CLASS_STRUCT_* cls, CORINFO_CLASS_STRUCT_** underlyingType) + { + AddCall("isEnum"); + return mc.repIsEnum(cls, underlyingType); + } + + private CORINFO_CLASS_STRUCT_* getParentType(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("getParentType"); + return mc.repGetParentType(cls); + } + + private CorInfoType getChildType(CORINFO_CLASS_STRUCT_* clsHnd, CORINFO_CLASS_STRUCT_** clsRet) + { + AddCall("getChildType"); + return mc.repGetChildType(clsHnd, clsRet); + } + + private bool isSDArray(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("isSDArray"); + return mc.repIsSDArray(cls); + } + + private uint getArrayRank(CORINFO_CLASS_STRUCT_* cls) + { + AddCall("getArrayRank"); + return mc.repGetArrayRank(cls); + } + + private CorInfoArrayIntrinsic getArrayIntrinsicID(CORINFO_METHOD_STRUCT_* ftn) + { + AddCall("getArrayIntrinsicID"); + return mc.repGetArrayIntrinsicID(ftn); + } + + private void* getArrayInitializationData(CORINFO_FIELD_STRUCT_* field, uint size) + { + AddCall("getArrayInitializationData"); + return mc.repGetArrayInitializationData(field, size); + } + + private CorInfoIsAccessAllowedResult canAccessClass(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_HELPER_DESC pAccessHelper) + { + AddCall("canAccessClass"); + return mc.repCanAccessClass(P(ref pResolvedToken), callerHandle, P(ref pAccessHelper)); + } + + private nuint printFieldName(CORINFO_FIELD_STRUCT_* field, byte* buffer, nuint bufferSize, nuint* pRequiredBufferSize) + { + AddCall("printFieldName"); + return mc.repPrintFieldName(field, buffer, bufferSize, pRequiredBufferSize); + } + + private CORINFO_CLASS_STRUCT_* getFieldClass(CORINFO_FIELD_STRUCT_* field) + { + AddCall("getFieldClass"); + return mc.repGetFieldClass(field); + } + + private CorInfoType getFieldType(CORINFO_FIELD_STRUCT_* field, CORINFO_CLASS_STRUCT_** structType, CORINFO_CLASS_STRUCT_* fieldOwnerHint) + { + AddCall("getFieldType"); + return mc.repGetFieldType(field, structType, fieldOwnerHint); + } + + private uint getFieldOffset(CORINFO_FIELD_STRUCT_* field) + { + AddCall("getFieldOffset"); + return mc.repGetFieldOffset(field); + } + + private void getFieldInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult) + { + AddCall("getFieldInfo"); + mc.repGetFieldInfo(P(ref pResolvedToken), callerHandle, flags, pResult); + } + + private uint getThreadLocalFieldInfo(CORINFO_FIELD_STRUCT_* field, bool isGCtype) + { + AddCall("getThreadLocalFieldInfo"); + return mc.repGetThreadLocalFieldInfo(field, isGCtype); + } + + private void getThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) + { + AddCall("getThreadLocalStaticBlocksInfo"); + mc.repGetThreadLocalStaticBlocksInfo(pInfo); + } + + private void getThreadLocalStaticInfo_NativeAOT(CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo) + { + AddCall("getThreadLocalStaticInfo_NativeAOT"); + mc.repGetThreadLocalStaticInfo_NativeAOT(pInfo); + } + + private bool isFieldStatic(CORINFO_FIELD_STRUCT_* fldHnd) + { + AddCall("isFieldStatic"); + return mc.repIsFieldStatic(fldHnd); + } + + private int getArrayOrStringLength(CORINFO_OBJECT_STRUCT_* objHnd) + { + AddCall("getArrayOrStringLength"); + return mc.repGetArrayOrStringLength(objHnd); + } + + private void getBoundaries(CORINFO_METHOD_STRUCT_* ftn, ref uint cILOffsets, ref uint* pILOffsets, BoundaryTypes* implicitBoundaries) + { + AddCall("getBoundaries"); + fixed (uint** ppILOffsets = &pILOffsets) + mc.repGetBoundaries(ftn, P(ref cILOffsets), ppILOffsets, implicitBoundaries); + + // The JIT frees the array with freeArray, so move the data to memory that complies with that. + if (cILOffsets > 0) + { + nuint size = cILOffsets * sizeof(uint); + var realOffsets = (uint*)allocateArray(size); + Buffer.MemoryCopy(pILOffsets, realOffsets, size, size); + pILOffsets = realOffsets; + } + else + { + pILOffsets = null; + } + } + + private void setBoundaries(CORINFO_METHOD_STRUCT_* ftn, uint cMap, OffsetMapping* pMap) + { + AddCall("setBoundaries"); + cr.recSetBoundaries(ftn, cMap, pMap); + freeArray(pMap); // Ownership of the array is ours. + } + + private void getVars(CORINFO_METHOD_STRUCT_* ftn, ref uint cVars, ILVarInfo** vars, ref bool extendOthers) + { + AddCall("getVars"); + mc.repGetVars(ftn, P(ref cVars), vars, P(ref extendOthers)); + + // The JIT frees the array with freeArray, so move the data to memory that complies with that. + if (cVars > 0) + { + nuint size = cVars * (nuint)sizeof(ILVarInfo); + var realVars = (ILVarInfo*)allocateArray(size); + Buffer.MemoryCopy(*vars, realVars, size, size); + *vars = realVars; + } + else + { + *vars = null; + } + } + + private void setVars(CORINFO_METHOD_STRUCT_* ftn, uint cVars, NativeVarInfo* vars) + { + AddCall("setVars"); + cr.recSetVars(ftn, cVars, vars); + freeArray(vars); // Ownership of the array is ours. + } + + // These compile outputs aren't saved. + private void reportRichMappings(InlineTreeNode* inlineTreeNodes, uint numInlineTreeNodes, RichOffsetMapping* mappings, uint numMappings) + { + AddCall("reportRichMappings"); + freeArray(inlineTreeNodes); + freeArray(mappings); + } + + private void reportAsyncDebugInfo(AsyncInfo* asyncInfo, AsyncSuspensionPoint* suspensionPoints, AsyncContinuationVarInfo* vars, uint numVars) + { + AddCall("reportAsyncDebugInfo"); + freeArray(suspensionPoints); + freeArray(vars); + } + + private void reportMetadata(byte* key, void* value, nuint length) + { + AddCall("reportMetadata"); + + ReadOnlySpan name = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(key); + if (name.SequenceEqual("MethodFullName"u8)) + { + cr.MethodFullName = Encoding.UTF8.GetString((byte*)value, (int)length); + } + else if (name.SequenceEqual("TieringName"u8)) + { + cr.TieringName = Encoding.UTF8.GetString((byte*)value, (int)length); + } + else + { + int index = JitMetrics.FindIndex(name, ref m_metricSearchStart); + if (index != -1) + cr.Metrics.Store(index, value, length); + } + } + + private void* allocateArray(nuint cBytes) => jitInstance.allocateArray(cBytes); + + private void freeArray(void* array) => jitInstance.freeArray(array); + + private CORINFO_ARG_LIST_STRUCT_* getArgNext(CORINFO_ARG_LIST_STRUCT_* args) + { + AddCall("getArgNext"); + return mc.repGetArgNext(args); + } + + private CorInfoTypeWithMod getArgType(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_STRUCT_* args, CORINFO_CLASS_STRUCT_** vcTypeRet) + { + AddCall("getArgType"); + CorInfoTypeWithMod value = mc.repGetArgType(sig, args, vcTypeRet, out uint exceptionCode); + if (exceptionCode != 0) + ThrowRecordedException(exceptionCode); + return value; + } + + private int getExactClasses(CORINFO_CLASS_STRUCT_* baseType, int maxExactClasses, CORINFO_CLASS_STRUCT_** exactClsRet) + { + AddCall("getExactClasses"); + return mc.repGetExactClasses(baseType, maxExactClasses, exactClsRet); + } + + private CORINFO_CLASS_STRUCT_* getArgClass(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_STRUCT_* args) + { + AddCall("getArgClass"); + CORINFO_CLASS_STRUCT_* value = mc.repGetArgClass(sig, args, out uint exceptionCode); + if (exceptionCode != 0) + ThrowRecordedException(exceptionCode); + return value; + } + + private CorInfoHFAElemType getHFAType(CORINFO_CLASS_STRUCT_* hClass) + { + AddCall("getHFAType"); + return mc.repGetHFAType(hClass); + } + + // The error traps are implemented natively, by the JIT-EE interface wrapper. + private bool runWithErrorTrap(void* function, void* parameter) => throw new NotSupportedException(); + + private bool runWithSPMIErrorTrap(void* function, void* parameter) => throw new NotSupportedException(); + + private void getEEInfo(ref CORINFO_EE_INFO pEEInfoOut) + { + AddCall("getEEInfo"); + mc.repGetEEInfo(P(ref pEEInfoOut)); + } + + private void getAsyncInfo(ref CORINFO_ASYNC_INFO pAsyncInfoOut) + { + AddCall("getAsyncInfo"); + mc.repGetAsyncInfo(P(ref pAsyncInfoOut)); + } + + private CORINFO_METHOD_STRUCT_* getAwaitReturnCall(CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_CONTEXT_STRUCT** contextHandle, ref CORINFO_LOOKUP instArg) + { + AddCall("getAwaitReturnCall"); + return mc.repGetAwaitReturnCall(callerHandle, contextHandle, P(ref instArg)); + } + + private CORINFO_METHOD_STRUCT_* getAwaitAwaiterInContinuationCall(CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool isUnsafe, + CORINFO_CONTEXT_STRUCT** contextHandle, ref CORINFO_LOOKUP instArg) + { + AddCall("getAwaitAwaiterInContinuationCall"); + return mc.repGetAwaitAwaiterInContinuationCall(callerHandle, P(ref pResolvedToken), isUnsafe, contextHandle, P(ref instArg)); + } + + private mdToken getMethodDefFromMethod(CORINFO_METHOD_STRUCT_* hMethod) + { + AddCall("getMethodDefFromMethod"); + return mc.repGetMethodDefFromMethod(hMethod); + } + + private nuint printMethodName(CORINFO_METHOD_STRUCT_* ftn, byte* buffer, nuint bufferSize, nuint* pRequiredBufferSize) + { + AddCall("printMethodName"); + return mc.repPrintMethodName(ftn, buffer, bufferSize, pRequiredBufferSize); + } + + private byte* getMethodNameFromMetadata(CORINFO_METHOD_STRUCT_* ftn, byte** className, byte** namespaceName, byte** enclosingClassNames, nuint maxEnclosingClassNames) + { + AddCall("getMethodNameFromMetadata"); + return mc.repGetMethodNameFromMetadata(ftn, className, namespaceName, enclosingClassNames, maxEnclosingClassNames); + } + + private uint getMethodHash(CORINFO_METHOD_STRUCT_* ftn) + { + AddCall("getMethodHash"); + return mc.repGetMethodHash(ftn); + } + + private bool getSystemVAmd64PassStructInRegisterDescriptor(CORINFO_CLASS_STRUCT_* structHnd, SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr) + { + AddCall("getSystemVAmd64PassStructInRegisterDescriptor"); + return mc.repGetSystemVAmd64PassStructInRegisterDescriptor(structHnd, structPassInRegDescPtr); + } + + private void getSwiftLowering(CORINFO_CLASS_STRUCT_* structHnd, ref CORINFO_SWIFT_LOWERING pLowering) + { + AddCall("getSwiftLowering"); + mc.repGetSwiftLowering(structHnd, P(ref pLowering)); + } + + private void getFpStructLowering(CORINFO_CLASS_STRUCT_* structHnd, ref CORINFO_FPSTRUCT_LOWERING pLowering) + { + AddCall("getFpStructLowering"); + mc.repGetFpStructLowering(structHnd, P(ref pLowering)); + } + + private CorInfoWasmType getWasmLowering(CORINFO_CLASS_STRUCT_* structHnd) + { + AddCall("getWasmLowering"); + return mc.repGetWasmLowering(structHnd); + } + + private uint getAddressAlignment(void* address) + { + AddCall("getAddressAlignment"); + return mc.repGetAddressAlignment(address); + } + + private void getWasmWellKnownGlobals(ref CORINFO_WASM_WELLKNOWN_GLOBALS pWellKnownGlobalsOut) + { + AddCall("getWasmWellKnownGlobals"); + mc.repGetWasmWellKnownGlobals(P(ref pWellKnownGlobalsOut)); + } + + private uint getThreadTLSIndex(ref void* ppIndirection) + { + AddCall("getThreadTLSIndex"); + fixed (void** p = &ppIndirection) + return mc.repGetThreadTLSIndex(p); + } + + private int* getAddrOfCaptureThreadGlobal(ref void* ppIndirection) + { + AddCall("getAddrOfCaptureThreadGlobal"); + fixed (void** p = &ppIndirection) + return mc.repGetAddrOfCaptureThreadGlobal(p); + } + + private void getHelperFtn(CorInfoHelpFunc ftnNum, CORINFO_CONST_LOOKUP* pNativeEntrypoint, CORINFO_METHOD_STRUCT_** pMethod) + { + AddCall("getHelperFtn"); + mc.repGetHelperFtn(ftnNum, pNativeEntrypoint, pMethod); + } + + private void getFunctionEntryPoint(CORINFO_METHOD_STRUCT_* ftn, ref CORINFO_CONST_LOOKUP pResult, CORINFO_ACCESS_FLAGS accessFlags) + { + AddCall("getFunctionEntryPoint"); + mc.repGetFunctionEntryPoint(ftn, P(ref pResult), accessFlags); + } + + private void getFunctionFixedEntryPoint(CORINFO_METHOD_STRUCT_* ftn, bool isUnsafeFunctionPointer, ref CORINFO_CONST_LOOKUP pResult) + { + AddCall("getFunctionFixedEntryPoint"); + mc.repGetFunctionFixedEntryPoint(ftn, isUnsafeFunctionPointer, P(ref pResult)); + } + + private CORINFO_MODULE_STRUCT_* embedModuleHandle(CORINFO_MODULE_STRUCT_* handle, ref void* ppIndirection) + { + AddCall("embedModuleHandle"); + fixed (void** p = &ppIndirection) + return mc.repEmbedModuleHandle(handle, p); + } + + private CORINFO_CLASS_STRUCT_* embedClassHandle(CORINFO_CLASS_STRUCT_* handle, ref void* ppIndirection) + { + AddCall("embedClassHandle"); + fixed (void** p = &ppIndirection) + return mc.repEmbedClassHandle(handle, p); + } + + private CORINFO_METHOD_STRUCT_* embedMethodHandle(CORINFO_METHOD_STRUCT_* handle, ref void* ppIndirection) + { + AddCall("embedMethodHandle"); + fixed (void** p = &ppIndirection) + return mc.repEmbedMethodHandle(handle, p); + } + + private CORINFO_FIELD_STRUCT_* embedFieldHandle(CORINFO_FIELD_STRUCT_* handle, ref void* ppIndirection) + { + AddCall("embedFieldHandle"); + fixed (void** p = &ppIndirection) + return mc.repEmbedFieldHandle(handle, p); + } + + private void embedGenericHandle(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool fEmbedParent, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_GENERICHANDLE_RESULT pResult) + { + AddCall("embedGenericHandle"); + mc.repEmbedGenericHandle(P(ref pResolvedToken), fEmbedParent, callerHandle, P(ref pResult)); + } + + private void getLocationOfThisType(CORINFO_METHOD_STRUCT_* context, ref CORINFO_LOOKUP_KIND pLookupKind) + { + AddCall("getLocationOfThisType"); + mc.repGetLocationOfThisType(context, P(ref pLookupKind)); + } + + private void getAddressOfPInvokeTarget(CORINFO_METHOD_STRUCT_* method, ref CORINFO_CONST_LOOKUP pLookup) + { + AddCall("getAddressOfPInvokeTarget"); + mc.repGetAddressOfPInvokeTarget(method, P(ref pLookup)); + } + + private void* GetCookieForInterpreterCalliSig(CORINFO_SIG_INFO* szMetaSig) + { + AddCall("GetCookieForInterpreterCalliSig"); + return mc.repGetCookieForInterpreterCalliSig(szMetaSig); + } + + private CORINFO_JUST_MY_CODE_HANDLE_* getJustMyCodeHandle(CORINFO_METHOD_STRUCT_* method, ref CORINFO_JUST_MY_CODE_HANDLE_* ppIndirection) + { + AddCall("getJustMyCodeHandle"); + fixed (CORINFO_JUST_MY_CODE_HANDLE_** p = &ppIndirection) + return mc.repGetJustMyCodeHandle(method, p); + } + + private void GetProfilingHandle(ref bool pbHookFunction, ref void* pProfilerHandle, ref bool pbIndirectedHandles) + { + AddCall("GetProfilingHandle"); + fixed (void** p = &pProfilerHandle) + mc.repGetProfilingHandle(P(ref pbHookFunction), p, P(ref pbIndirectedHandles)); + } + + private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, + CORINFO_CALLINFO_FLAGS flags, CORINFO_CALL_INFO* pResult) + { + AddCall("getCallInfo"); + mc.repGetCallInfo(P(ref pResolvedToken), pConstrainedResolvedToken, callerHandle, flags, pResult, out uint exceptionCode); + if (exceptionCode != 0) + ThrowRecordedException(exceptionCode); + } + + private bool getStaticFieldContent(CORINFO_FIELD_STRUCT_* field, byte* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects) + { + AddCall("getStaticFieldContent"); + return mc.repGetStaticFieldContent(field, buffer, bufferSize, valueOffset, ignoreMovableObjects); + } + + private bool getObjectContent(CORINFO_OBJECT_STRUCT_* obj, byte* buffer, int bufferSize, int valueOffset) + { + AddCall("getObjectContent"); + return mc.repGetObjectContent(obj, buffer, bufferSize, valueOffset); + } + + private CORINFO_CLASS_STRUCT_* getStaticFieldCurrentClass(CORINFO_FIELD_STRUCT_* field, byte* pIsSpeculative) + { + AddCall("getStaticFieldCurrentClass"); + return mc.repGetStaticFieldCurrentClass(field, pIsSpeculative); + } + + private IntPtr getVarArgsHandle(CORINFO_SIG_INFO* pSig, CORINFO_METHOD_STRUCT_* methHnd, ref void* ppIndirection) + { + AddCall("getVarArgsHandle"); + fixed (void** p = &ppIndirection) + return mc.repGetVarArgsHandle(pSig, methHnd, p); + } + + private InfoAccessType constructStringLiteral(CORINFO_MODULE_STRUCT_* module, mdToken metaTok, ref void* ppValue) + { + AddCall("constructStringLiteral"); + fixed (void** p = &ppValue) + return mc.repConstructStringLiteral(module, metaTok, p); + } + + private InfoAccessType emptyStringLiteral(ref void* ppValue) + { + AddCall("emptyStringLiteral"); + fixed (void** p = &ppValue) + return mc.repEmptyStringLiteral(p); + } + + private uint getFieldThreadLocalStoreID(CORINFO_FIELD_STRUCT_* field, ref void* ppIndirection) + { + AddCall("getFieldThreadLocalStoreID"); + fixed (void** p = &ppIndirection) + return mc.repGetFieldThreadLocalStoreID(field, p); + } + + private CORINFO_METHOD_STRUCT_* GetDelegateCtor(CORINFO_METHOD_STRUCT_* methHnd, CORINFO_CLASS_STRUCT_* clsHnd, CORINFO_METHOD_STRUCT_* targetMethodHnd, ref DelegateCtorArgs pCtorData) + { + AddCall("GetDelegateCtor"); + return mc.repGetDelegateCtor(methHnd, clsHnd, targetMethodHnd, P(ref pCtorData)); + } + + private void MethodCompileComplete(CORINFO_METHOD_STRUCT_* methHnd) + { + AddCall("MethodCompileComplete"); + Logger.LogError("Hit unimplemented MethodCompileComplete"); + SpmiUtil.DebugBreakorAV(118); + } + + private bool getTailCallHelpers(ref CORINFO_RESOLVED_TOKEN callToken, CORINFO_SIG_INFO* sig, CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, ref CORINFO_TAILCALL_HELPERS pResult) + { + AddCall("getTailCallHelpers"); + return mc.repGetTailCallHelpers(P(ref callToken), sig, flags, P(ref pResult)); + } + + private CORINFO_CLASS_STRUCT_* getContinuationType(nuint dataSize, ref bool objRefs, nuint objRefsSize) + { + AddCall("getContinuationType"); + return mc.repGetContinuationType(dataSize, P(ref objRefs), objRefsSize); + } + + private CORINFO_METHOD_STRUCT_* getAsyncResumptionStub(ref void* entryPoint) + { + AddCall("getAsyncResumptionStub"); + fixed (void** p = &entryPoint) + return mc.repGetAsyncResumptionStub(p); + } + + private bool convertPInvokeCalliToCall(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool mustConvert) + { + AddCall("convertPInvokeCalliToCall"); + return mc.repConvertPInvokeCalliToCall(P(ref pResolvedToken), mustConvert); + } + + private bool notifyInstructionSetUsage(InstructionSet instructionSet, bool supportEnabled, bool preserveNegativeDependency) + { + AddCall("notifyInstructionSetUsage"); + return mc.repNotifyInstructionSetUsage(instructionSet, supportEnabled, preserveNegativeDependency); + } + + private void updateEntryPointForTailCall(ref CORINFO_CONST_LOOKUP entryPoint) + { + AddCall("updateEntryPointForTailCall"); + mc.repUpdateEntryPointForTailCall(P(ref entryPoint)); + } + + // Allocates the code and data blocks: the hot code aligned as requested, and all the RO data in one block. + private void allocMem(ref AllocMemArgs pArgs) + { + AddCall("allocMem"); + + byte* hotCodeBlock = null, coldCodeBlock = null, roDataBlock = null; + nuint hotCodeSize = 0, coldCodeSize = 0, roDataSize = 0; + uint roDataAlignment = 0; + const CorJitAllocMemFlag CodeFlags = CorJitAllocMemFlag.CORJIT_ALLOCMEM_HOT_CODE | CorJitAllocMemFlag.CORJIT_ALLOCMEM_COLD_CODE; + + for (uint i = 0; i < pArgs.chunksCount; i++) + { + ref AllocMemChunk chunk = ref pArgs.chunks[i]; + if ((chunk.flags & CorJitAllocMemFlag.CORJIT_ALLOCMEM_HOT_CODE) != 0) + { + hotCodeSize = chunk.size; + uint codeAlignment = Math.Max((uint)sizeof(void*), chunk.alignment); + hotCodeBlock = (byte*)AlignUp((nuint)cr.allocateMemory(chunk.size + codeAlignment - 1), codeAlignment); + chunk.block = chunk.blockRW = hotCodeBlock; + } + else if ((chunk.flags & CorJitAllocMemFlag.CORJIT_ALLOCMEM_COLD_CODE) != 0) + { + coldCodeSize = chunk.size; + coldCodeBlock = (byte*)cr.allocateMemory(coldCodeSize); + chunk.block = chunk.blockRW = coldCodeBlock; + } + else + { + roDataAlignment = Math.Max(roDataAlignment, chunk.alignment); + roDataSize = AlignUp(roDataSize, chunk.alignment) + chunk.size; + } + } + + if (roDataSize > 0) + { + // The block is zeroed, so all the padding compares equal later. + roDataBlock = (byte*)AlignUp((nuint)cr.allocateMemory(roDataSize + roDataAlignment - 1), roDataAlignment); + nuint offset = 0; + for (uint i = 0; i < pArgs.chunksCount; i++) + { + ref AllocMemChunk chunk = ref pArgs.chunks[i]; + if ((chunk.flags & CodeFlags) != 0) + continue; + + offset = AlignUp(offset, chunk.alignment); + chunk.block = chunk.blockRW = roDataBlock + offset; + offset += chunk.size; + } + } + + cr.recAllocMem(hotCodeSize, coldCodeSize, roDataSize, pArgs.xcptnsCount, hotCodeBlock, coldCodeBlock, roDataBlock); + } + + private void reserveUnwindInfo(bool isFunclet, bool isColdCode, uint unwindSize) + { + AddCall("reserveUnwindInfo"); + cr.recReserveUnwindInfo(isFunclet, isColdCode, unwindSize); + } + + private void allocUnwindInfo(byte* pHotCode, byte* pColdCode, uint startOffset, uint endOffset, uint unwindSize, byte* pUnwindBlock, CorJitFuncKind funcKind) + { + AddCall("allocUnwindInfo"); + cr.recAllocUnwindInfo(pHotCode, pColdCode, startOffset, endOffset, unwindSize, pUnwindBlock, funcKind); + } + + private void* allocGCInfo(nuint size) + { + AddCall("allocGCInfo"); + void* temp = cr.allocateMemory(size); + cr.recAllocGCInfo(size, temp); + return temp; + } + + private void setEHcount(uint cEH) + { + AddCall("setEHcount"); + cr.recSetEHcount(cEH); + } + + private void setEHinfo(uint EHnumber, ref CORINFO_EH_CLAUSE clause) + { + AddCall("setEHinfo"); + cr.recSetEHinfo(EHnumber, P(ref clause)); + } + + private bool logMsg(uint level, byte* fmt, IntPtr args) + { + AddCall("logMsg"); + return false; + } + + // Returns whether the code should retry (DebugBreak), or ignore the assert. + private int doAssert(byte* szFile, int iLine, byte* szExpr) + { + AddCall("doAssert"); + string file = Marshal.PtrToStringUTF8((IntPtr)szFile); + string expr = Marshal.PtrToStringUTF8((IntPtr)szExpr); + string buff = $"{file} ({iLine}) - {expr}"; + + Logger.LogIssue($" #{mc.index} {buff}"); + cr.recMessageLog(buff); + + // Under "-boa", the assert is reported as a failure, without launching the JIT debugger. + if (SpmiUtil.BreakOnDebugBreakorAV) + { + Logger.LogError($"SuperPMI: Assert Failure (PID {Environment.ProcessId}, Thread {Environment.CurrentManagedThreadId}/{Environment.CurrentManagedThreadId:x})\n" + + $"{expr}\n\n{file}, Line: {iLine}\n"); + } + + SpmiUtil.DebugBreakorAV(0x7b); + return 0; + } + + private void reportFatalError(CorJitResult result) + { + AddCall("reportFatalError"); + cr.recReportFatalError(result); + } + + private HRESULT getPgoInstrumentationResults(CORINFO_METHOD_STRUCT_* ftnHnd, ref PgoInstrumentationSchema* pSchema, ref uint pCountSchemaItems, + byte** pInstrumentationData, ref PgoSource pPgoSource, ref bool pDynamicPgo) + { + AddCall("getPgoInstrumentationResults"); + fixed (PgoInstrumentationSchema** ppSchema = &pSchema) + return mc.repGetPgoInstrumentationResults(ftnHnd, ppSchema, P(ref pCountSchemaItems), pInstrumentationData, P(ref pPgoSource), P(ref pDynamicPgo)); + } + + private HRESULT allocPgoInstrumentationBySchema(CORINFO_METHOD_STRUCT_* ftnHnd, PgoInstrumentationSchema* pSchema, uint countSchemaItems, byte** pInstrumentationData) + { + AddCall("allocPgoInstrumentationBySchema"); + return mc.repAllocPgoInstrumentationBySchema(ftnHnd, pSchema, countSchemaItems, pInstrumentationData); + } + + private void recordCallSite(uint instrOffset, CORINFO_SIG_INFO* callSig, CORINFO_METHOD_STRUCT_* methodHandle) + { + AddCall("recordCallSite"); + cr.repRecordCallSite(instrOffset, callSig, methodHandle); + } + + // Only meaningful for ReadyToRun Wasm compilation. + private void recordWasmManagedCallSig(CORINFO_SIG_INFO* callSig) => AddCall("recordWasmManagedCallSig"); + + private void recordRelocation(void* location, void* locationRW, void* target, CorInfoReloc fRelocType, int addlDelta) + { + AddCall("recordRelocation"); + cr.repRecordRelocation(location, target, fRelocType, addlDelta); + } + + private CorInfoReloc getRelocTypeHint(void* target) + { + AddCall("getRelocTypeHint"); + return mc.repGetRelocTypeHint(target); + } + + private uint getExpectedTargetArchitecture() + { + AddCall("getExpectedTargetArchitecture"); + return mc.repGetExpectedTargetArchitecture(); + } + + private uint getJitFlags(ref CORJIT_FLAGS flags, uint sizeInBytes) + { + AddCall("getJitFlags"); + return jitInstance.getJitFlags(P(ref flags), sizeInBytes); + } + + private CORINFO_WASM_TYPE_SYMBOL_STRUCT_* getWasmTypeSymbol(CorInfoWasmType* types, nuint typesSize) + { + AddCall("getWasmTypeSymbol"); + return mc.repGetWasmTypeSymbol(types, typesSize); + } + + private CORINFO_METHOD_STRUCT_* getSpecialCopyHelper(CORINFO_CLASS_STRUCT_* type) + { + AddCall("getSpecialCopyHelper"); + return mc.repGetSpecialCopyHelper(type); + } +} diff --git a/src/coreclr/tools/superpmi/managed/superpmi/JitInstance.cs b/src/coreclr/tools/superpmi/managed/superpmi/JitInstance.cs new file mode 100644 index 00000000000000..157ad44bf6837d --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/superpmi/JitInstance.cs @@ -0,0 +1,539 @@ +// 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.Diagnostics; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; +using Internal.JitInterface; +using Internal.TypeSystem; + +namespace SuperPmi.Replay; + +internal enum ReplayResult +{ + Success, + Error, + Miss, +} + +internal struct ReplayResults +{ + public ReplayResult Result; + public bool IsMinOpts; + public long NumExecutedInstructions; + public CompileResult CompileResults; +} + +// An exception that escaped the JIT natively, such as an access violation. +internal sealed class NativeException(uint code) : Exception($"Unexpected exception {code:x} was thrown.") +{ + public uint Code { get; } = code; +} + +// A loaded JIT, with the JIT host and the JIT-EE interface that it compiles methods with. +internal sealed unsafe class JitInstance +{ + private const int E_FAIL = unchecked((int)0x80004005); + + private IntPtr hLib; + private delegate* unmanaged pnjitStartup; + private CorInfoImpl icji; + private IntPtr configProvider; + private readonly Stopwatch stj = new(); + + private LightWeightMap forceOptions; + private LightWeightMap options; + private MethodContext.ConfigEnvironment environment; + + private bool forceClearAltJitFlag; + private bool forceSetAltJitFlag; + + // The value of the string config option asked for, between the native JIT host's calls for its size and its data. + private byte[] pendingStringConfigValue; + + public readonly CycleTimer lt = new(); + public MethodContext mc; + public readonly ulong[] times = new ulong[2]; + public IntPtr pJitInstance; + + // The loaded JIT module, to detect when the baseline and diff JITs are the same module (which shares global state). + public IntPtr Module => hLib; + + public static JitInstance InitJit(string nameOfJit, bool breakOnAssert, Stopwatch st1, MethodContext firstContext, + LightWeightMap forceOptions, LightWeightMap options) + { + var jit = new JitInstance { forceOptions = forceOptions, options = options }; + + // The flag to invoke the JIT as an altjit is in the JIT flags, not the environment. If "-jitoption force" + // forces AltJit off or on, propagate that to the JIT flags. + foreach (string name in (ReadOnlySpan)["AltJit", "AltJitNgen"]) + { + string altJitFlag = jit.getForceOption(name); + if (altJitFlag == "") + jit.forceClearAltJitFlag = true; + else if (altJitFlag != null) + jit.forceSetAltJitFlag = true; + } + + st1?.Restart(); + int hr = jit.StartUp(nameOfJit, breakOnAssert, firstContext); + st1?.Stop(); + if (hr != 0) + { + Logger.LogError($"Startup of JIT({nameOfJit}) failed {hr}"); + return null; + } + if (st1 != null) + Logger.LogVerbose(CFormat.Sprintf("Jit startup took %fms", st1.Elapsed.TotalMilliseconds)); + + return jit; + } + + private int StartUp(string pathToJit, bool breakOnDebugBreakorAV, MethodContext firstContext) + { + SpmiUtil.BreakOnDebugBreakorAV = breakOnDebugBreakorAV; + + string fullPath = Path.GetFullPath(pathToJit); + if (OperatingSystem.IsWindows() && File.Exists(fullPath)) + { + FileVersionInfo version = FileVersionInfo.GetVersionInfo(fullPath); + Logger.LogDebug($"'{fullPath}' is version {version.FileMajorPart}.{version.FileMinorPart}.{version.FileBuildPart}.{version.FilePrivatePart}"); + } + + // The error codes are ERROR_MOD_NOT_FOUND and ERROR_PROC_NOT_FOUND. + if (!NativeLibrary.TryLoad(fullPath, out hLib)) + { + Logger.LogError("LoadLibrary failed (0x0000007e)"); + return E_FAIL; + } + + if (!NativeLibrary.TryGetExport(hLib, "getJit", out IntPtr pngetJit)) + { + Logger.LogError("GetProcAddress 'getJit' failed (0x0000007f)"); + return -1; + } + + // Set up the JIT host and call jitStartup, if the JIT has it. + if (NativeLibrary.TryGetExport(hLib, "jitStartup", out IntPtr jitStartup)) + { + pnjitStartup = (delegate* unmanaged)jitStartup; + mc = firstContext; + configProvider = CreateConfigProvider(); + callJitStartup(); + } + + pJitInstance = ((delegate* unmanaged)pngetJit)(); + if (pJitInstance == IntPtr.Zero) + { + Logger.LogError("pngetJit gave us null"); + return -1; + } + + Guid versionId = default; + SpmiJitInterface.JitGetVersionIdentifier(pJitInstance, &versionId); + if (versionId != JitEEVersion.Identifier) + { + // A mismatched version ID fails the load. + pJitInstance = IntPtr.Zero; + Logger.LogError($"Jit Compiler has wrong version identifier. Expected: {JitEEVersion.Identifier:D}. Actual: {versionId:D}."); + return -1; + } + + icji = new CorInfoImpl(this); + return 0; + } + + private void callJitStartup() + { + pnjitStartup(SpmiJitInterface.GetJitHost(configProvider)); + environment = mc.cloneEnvironment(); + } + + // Starts the JIT up again, so that it reads the configuration of 'firstContext'. + public bool resetConfig(MethodContext firstContext) + { + if (pnjitStartup == null) + return false; + + mc = firstContext; + callJitStartup(); + return true; + } + + public MethodContext.ConfigEnvironment getEnvironment() => environment; + + public void updateForceOptions(LightWeightMap newForceOptions) => forceOptions = newForceOptions; + + public ReplayResults CompileMethod(MethodContext methodToCompile, int mcIndex, bool collectThroughput) + { + var results = new ReplayResults { Result = ReplayResult.Success }; + CORINFO_METHOD_INFO info = default; + uint flags = 0; + + // The raw values, to figure things out later. + mc = methodToCompile; + times[0] = 0; + times[1] = 0; + stj.Restart(); + + ulong insCountBefore = 0; + SpmiJitInterface.Instrumentor_GetInsCount(&insCountBefore); + + try + { + CORINFO_OS os = CORINFO_OS.CORINFO_WINNT; + mc.repCompileMethod(&info, &flags, &os); + + CORJIT_FLAGS jitFlags = default; + getJitFlags(&jitFlags, (uint)sizeof(CORJIT_FLAGS)); + results.IsMinOpts = jitFlags.IsSet(CorJitFlag.CORJIT_FLAG_DEBUG_CODE) || jitFlags.IsSet(CorJitFlag.CORJIT_FLAG_MIN_OPT) || + jitFlags.IsSet(CorJitFlag.CORJIT_FLAG_TIER0); + + if (collectThroughput) + lt.Start(); + SpmiJitInterface.JitSetOs(pJitInstance, os); + CorJitResult jitResult = icji.CompileMethod(pJitInstance, &info, flags, out byte* nativeEntry, out uint nativeSizeOfCode); + if (collectThroughput) + { + lt.Stop(); + times[0] = lt.GetCycles(); + } + + CorInfoMethodRuntimeFlags methodFlags = mc.cr.repSetMethodAttribs(info.ftn); + if ((methodFlags & CorInfoMethodRuntimeFlags.CORINFO_FLG_SWITCHED_TO_MIN_OPT) != 0) + results.IsMinOpts = true; + else if ((methodFlags & CorInfoMethodRuntimeFlags.CORINFO_FLG_SWITCHED_TO_OPTIMIZED) != 0) + results.IsMinOpts = false; + + // An altjit skips the methods of other target architectures, which isn't a failure. Neither is + // skipping the methods of an altjit that matches the target, with RunAltJitCode=0 (which stops the + // generated code from being used). + if (jitResult == CorJitResult.CORJIT_SKIPPED && + (!MatchesTargetArchitecture((CorInfoArch)mc.repGetExpectedTargetArchitecture()) || + (jitFlags.IsSet(CorJitFlag.CORJIT_FLAG_ALT_JIT) && GetIntConfigValue("RunAltJitCode"u8, 1) == 0))) + { + jitResult = CorJitResult.CORJIT_OK; + } + + if (jitResult is CorJitResult.CORJIT_OK or CorJitResult.CORJIT_BADCODE or CorJitResult.CORJIT_R2R_UNSUPPORTED) + { + // Capture the results of the compilation. + mc.cr.recCompileMethod(nativeEntry, nativeSizeOfCode, jitResult); + mc.cr.recAllocMemCapture(); + mc.cr.recAllocGCInfoCapture(); + mc.cr.recMessageLog(jitResult == CorJitResult.CORJIT_OK ? "Successful Compile" : "Successful Compile (BADCODE)"); + } + else + { + Logger.LogDebug($"compileMethod failed with result {(int)jitResult}"); + results.Result = ReplayResult.Error; + } + } + catch (SpmiException e) when (e.Code == ExceptionCodes.MC) + { + Logger.LogMissing($"Method context {mcIndex} failed to replay: {e.Message}"); + results.Result = ReplayResult.Miss; + } + catch (SpmiException e) when (e.Code == ExceptionCodes.RECORDED_EXCEPTION) + { + // An exception that the EE threw during recording, such as a MissingFieldException from + // resolveToken. Several JIT-EE APIs can throw exceptions, which the recorder rethrows under this + // code. These aren't replay failures; capture that no code or GC info was generated. + mc.cr.recAllocMemCapture(); + mc.cr.recAllocGCInfoCapture(); + mc.cr.recMessageLog("Successful Compile (EE API exception)"); + } + catch (SpmiException e) + { + Logger.LogError($"Exception thrown: {e.Message}"); + results.Result = ReplayResult.Error; + } + catch (NativeException e) + { + Logger.LogError(e.Message); + results.Result = ReplayResult.Error; + } + catch (Exception e) + { + Logger.LogError($"Exception thrown: {e}"); + results.Result = ReplayResult.Error; + } + + stj.Stop(); + + // Reaching here with throughput collection means the method compiles. + if (collectThroughput) + timeResult(&info, flags); + + mc.cr.secondsToCompile = stj.Elapsed.TotalSeconds; + results.CompileResults = mc.cr; + + ulong insCountAfter = 0; + SpmiJitInterface.Instrumentor_GetInsCount(&insCountAfter); + results.NumExecutedInstructions = (long)(insCountAfter - insCountBefore); + return results; + } + + private static bool MatchesTargetArchitecture(CorInfoArch arch) + { + TargetArchitecture? expected = arch switch + { + CorInfoArch.CORINFO_ARCH_X64 => TargetArchitecture.X64, + CorInfoArch.CORINFO_ARCH_X86 => TargetArchitecture.X86, + CorInfoArch.CORINFO_ARCH_ARM => TargetArchitecture.ARM, + CorInfoArch.CORINFO_ARCH_ARM64 => TargetArchitecture.ARM64, + CorInfoArch.CORINFO_ARCH_LOONGARCH64 => TargetArchitecture.LoongArch64, + CorInfoArch.CORINFO_ARCH_RISCV64 => TargetArchitecture.RiscV64, + CorInfoArch.CORINFO_ARCH_WASM32 => TargetArchitecture.Wasm32, + _ => null, + }; + if (expected == null) + Logger.LogError("Unknown target architecture"); + return expected == SpmiUtil.GetSpmiTargetArchitecture(); + } + + // Compiles the method ten more times, keeping the two smallest times (whose closest pair reduces the noise). + private void timeResult(CORINFO_METHOD_INFO* info, uint flags) + { + for (int i = 0; i < 10; i++) + { + mc.cr = new CompileResult(); + lt.Start(); + icji.CompileMethod(pJitInstance, info, flags, out _, out _); + lt.Stop(); + ulong time = lt.GetCycles(); + if (times[1] == 0 || time < times[1]) + { + if (time < times[0]) + { + times[1] = times[0]; + times[0] = time; + } + else + { + times[1] = time; + } + } + } + } + + private string getForceOption(string key) => getOption(key, forceOptions); + + private string getOption(string key) => getOption(key, options); + + private static string getOption(string key, LightWeightMap options) + { + if (options == null) + return null; + + byte[] keyBytes = new byte[Encoding.UTF8.GetByteCount(key) + 1]; + Encoding.UTF8.GetBytes(key, keyBytes); + int keyIndex = options.Contains(keyBytes); + return keyIndex == -1 ? null : options.GetString(options.Get((uint)keyIndex)); + } + + // The JIT flags of the compilation, adjusted for altjit. This doesn't record the call in the compile result. + public uint getJitFlags(CORJIT_FLAGS* jitFlags, uint sizeInBytes) + { + uint ret = mc.repGetJitFlags(jitFlags, sizeInBytes); + if (forceClearAltJitFlag) + jitFlags->Clear(CorJitFlag.CORJIT_FLAG_ALT_JIT); + else if (forceSetAltJitFlag) + jitFlags->Set(CorJitFlag.CORJIT_FLAG_ALT_JIT); + return ret; + } + + // Memory handed to the EE, such as for the debug info passed to setVars() and setBoundaries(). + public void* allocateArray(nuint cBytes) + { + mc.cr.AddCall("allocateArray"); + return mc.cr.allocateMemory(cBytes); + } + + // Arrays that the EE passed to the JIT, such as from getVars() and getBoundaries(). They live as long as + // the compile result does. + public void freeArray(void* array) => mc.cr.AddCall("freeArray"); + + // The JIT host is crossgen2's (in src/coreclr/tools/aot/jitinterface/jithost.cpp), which gets the + // configuration from this provider: a native object whose vtable has getIntConfigValue and getStringConfigValue. + private IntPtr CreateConfigProvider() + { + var vtable = (IntPtr*)NativeMemory.Alloc(2, (nuint)sizeof(IntPtr)); + vtable[0] = (IntPtr)(delegate* unmanaged)&getIntConfigValue; + vtable[1] = (IntPtr)(delegate* unmanaged)&getStringConfigValue; + + // The JIT instance lives as long as the process. + var provider = (IntPtr*)NativeMemory.Alloc(2, (nuint)sizeof(IntPtr)); + provider[0] = (IntPtr)vtable; + provider[1] = GCHandle.ToIntPtr(GCHandle.Alloc(this)); + return (IntPtr)provider; + } + + private static JitInstance FromProvider(IntPtr provider) => (JitInstance)GCHandle.FromIntPtr(((IntPtr*)provider)[1]).Target; + + [UnmanagedCallersOnly] + private static int getIntConfigValue(IntPtr thisHandle, byte* name, int defaultValue) + { + try + { + return FromProvider(thisHandle).GetIntConfigValue(MemoryMarshal.CreateReadOnlySpanFromNullTerminated(name), defaultValue); + } + catch (Exception e) + { + Logger.LogError($"Exception thrown: {e}"); + return defaultValue; + } + } + + // Returns the size of the value with its null terminator (or 0 for no value), and copies it to 'retBuffer'. + [UnmanagedCallersOnly] + private static int getStringConfigValue(IntPtr thisHandle, byte* name, byte* retBuffer, int retBufferLength) + { + try + { + JitInstance jit = FromProvider(thisHandle); + byte[] value = retBuffer == null ? jit.GetStringConfigValue(MemoryMarshal.CreateReadOnlySpanFromNullTerminated(name)) : jit.pendingStringConfigValue; + jit.pendingStringConfigValue = retBuffer == null ? value : null; + if (value == null) + return 0; + if (retBuffer != null && retBufferLength >= value.Length) + value.CopyTo(new Span(retBuffer, value.Length)); + return value.Length; + } + catch (Exception e) + { + Logger.LogError($"Exception thrown: {e}"); + return 0; + } + } + + // In order: the force options, the method context's recorded value, special keys, the JIT options, and the environment. + private int GetIntConfigValue(ReadOnlySpan keyBytes, int defaultValue) + { + mc.cr.AddCall("getIntConfigValue"); + + string key = Encoding.UTF8.GetString(keyBytes); + int result = defaultValue; + bool valueFound = convertStringValueToInt(key, getForceOption(key), ref result); + + if (!valueFound) + { + // A default value that was set explicitly can't be told apart from the default value of a key that + // wasn't set; see CLRConfig::GetConfigValue. + fixed (byte* pKey = NulTerminated(keyBytes)) + result = mc.repGetIntConfigValue(pKey, defaultValue); + valueFound = result != defaultValue; + } + + if (!valueFound) + { + if (key == "SuperPMIMethodContextNumber") + { + result = mc.index; + valueFound = true; + } + else if (key == "JitReportMetrics") + { + result = 1; + valueFound = true; + } + } + + if (!valueFound) + valueFound = convertStringValueToInt(key, getOption(key), ref result); + + if (!valueFound) + valueFound = convertStringValueToInt(key, GetConfigFromEnvironmentVariable(key), ref result); + + if (valueFound) + Logger.LogDebug($"Environment variable {key}={result}"); + + return valueFound ? result : defaultValue; + } + + // In order: the force options, the method context's recorded value, the JIT options, and the environment. + private byte[] GetStringConfigValue(ReadOnlySpan keyBytes) + { + mc.cr.AddCall("getStringConfigValue"); + + string key = Encoding.UTF8.GetString(keyBytes); + string result = getForceOption(key); + if (result == null) + { + fixed (byte* pKey = NulTerminated(keyBytes)) + { + byte* value = mc.repGetStringConfigValue(pKey); + if (value != null) + result = Marshal.PtrToStringUTF8((IntPtr)value); + } + } + result ??= getOption(key); + result ??= GetConfigFromEnvironmentVariable(key); + + if (result == null) + return null; + + Logger.LogDebug($"Environment variable {key}={result}"); + return NulTerminated(Encoding.UTF8.GetBytes(result)); + } + + private static byte[] NulTerminated(ReadOnlySpan bytes) + { + byte[] result = new byte[bytes.Length + 1]; + bytes.CopyTo(result); + return result; + } + + private static string GetConfigFromEnvironmentVariable(string key) + => Environment.GetEnvironmentVariable("DOTNET_" + key) ?? Environment.GetEnvironmentVariable("COMPlus_" + key); + + // Config values are in hex, as parsed by strtoul (whose unsigned long is 32 bits on Windows, and 64 bits elsewhere). + private static bool convertStringValueToInt(string key, string stringValue, ref int result) + { + if (stringValue == null) + return false; + + if (!TryParseUnsignedLong16(stringValue, out ulong value) || value > uint.MaxValue) + { + Logger.LogWarning($"Can't convert int config value from string, key: {key}, string value: {stringValue}\n"); + return false; + } + + result = (int)value; + return true; + } + + private static bool TryParseUnsignedLong16(string s, out ulong value) + { + ulong max = OperatingSystem.IsWindows() ? uint.MaxValue : ulong.MaxValue; + value = 0; + + int i = 0; + while (i < s.Length && (s[i] == ' ' || (s[i] >= '\t' && s[i] <= '\r'))) + i++; + bool negative = i < s.Length && s[i] == '-'; + if (i < s.Length && (s[i] == '-' || s[i] == '+')) + i++; + if (i + 2 < s.Length && s[i] == '0' && (s[i + 1] | 0x20) == 'x' && char.IsAsciiHexDigit(s[i + 2])) + i += 2; + + int start = i; + bool overflow = false; + for (; i < s.Length && char.IsAsciiHexDigit(s[i]); i++) + { + ulong digit = (ulong)(char.IsAsciiDigit(s[i]) ? s[i] - '0' : (s[i] | 0x20) - 'a' + 10); + if (value > (max - digit) / 16) + overflow = true; + else + value = value * 16 + digit; + } + + if (i == start || overflow) + return false; + if (negative) + value = unchecked(0 - value) & max; + return true; + } +} diff --git a/src/coreclr/tools/superpmi/managed/superpmi/NearDiffer.cs b/src/coreclr/tools/superpmi/managed/superpmi/NearDiffer.cs new file mode 100644 index 00000000000000..8446698b5c912e --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/superpmi/NearDiffer.cs @@ -0,0 +1,609 @@ +// 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.Diagnostics; +using System.IO; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Internal.JitInterface; +using Internal.TypeSystem; + +using static SuperPmi.SpmiRecordsHelper; +using static SuperPmi.SpmiUtil; + +namespace SuperPmi.Replay; + +// Compares two compilations of a method. After simple fixups, the main artifacts of the compile results (the +// code, GC info, EH info, debug info, and so on) are compared for equality; to be fast, the fixups and the +// definitions of "equality" are minimal (for example, the GC info is compared byte by byte). +// +// The asm comparison is done by the CoreDisTools library, which compares the code instruction by instruction. +// Literal operands that differ are run through heuristics that try to normalize them, by reinterpreting them as +// deltas from known base addresses; for example, a common case is a pointer into the read-only data section. +// +// Most of the logic is architecture independent, with these exceptions: the disassembler is created for the +// target architecture; the heuristics have some architecture-specific assumptions; and the code is fixed up with +// the relocations recorded during the compilation, which in theory is architecture independent, but the runtime +// implementations may have subtle differences. +internal sealed unsafe class NearDiffer : IDisposable +{ + // coredistools.h + private enum TargetArch + { + Target_Host, + Target_X86, + Target_X64, + Target_Thumb, + Target_Arm64, + Target_LoongArch64, + Target_RiscV64, + Target_Wasm32, + } + + // The offset comparator's view of the two code blocks. + private struct DiffData + { + public byte* block1; + public nuint blocksize1; + public byte* datablock1; + public nuint datablockSize1; + public nuint originalBlock1; + public nuint originalDataBlock1; + public nuint otherCodeBlock1; + public nuint otherCodeBlockSize1; + + public byte* block2; + public nuint blocksize2; + public byte* datablock2; + public nuint datablockSize2; + public nuint originalBlock2; + public nuint originalDataBlock2; + public nuint otherCodeBlock2; + public nuint otherCodeBlockSize2; + } + + // The compile results being compared, for the offset comparator. + private static CompileResult s_cr1; + private static CompileResult s_cr2; + + private static delegate* unmanaged[Cdecl] g_PtrNewDiffer; // For temporary backwards-compatibility with older coredistools + private static delegate* unmanaged[Cdecl] g_PtrNewDiffer2; + private static delegate* unmanaged[Cdecl] g_PtrFinishDiff; + private static delegate* unmanaged[Cdecl] g_PtrNearDiffCodeBlocks; + private static delegate* unmanaged[Cdecl] g_PtrDumpDiffBlocks; + + private readonly TargetArchitecture? targetArchitecture; + private IntPtr corAsmDiff; + + // 'targetArchitecture' is the one given with -target, if any. + public NearDiffer(TargetArchitecture? targetArchitecture) => this.targetArchitecture = targetArchitecture; + + public void Dispose() + { + if (corAsmDiff != IntPtr.Zero) + g_PtrFinishDiff(corAsmDiff); + } + + // Loads CoreDisTools, which is next to superpmi. + public bool InitAsmDiff() + { + string libraryName = OperatingSystem.IsWindows() ? "coredistools.dll" : OperatingSystem.IsMacOS() ? "libcoredistools.dylib" : "libcoredistools.so"; + if (!NativeLibrary.TryLoad(Path.Combine(AppContext.BaseDirectory, libraryName), out IntPtr hCoreDisToolsLib)) + { + Logger.LogError($"LoadLibrary({libraryName}) failed (0x0000007e)"); + return false; + } + + IntPtr GetExport(string name, bool required = true) + { + if (!NativeLibrary.TryGetExport(hCoreDisToolsLib, name, out IntPtr address)) + { + if (required) + Logger.LogError($"GetProcAddress '{name}' failed (0x0000007f)"); + else + Logger.LogWarning($"GetProcAddress '{name}' failed (0x0000007f)"); // Just a warning; fall back to NewDiffer + } + return address; + } + + if ((g_PtrNewDiffer = (delegate* unmanaged[Cdecl])GetExport("NewDiffer")) == null) + return false; + g_PtrNewDiffer2 = (delegate* unmanaged[Cdecl])GetExport("NewDiffer2", required: false); + if ((g_PtrFinishDiff = (delegate* unmanaged[Cdecl])GetExport("FinishDiff")) == null || + (g_PtrNearDiffCodeBlocks = (delegate* unmanaged[Cdecl])GetExport("NearDiffCodeBlocks")) == null || + (g_PtrDumpDiffBlocks = (delegate* unmanaged[Cdecl])GetExport("DumpDiffBlocks")) == null) + { + return false; + } + + TargetArch coreDisTargetArchitecture = targetArchitecture switch + { + TargetArchitecture.X64 => TargetArch.Target_X64, + TargetArchitecture.X86 => TargetArch.Target_X86, + TargetArchitecture.ARM => TargetArch.Target_Thumb, + TargetArchitecture.ARM64 => TargetArch.Target_Arm64, + TargetArchitecture.LoongArch64 => TargetArch.Target_LoongArch64, + TargetArchitecture.RiscV64 => TargetArch.Target_RiscV64, + // Requires coredistools >= 1.7.0 (Target_Wasm32 and framed entry points). NearDiffCodeBlocks and + // DumpDiffBlocks route to the Wasm framing-aware implementations inside coredistools. + TargetArchitecture.Wasm32 => TargetArch.Target_Wasm32, + _ => TargetArch.Target_Host, + }; + + // Only arm32 uses this feature currently. + IntPtr munger = targetArchitecture == TargetArchitecture.ARM + ? (IntPtr)(delegate* unmanaged[Cdecl])&CoreDisMungeOffsetsCallback + : IntPtr.Zero; + + IntPtr printers = SpmiJitInterface.GetCoreDisToolsPrinters(&CoreDisToolsLog); + IntPtr comparator = (IntPtr)(delegate* unmanaged[Cdecl])&CoreDisCompareOffsetsCallback; + corAsmDiff = g_PtrNewDiffer2 == null + ? g_PtrNewDiffer(coreDisTargetArchitecture, printers, comparator) + : g_PtrNewDiffer2(coreDisTargetArchitecture, printers, comparator, munger); + return true; + } + + [UnmanagedCallersOnly] + private static void CoreDisToolsLog(int level, byte* message) + { + string text = Marshal.PtrToStringUTF8((IntPtr)message); + if (level == 0) + Logger.LogError(text); + else if (level == 1) + Logger.LogWarning(text); + else + Logger.LogVerbose(text); + } + + [UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])] + private static byte CoreDisCompareOffsetsCallback(void* payload, nuint blockOffset, nuint instrLen, ulong offset1, ulong offset2) + => compareOffsets((DiffData*)payload, blockOffset, instrLen, offset1, offset2) ? (byte)1 : (byte)0; + + [UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])] + private static byte CoreDisMungeOffsetsCallback(void* payload, nuint blockOffset, nuint instrLen, ulong* offset1, ulong* offset2, uint* skip1, uint* skip2) + => mungeOffsets((DiffData*)payload, blockOffset, offset1, offset2, skip1, skip2) ? (byte)1 : (byte)0; + + // On Thumb-2, movw/movt pairs that generate a 32-bit address are treated as a single instruction. + // + // Something similar might be needed for mov/movk/movk/movk on Arm64, but the number of movk can differ + // with the data, so zeroing out the constants doesn't work well; the disassembler would need a callback to + // skip the instructions. + private static bool mungeOffsets(DiffData* data, nuint blockOffset, ulong* offset1, ulong* offset2, uint* skip1, uint* skip2) + { + if (GetSpmiTargetArchitecture() != TargetArchitecture.ARM) + return false; + + static bool FindMovwMovtAddress(byte* block, nuint blocksize, nuint blockOffset, out uint reg, out ulong addr) + { + var iaddr = (uint*)(block + blockOffset); + var iaddrEnd = (uint*)(block + blocksize); + addr = 0; + reg = 0; + if (iaddr < iaddrEnd && GetArm32MovwConstant(iaddr, out reg, out uint conW) && + iaddr + 1 < iaddrEnd && GetArm32MovtConstant(iaddr + 1, out uint regT, out uint conT) && reg == regT) + { + addr = conW + ((ulong)conT << 16); + return true; + } + return false; + } + + if (FindMovwMovtAddress(data->block1, data->blocksize1, blockOffset, out uint reg1, out ulong addr1) && + FindMovwMovtAddress(data->block2, data->blocksize2, blockOffset, out uint reg2, out ulong addr2) && reg1 == reg2) + { + // Use the constructed constant instead, and skip the movt instruction. + *offset1 = addr1; + *offset2 = addr2; + *skip1 = *skip2 = 1; + return true; + } + return false; + } + + // Determines whether two syntactically different constants are semantically equivalent, with heuristics. + private static bool compareOffsets(DiffData* data, nuint blockOffset, nuint instrLen, ulong offset1, ulong offset2) + { + // The trivial case. + if (offset1 == offset2) + return true; + + // For wasm32, the recorded relocations are the source of truth: handles materialize as i32.const + // immediates with padded ULEB128/SLEB128 placeholders, which the JIT records separately in a reloc + // table. + if (GetSpmiTargetArchitecture() == TargetArchitecture.Wasm32) + return compareOffsetsWasm(data, blockOffset, instrLen, offset1, offset2); + + nuint ip1 = data->originalBlock1 + blockOffset; + nuint ip2 = data->originalBlock2 + blockOffset; + nuint ipRelOffset1 = ip1 + instrLen + (nuint)offset1; + nuint ipRelOffset2 = ip2 + instrLen + (nuint)offset2; + + // A call to a flat address, the most common case. Only the lower 32 bits are compared, the best that + // can be done with the current replay form. + if ((uint)ipRelOffset1 == (uint)ipRelOffset2) + return true; + + // An offset into the read-only section (for example, loading a float value), that fits in the section. + nuint roOffset1a = (nuint)offset1 - data->originalDataBlock1; + nuint roOffset2a = (nuint)offset2 - data->originalDataBlock2; + if (roOffset1a == roOffset2a && roOffset1a < data->datablockSize1) + return true; + + // An IP-relative offset into the read-only data section. + nuint roOffset1b = ipRelOffset1 - data->originalDataBlock1; + nuint roOffset2b = ipRelOffset2 - data->originalDataBlock2; + if (roOffset1b == roOffset2b && roOffset1b < data->datablockSize1) + return true; + + // An address in our own code section. + nuint gOffset1a = (nuint)offset1 - data->originalBlock1; + nuint gOffset2a = (nuint)offset2 - data->originalBlock2; + if (gOffset1a == gOffset2a && gOffset1a < data->blocksize1) + return true; + + // An address in the other code block. + nuint gOffset1b = (nuint)offset1 - data->otherCodeBlock1; + nuint gOffset2b = (nuint)offset2 - data->otherCodeBlock2; + if (gOffset1b == gOffset2b && gOffset1b < data->otherCodeBlockSize1) + return true; + + // An offset into the hot code block from the cold code block (why?). It would be nice to check that it + // fits in the other code block. + nuint ocOffset1 = ipRelOffset1 - data->otherCodeBlock1; + nuint ocOffset2 = ipRelOffset2 - data->otherCodeBlock2; + if (ocOffset1 == ocOffset2) + return true; + + // It's rather odd to look up artifacts of cr1 in cr2; one would expect cr1.map(artifact1) to be compared + // with cr2.map(artifact2). This is left as it is for now, since it seems to work. + + // The VSD calling case. + if (s_cr2.CallTargetTypes.GetIndex(ipRelOffset1 - 8) != -1) + return true; + + // The x86 VSD calling cases. + if (s_cr2.CallTargetTypes.GetIndex((nuint)offset1 - 4) != -1 || s_cr2.CallTargetTypes.GetIndex((nuint)offset2) != -1) + return true; + + return false; + } + + // For wasm32, the integer immediates that materialize JIT handles (function indices, type indices, memory + // addresses, globals) are 5-byte ULEB128/SLEB128 placeholders (80 80 80 80 00), which the JIT records + // separately in a reloc table. For un-prefixed forms like i32.const and call, the placeholder is at the + // opcode byte + 1; for un-prefixed memory ops (i32.load, i32.store, ...), the layout is + // :u32 :u32, so it's at the opcode byte + 2. Either way, both JITs write the + // same placeholder bytes, so the byte-by-byte comparison succeeds at reloc sites without any patching. So + // an immediate mismatch here is one of: + // + // 1. A hard-coded non-reloc literal that differs: a real codegen change. + // 2. A reloc site with relocs on both sides but different immediates (for example, if a future change + // patches the placeholder into real bytes): equivalent when the reloc kinds match, and the targets are + // equal after the addlDelta correction. + // 3. A reloc on only one side: genuinely asymmetric codegen. + // + // 'blockOffset' is the opcode byte's offset in the framed buffer, per the coredistools Wasm32 contract. The + // recorded reloc location is the payload byte, which can be at the opcode byte + 1, + 2, or further for + // prefixed opcodes; so the entire immediate window [blockOffset + 1, blockOffset + instrLen) is searched. + private static bool compareOffsetsWasm(DiffData* data, nuint blockOffset, nuint instrLen, ulong offset1, ulong offset2) + { + if (offset1 == offset2) + return true; + + // A single-byte opcode (without an immediate) shouldn't get here at all; treat it as a real mismatch. + nuint windowSize = instrLen > 1 ? instrLen - 1 : 0; + if (windowSize == 0) + return false; + + // Multiple relocs in a single instruction aren't emitted today, so the first one is used. + if (!s_cr1.findRelocationInRange(data->originalBlock1, blockOffset + 1, windowSize, out Agnostic_RecordRelocation reloc1) || + !s_cr2.findRelocationInRange(data->originalBlock2, blockOffset + 1, windowSize, out Agnostic_RecordRelocation reloc2)) + { + // A non-reloc immediate mismatch (case 1), or an asymmetric reloc (case 3). + return false; + } + + // Different reloc kinds at the same site are a real codegen change. + if (reloc1.fRelocType != reloc2.fRelocType) + return false; + + // Different targets are a different handle picked for the same source: a real mismatch for now. A future + // revision could plug in handle-equivalence logic, like the remapping in compareOffsets. + return reloc1.target + (ulong)(long)(int)reloc1.addlDelta == reloc2.target + (ulong)(long)(int)reloc2.addlDelta; + } + + // Compares two code sections for syntactic equality: the core of the asm diffing. + private bool compareCodeSection(byte* block1, uint blocksize1, byte* datablock1, uint datablockSize1, void* originalBlock1, + void* originalDataBlock1, void* otherCodeBlock1, uint otherCodeBlockSize1, byte* block2, uint blocksize2, byte* datablock2, + uint datablockSize2, void* originalBlock2, void* originalDataBlock2, void* otherCodeBlock2, uint otherCodeBlockSize2) + { + var data = new DiffData + { + block1 = block1, + blocksize1 = blocksize1, + datablock1 = datablock1, + datablockSize1 = datablockSize1, + originalBlock1 = (nuint)originalBlock1, + originalDataBlock1 = (nuint)originalDataBlock1, + otherCodeBlock1 = (nuint)otherCodeBlock1, + otherCodeBlockSize1 = otherCodeBlockSize1, + block2 = block2, + blocksize2 = blocksize2, + datablock2 = datablock2, + datablockSize2 = datablockSize2, + originalBlock2 = (nuint)originalBlock2, + originalDataBlock2 = (nuint)originalDataBlock2, + otherCodeBlock2 = (nuint)otherCodeBlock2, + otherCodeBlockSize2 = otherCodeBlockSize2, + }; + + bool areSame = g_PtrNearDiffCodeBlocks(corAsmDiff, &data, (byte*)originalBlock1, block1, blocksize1, (byte*)originalBlock2, block2, blocksize2) != 0; + if (!areSame) + g_PtrDumpDiffBlocks(corAsmDiff, (byte*)originalBlock1, block1, blocksize1, (byte*)originalBlock2, block2, blocksize2); + return areSame; + } + + private static bool compareReadOnlyDataBlock(uint blocksize1, uint blocksize2) + { + // No RO data. + if (blocksize1 == 0 && blocksize2 == 0) + return true; + + if (blocksize1 != blocksize2) + { + Logger.LogVerbose($"compareReadOnlyDataBlock found non-matching sizes {blocksize1} {blocksize2}"); + return false; + } + + // TODO-Cleanup: the values in the data block seem to wobble. A good near comparison for them needs + // further investigation. + return true; + } + + private static bool compareEHInfo(CompileResult cr1, CompileResult cr2) + { + uint cEHSize_1 = cr1.repSetEHcount(); + uint cEHSize_2 = cr2.repSetEHcount(); + + // No exception handling. + if (cEHSize_1 == 0 && cEHSize_2 == 0) + return true; + + if (cEHSize_1 != cEHSize_2) + { + Logger.LogVerbose($"compareEHInfo found non-matching sizes {cEHSize_1} {cEHSize_2}"); + return false; + } + + for (uint i = 0; i < cEHSize_1; i++) + { + Agnostic_CORINFO_EH_CLAUSE eh1 = cr1.repSetEHinfo(i); + Agnostic_CORINFO_EH_CLAUSE eh2 = cr2.repSetEHinfo(i); + if (eh1.Flags != eh2.Flags) + { + Logger.LogVerbose($"EH flags don't match {eh1.Flags} != {eh2.Flags}"); + return false; + } + if (eh1.TryOffset != eh2.TryOffset || eh1.TryLength != eh2.TryLength) + { + Logger.LogVerbose($"EH try information don't match, offset: {eh1.TryOffset} {eh2.TryOffset}, length: {eh1.TryLength} {eh2.TryLength}"); + return false; + } + if (eh1.HandlerOffset != eh2.HandlerOffset || eh1.HandlerLength != eh2.HandlerLength) + { + Logger.LogVerbose($"EH handler information don't match, offset: {eh1.HandlerOffset} {eh2.HandlerOffset}, length: {eh1.HandlerLength} {eh2.HandlerLength}"); + return false; + } + if (eh1.ClassToken != eh2.ClassToken) + { + Logger.LogVerbose($"EH class tokens don't match {eh1.ClassToken}!={eh2.ClassToken}"); + return false; + } + } + + return true; + } + + private static bool compareGCInfo(CompileResult cr1, CompileResult cr2) + { + cr1.repAllocGCInfo(out nuint gcInfo1Size, out void* gcInfo1); + cr2.repAllocGCInfo(out nuint gcInfo2Size, out void* gcInfo2); + + if (gcInfo1Size != gcInfo2Size) + { + Logger.LogVerbose($"Reported GCInfo sizes don't match: {(uint)gcInfo1Size} != {(uint)gcInfo2Size}"); + return false; + } + + if (!new ReadOnlySpan(gcInfo1, (int)gcInfo1Size).SequenceEqual(new ReadOnlySpan(gcInfo2, (int)gcInfo2Size))) + { + Logger.LogVerbose("GCInfo doesn't match."); + return false; + } + + return true; + } + + private static bool compareVars(MethodContext mc, CompileResult cr1, CompileResult cr2) + { + CORINFO_METHOD_INFO info = mc.repCompileMethod(out _, out _); + + bool set1 = cr1.repSetVars(out CORINFO_METHOD_STRUCT_* ftn_1, out uint cVars_1, out _); + bool set2 = cr2.repSetVars(out CORINFO_METHOD_STRUCT_* ftn_2, out uint cVars_2, out _); + if (!set1 && !set2) + return true; // There are no vars for either. + if (set1 != set2) + { + Logger.LogVerbose("missing matching vars sets"); + return false; + } + + // No vars. + if (cVars_1 == 0 && cVars_2 == 0) + return true; + + if (ftn_1 != ftn_2) + { + // This situation is interesting to find out about. + if (Debugger.IsAttached) + Debugger.Break(); + Logger.LogVerbose(CFormat.Sprintf("compareVars found non-matching CORINFO_METHOD_HANDLE %p %p", CastHandle(ftn_1), CastHandle(ftn_2))); + return false; + } + if (ftn_1 != info.ftn) + { + Logger.LogVerbose(CFormat.Sprintf("compareVars found issues with the CORINFO_METHOD_HANDLE %p %p", CastHandle(ftn_1), CastHandle(info.ftn))); + return false; + } + + if (cVars_1 != cVars_2) + { + Logger.LogVerbose($"compareVars found non-matching var count {cVars_1} {cVars_2}"); + return false; + } + + // TODO-Cleanup: the values in the NativeVarInfo array seem to wobble. A good near comparison for them + // needs further investigation. + return true; + } + + private static bool compareBoundaries(MethodContext mc, CompileResult cr1, CompileResult cr2) + { + bool set1 = cr1.repSetBoundaries(out CORINFO_METHOD_STRUCT_* ftn_1, out uint cMap_1, out OffsetMapping* map_1); + bool set2 = cr2.repSetBoundaries(out CORINFO_METHOD_STRUCT_* ftn_2, out uint cMap_2, out OffsetMapping* map_2); + if (!set1 && !set2) + return true; // There are no boundaries for either. + if (set1 != set2) + { + Logger.LogVerbose("missing matching boundary sets"); + return false; + } + + if (ftn_1 != ftn_2) + { + Logger.LogVerbose(CFormat.Sprintf("compareBoundaries found non-matching CORINFO_METHOD_HANDLE %p %p", CastHandle(ftn_1), CastHandle(ftn_2))); + return false; + } + + // No maps. + if (cMap_1 == 0 && cMap_2 == 0) + return true; + + if (cMap_1 != cMap_2) + { + Logger.LogVerbose($"compareBoundaries found non-matching var count {cMap_1} {cMap_2}"); + return false; + } + + for (uint i = 0; i < cMap_1; i++) + { + if (map_1[i].ilOffset != map_2[i].ilOffset) + { + Logger.LogVerbose($"compareBoundaries found non-matching ilOffset {map_1[i].ilOffset} {map_2[i].ilOffset} for map: {i}"); + return false; + } + if (map_1[i].nativeOffset != map_2[i].nativeOffset) + { + Logger.LogVerbose($"compareBoundaries found non-matching nativeOffset {map_1[i].nativeOffset} {map_2[i].nativeOffset} for map: {i}"); + return false; + } + if (map_1[i].source != map_2[i].source) + { + Logger.LogVerbose($"compareBoundaries found non-matching source {(uint)map_1[i].source} {(uint)map_2[i].source} for map: {i}"); + return false; + } + } + + return true; + } + + // A compiled method's code and data blocks, and the addresses they had when compiled. + private struct Blocks + { + public uint hotCodeSize, coldCodeSize, roDataSize1, roDataSize2, xcptnsCount; + public byte* hotCodeBlock, coldCodeBlock, roDataBlock; + public void* origHotCodeBlock, origColdCodeBlock, origRoDataBlock1, origRoDataBlock2; + + public Blocks(CompileResult cr) + { + Agnostic_AllocMemDetails value = cr.repAllocMem(out hotCodeBlock, out coldCodeBlock, out roDataBlock); + hotCodeSize = value.hotCodeSize; + coldCodeSize = value.coldCodeSize; + roDataSize1 = value.roDataSize; + xcptnsCount = value.xcptnsCount; + origHotCodeBlock = (void*)value.hotCodeBlock; + origColdCodeBlock = (void*)value.coldCodeBlock; + origRoDataBlock1 = (void*)value.roDataBlock; + + // On Arm64 the constant pool is appended to the method's code, so the hot code size is the sum of + // their sizes. Adjust the sizes and the RO data block pointers. + if (GetSpmiTargetArchitecture() == TargetArchitecture.ARM64 && hotCodeSize > 0) + { + cr.repCompileMethod(out _, out uint nativeSizeOfCode, out _); + roDataSize2 = roDataSize1; + roDataSize1 = hotCodeSize - nativeSizeOfCode; + roDataBlock = hotCodeBlock + nativeSizeOfCode; + origRoDataBlock2 = origRoDataBlock1; + origRoDataBlock1 = (byte*)origHotCodeBlock + nativeSizeOfCode; + hotCodeSize = nativeSizeOfCode; + } + } + + public readonly string Describe(int n) => CFormat.Sprintf("HCS%d %d CCS%d %d RDS%d %d xcpnt%d %d HCB %p CCB %p RDB %p ohcb %p occb %p odb %p", + n, hotCodeSize, n, coldCodeSize, n, roDataSize1, n, xcptnsCount, (ulong)hotCodeBlock, (ulong)coldCodeBlock, (ulong)roDataBlock, + CastHandle(origHotCodeBlock), CastHandle(origColdCodeBlock), CastHandle(origRoDataBlock1)); + + // Fixes up the code with the recorded relocations, for the original base addresses. + public readonly void ApplyRelocs(MethodContext mc, CompileResult cr) + { + var rc = new RelocContext + { + mc = mc, + hotCodeAddress = (nuint)hotCodeBlock, + hotCodeSize = hotCodeSize, + coldCodeAddress = (nuint)coldCodeBlock, + coldCodeSize = coldCodeSize, + roDataAddress = (nuint)roDataBlock, + roDataSize1 = roDataSize1, + roDataSize2 = roDataSize2, + originalHotCodeAddress = (nuint)origHotCodeBlock, + originalColdCodeAddress = (nuint)origColdCodeBlock, + originalRoDataAddress1 = (nuint)origRoDataBlock1, + originalRoDataAddress2 = (nuint)origRoDataBlock2, + }; + cr.applyRelocs(ref rc, hotCodeBlock, hotCodeSize, origHotCodeBlock); + cr.applyRelocs(ref rc, coldCodeBlock, coldCodeSize, origColdCodeBlock); + cr.applyRelocs(ref rc, roDataBlock, roDataSize1, origRoDataBlock1); + } + } + + // Compares two compilations of a method, after fixing up their code with the relocations recorded during + // the compilations, for the original base addresses. Returns whether they're the same. + public bool compare(MethodContext mc, CompileResult cr1, CompileResult cr2) + { + var b1 = new Blocks(cr1); + var b2 = new Blocks(cr2); + + Logger.LogDebug(b1.Describe(1)); + Logger.LogDebug(b2.Describe(2)); + + b1.ApplyRelocs(mc, cr1); + b2.ApplyRelocs(mc, cr2); + + s_cr1 = cr1; + s_cr2 = cr2; + + return compareCodeSection(b1.hotCodeBlock, b1.hotCodeSize, b1.roDataBlock, b1.roDataSize1, b1.origHotCodeBlock, b1.origRoDataBlock1, + b1.origColdCodeBlock, b1.coldCodeSize, b2.hotCodeBlock, b2.hotCodeSize, b2.roDataBlock, b2.roDataSize1, b2.origHotCodeBlock, + b2.origRoDataBlock1, b2.origColdCodeBlock, b2.coldCodeSize) && + compareCodeSection(b1.coldCodeBlock, b1.coldCodeSize, b1.roDataBlock, b1.roDataSize1, b1.origColdCodeBlock, b1.origRoDataBlock1, + b1.origHotCodeBlock, b1.hotCodeSize, b2.coldCodeBlock, b2.coldCodeSize, b2.roDataBlock, b2.roDataSize1, b2.origColdCodeBlock, + b2.origRoDataBlock1, b2.origHotCodeBlock, b2.hotCodeSize) && + compareReadOnlyDataBlock(b1.roDataSize1, b2.roDataSize1) && + compareEHInfo(cr1, cr2) && + compareGCInfo(cr1, cr2) && + compareVars(mc, cr1, cr2) && + compareBoundaries(mc, cr1, cr2); + } +} diff --git a/src/coreclr/tools/superpmi/managed/superpmi/Output.cs b/src/coreclr/tools/superpmi/managed/superpmi/Output.cs new file mode 100644 index 00000000000000..db054ba10e0532 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/superpmi/Output.cs @@ -0,0 +1,111 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.IO; +using System.Text; +using Internal.JitInterface; + +namespace SuperPmi.Replay; + +// A buffered output file, written as is (without newline translation). +internal sealed class FileWriter : IDisposable +{ + private readonly StreamWriter _writer; + + private FileWriter(StreamWriter writer) => _writer = writer; + + public static FileWriter CreateNew(string path) + { + try + { + return new FileWriter(new StreamWriter(new FileStream(path, FileMode.Create, FileAccess.Write), new UTF8Encoding(false), 1 << 16)); + } + catch (Exception e) when (e is IOException or UnauthorizedAccessException) + { + return null; + } + } + + public void Print(string value) => _writer.Write(value); + + public void Printf(string format, params object[] args) => _writer.Write(CFormat.Sprintf(format, args)); + + public void PrintQuotedCsvField(string value) => _writer.Write($"\"{value.Replace("\"", "\"\"")}\""); + + public void Dispose() => _writer.Dispose(); +} + +// Emits method statistics as CSV, to .stats. +internal sealed unsafe class MethodStatsEmitter : IDisposable +{ + private readonly FileWriter _statsFile; + private string _statsTypes; + + public MethodStatsEmitter(string nameOfInput) + { + string fileName = nameOfInput + ".stats"; + _statsFile = FileWriter.CreateNew(fileName); + if (_statsFile == null) + Logger.LogError($"Failed to open output file '{fileName}'."); + } + + private bool Has(char type) => _statsTypes.Contains('*') || _statsTypes.Contains(type) || _statsTypes.Contains(char.ToUpperInvariant(type)); + + // The CSV header row. + public void SetStatsTypes(string types) + { + _statsTypes = types; + if (_statsFile == null) + return; + + var header = new StringBuilder(); + if (Has('h')) + header.Append("HASH,"); + if (Has('n')) + header.Append("METHOD_NUMBER,"); + if (Has('i')) + header.Append("IL_CODE_SIZE,"); + if (Has('a')) + header.Append("ASM_CODE_SIZE,"); + if (Has('t')) + header.Append("Time1,Time2,"); + WriteRow(header); + } + + public void Emit(int methodNumber, MethodContext mc, ulong firstTime, ulong secondTime) + { + if (_statsFile == null) + return; + + var row = new StringBuilder(); + if (Has('h')) + row.Append(mc.dumpMethodHashToBuffer()).Append(','); + if (Has('n')) + row.Append(methodNumber).Append(','); + if (Has('i')) + row.Append(mc.repCompileMethod(out _, out _).ILCodeSize).Append(','); + if (Has('a')) + { + // A compile result without code is likely a thin method context. + uint codeSize = 0; + if (mc.cr.CompileMethod != null) + mc.cr.repCompileMethod(out _, out codeSize, out _); + row.Append(codeSize).Append(','); + } + if (Has('t')) + row.Append(firstTime).Append(',').Append(secondTime).Append(','); + WriteRow(row); + } + + // Replaces the final ',' with a newline. + private void WriteRow(StringBuilder row) + { + if (row.Length == 0) + return; + row[row.Length - 1] = '\n'; + _statsFile.Print(row.ToString()); + } + + public void Dispose() => _statsFile?.Dispose(); +} diff --git a/src/coreclr/tools/superpmi/managed/superpmi/ParallelReplay.cs b/src/coreclr/tools/superpmi/managed/superpmi/ParallelReplay.cs new file mode 100644 index 00000000000000..7ed2d8039c9cf0 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/superpmi/ParallelReplay.cs @@ -0,0 +1,420 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SuperPmi.Replay; + +// Parallel mode: runs SuperPMI child processes on interleaved method contexts ("-stride"), and merges their +// output, failing method context lists, and details. +internal static class ParallelReplay +{ + // CoreCLR's MAXIMUM_WAIT_OBJECTS. + private const int MaximumWaitObjects = 64; + + private static volatile bool s_closeRequested; + + private sealed class PerWorkerData + { + public string failingMCListPath; + public string detailsPath; + public string stdOutputPath; + public string stdErrorPath; + public SpmiResult resultCode = SpmiResult.GeneralFailure; + } + + // The arguments passed to the child processes. These aren't passed through: -parallel, -writeLogFile (the + // parent writes the log, from the output of the children), -reproName, -coredistools, -skipCleanup, + // -failingMCList, and -details. + // + // With a verbosity that includes info, a child outputs a "Loaded/Jitted/FailedCompile/Excluded/Missing[/Diffs]" + // line, which the parent parses and sums up. + private static List ConstructChildProcessArgs(Options o) + { + var args = new List(); + void AddBool(bool b, string arg) + { + if (b) + args.Add(arg); + } + void AddString(string s, string arg) + { + if (s != null) + args.AddRange([arg, s]); + } + // Only an integer that differs from the default, as a proxy for whether it was parsed. + void AddInt(int i, string arg, int defaultValue) + { + if (i != defaultValue) + args.AddRange([arg, i.ToString()]); + } + void AddJitOptions(LightWeightMap jitOptions, params string[] optionName) + { + for (int i = 0; i < (jitOptions?.GetCount() ?? 0); i++) + args.AddRange([.. optionName, $"{jitOptions.GetString(jitOptions.GetKey(i))}={jitOptions.GetString(jitOptions.GetItem(i))}"]); + } + + AddBool(o.breakOnError, "-boe"); + AddBool(o.breakOnAssert, "-boa"); + AddBool(o.breakOnException, "-box"); + AddBool(o.ignoreStoredConfig, "-ignoreStoredConfig"); + AddBool(o.applyDiff, "-applyDiff"); + AddString(o.verbosity, "-verbosity"); + AddString(o.reproName, "-reproName"); + AddString(o.methodStatsTypes, "-emitMethodStats"); + AddString(o.hash, "-matchHash"); + AddString(o.targetArchitecture, "-target"); + AddString(o.compileList, "-compile"); + AddInt(o.failureLimit, "-failureLimit", -1); + AddInt(o.repeatCount, "-repeatCount", 1); + AddJitOptions(o.forceJitOptions, "-jitoption", "force"); + AddJitOptions(o.forceJit2Options, "-jit2option", "force"); + AddJitOptions(o.jitOptions, "-jitoption"); + AddJitOptions(o.jit2Options, "-jit2option"); + if (o.nameOfJit != null) + args.Add(o.nameOfJit); + if (o.nameOfJit2 != null) + args.Add(o.nameOfJit2); + if (o.nameOfInputMethodContextFile != null) + args.Add(o.nameOfInputMethodContextFile); + return args; + } + + public static int Run(Options o, string program) + { + Stopwatch st = Stopwatch.StartNew(); + + // The child processes share the console, so they also get Ctrl+C. + Console.CancelKeyPress += (_, e) => + { + s_closeRequested = true; + e.Cancel = true; + }; + + string tempPath = Path.GetTempPath(); + + if (o.workerCount <= 0) + o.workerCount = OperatingSystem.IsWindows() ? Math.Min(Environment.ProcessorCount, MaximumWaitObjects) : Environment.ProcessorCount; + + // The child processes are this same program. + string spmiFilename = Environment.ProcessPath; + List spmiArgs = ConstructChildProcessArgs(o); + + Logger.LogVerbose($"Using child ({spmiFilename}) with args ({string.Concat(spmiArgs.Select(a => " " + a))})"); + if (o.mclFilename != null) + Logger.LogVerbose($" failingMCList={o.mclFilename}"); + if (o.details != null) + Logger.LogVerbose($" details={o.details}"); + Logger.LogVerbose($" workerCount={o.workerCount}, skipCleanup={(o.skipCleanup ? 1 : 0)}."); + + // A random number in the temporary file names allows running multiple parallel SuperPMI at once. + uint randNumber = (uint)Random.Shared.NextInt64(uint.MaxValue + 1L); + + var perWorkerData = new PerWorkerData[o.workerCount]; + for (int i = 0; i < o.workerCount; i++) + { + perWorkerData[i] = new PerWorkerData + { + failingMCListPath = o.mclFilename != null ? $"{tempPath}ParallelSuperPMI-{randNumber}-{i}.mcl" : null, + detailsPath = o.details != null ? $"{tempPath}ParallelSuperPMI-Details-{randNumber}-{i}.csv" : null, + stdOutputPath = $"{tempPath}ParallelSuperPMI-stdout-{randNumber}-{i}.txt", + stdErrorPath = $"{tempPath}ParallelSuperPMI-stderr-{randNumber}-{i}.txt", + }; + } + + var processes = new Process[o.workerCount]; + var outputCopies = new List(); + for (int i = 0; i < o.workerCount; i++) + { + PerWorkerData wd = perWorkerData[i]; + var startInfo = new ProcessStartInfo(spmiFilename) + { + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + }; + startInfo.ArgumentList.Add("-stride"); + startInfo.ArgumentList.Add((i + 1).ToString()); + startInfo.ArgumentList.Add(o.workerCount.ToString()); + if (wd.failingMCListPath != null) + { + startInfo.ArgumentList.Add("-failingMCList"); + startInfo.ArgumentList.Add(wd.failingMCListPath); + } + if (wd.detailsPath != null) + { + startInfo.ArgumentList.Add("-details"); + startInfo.ArgumentList.Add(wd.detailsPath); + } + startInfo.ArgumentList.Add("-v"); + startInfo.ArgumentList.Add("ewmin"); + foreach (string arg in spmiArgs) + startInfo.ArgumentList.Add(arg); + + Logger.LogDebug($"stdout {i}={wd.stdOutputPath}"); + Logger.LogDebug($"stderr {i}={wd.stdErrorPath}"); + Logger.LogDebug($"StartProcess commandLine={spmiFilename}{string.Concat(startInfo.ArgumentList.Select(a => " " + a))}"); + + Stream stdout, stderr; + try + { + stdout = new FileStream(wd.stdOutputPath, FileMode.Create, FileAccess.Write, FileShare.Read); + stderr = new FileStream(wd.stdErrorPath, FileMode.Create, FileAccess.Write, FileShare.Read); + processes[i] = Process.Start(startInfo); + } + catch (Exception e) when (e is IOException or UnauthorizedAccessException or System.ComponentModel.Win32Exception) + { + Logger.LogError($"Unable to start the SuperPMI worker process. {e.Message}"); + return -1; + } + + outputCopies.Add(CopyAndClose(processes[i].StandardOutput.BaseStream, stdout)); + outputCopies.Add(CopyAndClose(processes[i].StandardError.BaseStream, stderr)); + } + + foreach (Process process in processes) + process.WaitForExit(); + Task.WaitAll(outputCopies); + + SpmiResult result = SpmiResult.Success; + + if (!s_closeRequested) + { + // If any child returns non-zero, return non-zero, to indicate failure. + for (int i = 0; i < o.workerCount; i++) + { + var childResult = (SpmiResult)processes[i].ExitCode; + if (childResult is not (SpmiResult.Success or SpmiResult.Diffs or SpmiResult.Misses or SpmiResult.Error or SpmiResult.JitFailedToInit)) + { + // For example, if the child was OOM-killed. + Logger.LogError($"Child process {i} exited with code {(uint)processes[i].ExitCode}"); + childResult = SpmiResult.GeneralFailure; + } + + perWorkerData[i].resultCode = childResult; + + // In priority: the first failures are the most important to propagate. + if (childResult != result) + { + foreach (SpmiResult r in (ReadOnlySpan)[SpmiResult.GeneralFailure, SpmiResult.JitFailedToInit, SpmiResult.Error, SpmiResult.Diffs, SpmiResult.Misses]) + { + if (result == r || childResult == r) + { + result = r; + break; + } + } + } + } + + bool usageError = false; + int loaded = 0, jitted = 0, failed = 0, excluded = 0, missing = 0, diffs = 0; + + // Log the stderr of the children as errors, and parse their stdout for the counts. + for (int i = 0; i < o.workerCount; i++) + { + PerWorkerData wd = perWorkerData[i]; + ProcessChildStdErr(wd.stdErrorPath); + ProcessChildStdOut(o, wd.stdOutputPath, ref loaded, ref jitted, ref failed, ref excluded, ref missing, ref diffs, ref usageError); + if (usageError) + break; + } + + if (o.mclFilename != null && !usageError) + MergeWorkerMCLs(o.mclFilename, perWorkerData.Select(wd => wd.failingMCListPath)); + + if (o.details != null && !usageError) + MergeWorkerCsvs(o.details, perWorkerData); + + if (!usageError) + { + if (o.applyDiff) + Logger.LogInfo(CFormat.Sprintf(Replay.AsmDiffsSummaryFormatString, loaded, jitted, failed, excluded, missing, diffs)); + else + Logger.LogInfo(CFormat.Sprintf(Replay.SummaryFormatString, loaded, jitted, failed, excluded, missing)); + } + + Logger.LogVerbose(CFormat.Sprintf("Total time: %fms", st.Elapsed.TotalMilliseconds)); + } + + if (!o.skipCleanup) + { + // Delete all the temporary files. + foreach (PerWorkerData wd in perWorkerData) + { + foreach (string path in (ReadOnlySpan)[wd.failingMCListPath, wd.detailsPath, wd.stdOutputPath, wd.stdErrorPath]) + { + if (path != null) + File.Delete(path); + } + } + } + + return (int)result; + } + + private static async Task CopyAndClose(Stream source, Stream destination) + { + await source.CopyToAsync(destination); + await destination.DisposeAsync(); + } + + private static IEnumerable ReadLines(string path) + { + try + { + return File.ReadLines(path); + } + catch (Exception e) when (e is IOException or UnauthorizedAccessException) + { + Logger.LogError($"Unable to open '{path}'."); + return []; + } + } + + private static void ProcessChildStdErr(string stderrFilename) + { + foreach (string line in ReadLines(stderrFilename)) + Logger.LogPassThroughStderr(line); + } + + private static void ProcessChildStdOut(Options o, string stdoutFilename, ref int loaded, ref int jitted, ref int failed, ref int excluded, + ref int missing, ref int diffs, ref bool usageError) + { + foreach (string line in ReadLines(stdoutFilename)) + { + if (line.StartsWith(CommandLine.UsageFirstLine, StringComparison.Ordinal)) + { + // A SuperPMI command line usage error. + usageError = true; + Logger.LogPassThroughStdout(line); + } + else if (line.StartsWith(Replay.AllFormatStringFixedPrefix, StringComparison.Ordinal)) + { + int[] counts = ScanSummary(line, o.applyDiff ? 6 : 5); + if (counts == null) + { + Logger.LogError($"Couldn't parse status message: \"{line}\""); + continue; + } + + loaded += counts[0]; + jitted += counts[1]; + failed += counts[2]; + excluded += counts[3]; + missing += counts[4]; + if (o.applyDiff) + diffs += counts[5]; + else + diffs = -1; + } + else + { + // Pass the output through; the children have the same verbosity. + Logger.LogPassThroughStdout(line); + } + } + } + + // Parses "Loaded %d Jitted %d FailedCompile %d Excluded %d Missing %d[ Diffs %d]" as sscanf would. + private static int[] ScanSummary(string line, int count) + { + ReadOnlySpan labels = ["Loaded", "Jitted", "FailedCompile", "Excluded", "Missing", "Diffs"]; + string[] tokens = line.Split([' ', '\t'], StringSplitOptions.RemoveEmptyEntries); + var counts = new int[count]; + for (int i = 0; i < count; i++) + { + if (2 * i + 1 >= tokens.Length || tokens[2 * i] != labels[i] || !int.TryParse(tokens[2 * i + 1], out counts[i])) + return null; + } + return counts; + } + + // This counts the lines by their carriage returns, as MCList writes them. + private static List ReadMCLToArray(string mclFilename) + { + var result = new List(); + byte[] buff; + try + { + buff = File.ReadAllBytes(mclFilename); + } + catch (Exception e) when (e is IOException or UnauthorizedAccessException) + { + Logger.LogError($"Unable to open '{mclFilename}'. GetLastError()={ErrorHandling.LastError(e)}"); + return result; + } + + int count = buff.Count(b => b == '\r'); + for (int j = 0; result.Count < count && j < buff.Length;) + { + // Seek the first number on the line, read it, and seek to the start of the next line. + while (j < buff.Length && !char.IsAsciiDigit((char)buff[j])) + j++; + int start = j; + while (j < buff.Length && char.IsAsciiDigit((char)buff[j])) + j++; + result.Add(CommandLine.Atoi(Encoding.ASCII.GetString(buff, start, j - start))); + while (j < buff.Length && buff[j] != '\n') + j++; + j++; + } + return result; + } + + private static void MergeWorkerMCLs(string mclFilename, IEnumerable workerMCLs) + { + List mergedMCL = workerMCLs.SelectMany(ReadMCLToArray).Order().ToList(); + try + { + File.WriteAllText(mclFilename, string.Concat(mergedMCL.Select(i => $"{i}\r\n"))); + } + catch (Exception e) when (e is IOException or UnauthorizedAccessException) + { + Logger.LogError($"Failed to open output file '{mclFilename}'. GetLastError()={ErrorHandling.LastError(e)}"); + Logger.LogError($"Unable to write to MCL file {mclFilename}."); + } + } + + // Concatenates the CSV files of the children, with one header. + private static void MergeWorkerCsvs(string csvFilename, PerWorkerData[] workerData) + { + using FileWriter fw = FileWriter.CreateNew(csvFilename); + if (fw == null) + { + Logger.LogError($"Could not create file {csvFilename}"); + return; + } + + bool hasHeader = false; + for (int i = 0; i < workerData.Length; i++) + { + if (workerData[i].resultCode is not (SpmiResult.Success or SpmiResult.Diffs or SpmiResult.Misses or SpmiResult.Error)) + { + Logger.LogWarning($"Skipping merging CSV from child {i} due to result code {(int)workerData[i].resultCode}"); + continue; + } + + IEnumerable lines; + try + { + lines = File.ReadLines(workerData[i].detailsPath); + } + catch (Exception e) when (e is IOException or UnauthorizedAccessException) + { + Logger.LogError($"Could not open child CSV file {workerData[i].detailsPath}"); + continue; + } + + foreach (string line in hasHeader ? lines.Skip(1) : lines) + fw.Print(line + "\n"); + hasHeader = true; + } + } +} diff --git a/src/coreclr/tools/superpmi/managed/superpmi/Program.cs b/src/coreclr/tools/superpmi/managed/superpmi/Program.cs new file mode 100644 index 00000000000000..e63bf77ebdb869 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/superpmi/Program.cs @@ -0,0 +1,44 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace SuperPmi.Replay; + +internal enum SpmiResult +{ + JitFailedToInit = -2, + GeneralFailure = -1, + Success = 0, + Error = 1, + Diffs = 2, + Misses = 3, +} + +internal static class Program +{ + private static int Main(string[] args) + { + try + { + // As in C's argv, the first argument is the program as invoked. + return Replay.Run([Environment.GetCommandLineArgs()[0], .. args]); + } + catch (Exception) when (FlushBeforeCrash()) + { + throw; + } + finally + { + Logger.Shutdown(); + } + } + + // Runs as an exception filter, before an unhandled exception terminates the process without running + // finally blocks, so the output written so far isn't lost. + private static bool FlushBeforeCrash() + { + Logger.Flush(); + return false; + } +} diff --git a/src/coreclr/tools/superpmi/managed/superpmi/Replay.cs b/src/coreclr/tools/superpmi/managed/superpmi/Replay.cs new file mode 100644 index 00000000000000..8722d6dda087e7 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/superpmi/Replay.cs @@ -0,0 +1,451 @@ +// 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.Diagnostics; +using System.IO; + +namespace SuperPmi.Replay; + +internal static class Replay +{ + // Parallel mode parses these status lines from the child processes. They must all start with the same + // fixed prefix, to quickly tell when to parse a line fully. + public const string AllFormatStringFixedPrefix = "Loaded "; + public const string SummaryFormatString = "Loaded %d Jitted %d FailedCompile %d Excluded %d Missing %d"; + public const string AsmDiffsSummaryFormatString = "Loaded %d Jitted %d FailedCompile %d Excluded %d Missing %d Diffs %d"; + + private enum NearDifferResult + { + SuccessWithoutDiff, + SuccessWithDiff, + Failure, + } + + // Runs SuperPMI, returning a SpmiResult. + public static int Run(string[] args) + { + Stopwatch st2 = Stopwatch.StartNew(); + JitInstance jit = null; + JitInstance jit2 = null; + + var o = new Options(); + if (!CommandLine.Parse(args, o)) + return (int)SpmiResult.GeneralFailure; + + if (o.parallel) + return ParallelReplay.Run(o, args[0]); + + if (o.streamFile != null) + return StreamingReplay.Run(o); + + SpmiUtil.BreakOnException = o.breakOnException; + + bool collectThroughput = o.methodStatsTypes != null && o.methodStatsTypes.AsSpan().IndexOfAny('*', 't', 'T') >= 0; + + Logger.LogVerbose($"Using jit({o.nameOfJit}) with input ({o.nameOfInputMethodContextFile})"); + Logger.LogVerbose($" indexCount={o.indexCount} ({string.Join(",", o.indexes ?? [])})"); + if (o.methodStatsTypes != null) + Logger.LogVerbose($" EmitMethodStats-Types={o.methodStatsTypes}"); + if (o.hash != null) + Logger.LogVerbose($" MD5Hash={o.hash}"); + if (o.mclFilename != null) + Logger.LogVerbose($" failingMCList={o.mclFilename}"); + if (o.offset > 0 && o.increment > 0) + Logger.LogVerbose($" offset={o.offset} increment={o.increment}"); + + using MethodStatsEmitter methodStatsEmitter = o.methodStatsTypes != null ? new MethodStatsEmitter(o.nameOfInputMethodContextFile) : null; + methodStatsEmitter?.SetStatsTypes(o.methodStatsTypes); + + var failingToReplayMCL = new MCList(); + if (o.mclFilename != null) + failingToReplayMCL.InitializeMCL(o.mclFilename); + + using FileWriter detailsCsv = o.details != null ? FileWriter.CreateNew(o.details) : null; + if (o.details != null && detailsCsv == null) + { + Logger.LogError($"Could not create file {o.details}"); + return (int)SpmiResult.GeneralFailure; + } + + // The method context reader skips the method contexts that weren't asked for; with an index (.mct) + // file, it does a lot less work. + using var reader = new MethodContextReader(o.nameOfInputMethodContextFile, o.indexes, o.hash, o.offset, o.increment); + if (!reader.isValid()) + return (int)SpmiResult.GeneralFailure; + + int loadedCount = 0; + int jittedCount = 0; + int failToReplayCount = 0; + int errorCount = 0; + int errorCount2 = 0; + int diffsCount = 0; + int missingCount = 0; + int excludedCount = 0; + + Stopwatch st1 = Stopwatch.StartNew(); + using var nearDiffer = new NearDiffer(o.targetArchitecture != null ? SpmiUtil.GetSpmiTargetArchitecture() : null); + + if (o.applyDiff && !nearDiffer.InitAsmDiff()) + return (int)SpmiResult.GeneralFailure; + + if (detailsCsv != null) + { + if (o.applyDiff) + PrintDiffsCsvHeader(detailsCsv); + else + PrintReplayCsvHeader(detailsCsv); + } + + double totalWork = reader.TotalWork() * o.repeatCount; + + while (true) + { + // The progress before reading the method context, since the progress reported below adds the + // per-repeatCount progress for the current one. + double progressBeforeCurrentMC = reader.Progress() * o.repeatCount; + + MethodContextBuffer mcb = reader.GetNextMethodContext(); + if (mcb.Error()) + return (int)SpmiResult.GeneralFailure; + if (mcb.allDone()) + { + Logger.LogDebug("Done processing method contexts"); + break; + } + + // This fails if the method context data is corrupt. + loadedCount++; + int mcIndex = reader.GetMethodContextIndex(); + if (!MethodContext.Initialize(mcIndex, mcb.buff, (uint)mcb.size, readCompileResults: false, out MethodContext mc)) + return (int)SpmiResult.GeneralFailure; + + if (o.ignoreStoredConfig) + mc.ignoreStoredConfig = true; + + if (reader.IsMethodExcluded(mc)) + { + excludedCount++; + Logger.LogInfo($"main method {mcIndex} of size {mc.methodSize} with was excluded from the compilation."); + continue; + } + + // Compile the method context as many times as asked for (once by default). + for (int iter = 0; iter < o.repeatCount; iter++) + { + if (jit == null) + { + var stInitJit = new Stopwatch(); + jit = JitInstance.InitJit(o.nameOfJit, o.breakOnAssert, stInitJit, mc, o.forceJitOptions, o.jitOptions); + if (jit == null) + return (int)SpmiResult.JitFailedToInit; // InitJit already printed a failure message. + + if (o.nameOfJit2 != null) + { + jit2 = JitInstance.InitJit(o.nameOfJit2, o.breakOnAssert, stInitJit, mc, o.forceJit2Options, o.jit2Options); + if (jit2 == null) + return (int)SpmiResult.JitFailedToInit; + + // A module shared by the two JIT instances would corrupt the JIT's global state (such as + // g_jitHost and JitConfig), with spurious diffs and intermittent crashes. + if (jit2.Module == jit.Module) + { + Logger.LogError($"The baseline JIT ('{o.nameOfJit}') and diff JIT ('{o.nameOfJit2}') resolve to the same loaded module. " + + "They must be distinct files; copy one JIT to a different path."); + return (int)SpmiResult.JitFailedToInit; + } + } + } + + // For asm diffs, the compile result of the first JIT is kept while compiling with the second. + CompileResult crl = null; + + if (mc.WasEnvironmentChanged(jit.getEnvironment())) + { + if (!jit.resetConfig(mc)) + Logger.LogError("JIT can't reset environment"); + if (o.nameOfJit2 != null && !jit2.resetConfig(mc)) + Logger.LogError("JIT2 can't reset environment"); + } + + jittedCount++; + Stopwatch st3 = Stopwatch.StartNew(); + ReplayResults res = jit.CompileMethod(mc, mcIndex, collectThroughput); + st3.Stop(); + Logger.LogDebug(CFormat.Sprintf("Method %d compiled%s in %fms, result %d", mcIndex, o.nameOfJit2 == null ? "" : " by JIT1", + st3.Elapsed.TotalMilliseconds, (int)res.Result)); + + if (res.Result == ReplayResult.Success) + { + if (Logger.IsEnabled(LogLevel.Debug)) + mc.cr.dumpToConsole(); // Dump the compile results when debug logging. + } + else if (res.Result == ReplayResult.Error) + { + errorCount++; + Logger.LogError($"Method {mcIndex} of size {mc.methodSize} failed to load and compile correctly{(o.nameOfJit2 == null ? "" : " by JIT1")} ({o.nameOfJit})."); + if (errorCount == o.failureLimit) + { + Logger.LogError($"More than {o.failureLimit} methods failed{(o.nameOfJit2 == null ? "" : " by JIT1")}. Skip compiling remaining methods."); + goto doneRepeatCount; + } + if (o.reproName != null && o.indexCount == -1 && !WriteRepro(o.reproName, mcIndex, mc)) + return (int)SpmiResult.GeneralFailure; + if (o.breakOnError) + { + if (o.indexCount == -1) + Logger.LogInfo($"HINT: to repro add '-c {mcIndex}' to cmdline"); + Debugger.Break(); + } + } + + var res2 = new ReplayResults { Result = ReplayResult.Success }; + if (o.nameOfJit2 != null) + { + // Keep the first JIT's compile result, and compile with the second JIT. + crl = mc.cr; + mc.cr = new CompileResult(); + + Stopwatch st4 = Stopwatch.StartNew(); + res2 = jit2.CompileMethod(mc, mcIndex, collectThroughput); + st4.Stop(); + Logger.LogDebug(CFormat.Sprintf("Method %d compiled by JIT2 in %fms, result %d", mcIndex, st4.Elapsed.TotalMilliseconds, (int)res2.Result)); + + if (res2.Result == ReplayResult.Success) + { + if (Logger.IsEnabled(LogLevel.Debug)) + mc.cr.dumpToConsole(); + } + else if (res2.Result == ReplayResult.Error) + { + errorCount2++; + Logger.LogError($"Method {mcIndex} of size {mc.methodSize} failed to load and compile correctly by JIT2 ({o.nameOfJit2})."); + if (errorCount2 == o.failureLimit) + { + Logger.LogError($"More than {o.failureLimit} methods compilation failed by JIT2. Skip compiling remaining methods."); + goto doneRepeatCount; + } + } + } + + if (res.Result == ReplayResult.Success && res2.Result == ReplayResult.Success) + { + if (collectThroughput) + { + if (o.nameOfJit2 != null) + { + (crl.clockCyclesToCompile, mc.cr.clockCyclesToCompile) = ClosestTimes(jit.times, jit2.times); + methodStatsEmitter?.Emit(mcIndex, mc, crl.clockCyclesToCompile, mc.cr.clockCyclesToCompile); + } + else + { + mc.cr.clockCyclesToCompile = Math.Min(jit.times[0], jit.times[1]); + methodStatsEmitter?.Emit(mcIndex, mc, mc.cr.clockCyclesToCompile, 0); + } + } + else + { + methodStatsEmitter?.Emit(mcIndex, mc, ulong.MaxValue, ulong.MaxValue); + } + + if (o.applyDiff) + { + // Diffing needs two compile results: from two JIT invocations, or one from the method context file. + NearDifferResult diffResult = NearDifferResult.Failure; + if (crl.AllocMem == null || mc.cr.AllocMem == null) + { + Logger.LogError($"method {mcIndex} is missing a compileResult, cannot do diffing"); + } + else + { + diffResult = InvokeNearDiffer(nearDiffer, mc, crl, mcIndex); + switch (diffResult) + { + case NearDifferResult.SuccessWithDiff: + // This is a difference in the asm of the two JITs, not a replay failure. It's in the + // details if there are any, and otherwise in the failing method context list. + diffsCount++; + if (o.details == null) + failingToReplayMCL.AddMethodToMCL(mcIndex); + break; + case NearDifferResult.Failure: + if (o.mclFilename != null) + failingToReplayMCL.AddMethodToMCL(mcIndex); + break; + } + } + + if (detailsCsv != null) + PrintDiffsCsvRow(detailsCsv, mcIndex, (uint)mcb.size, res, res2, hasDiff: diffResult != NearDifferResult.SuccessWithoutDiff); + } + else if (detailsCsv != null) + { + PrintReplayCsvRow(detailsCsv, mcIndex, (uint)mcb.size, res); + } + } + else + { + failToReplayCount++; + + // Methods that don't compile because of missing JIT-EE information are still added to the + // failing method context list, but without a repro. + if (o.mclFilename != null) + failingToReplayMCL.AddMethodToMCL(mcIndex); + + if (res.Result == ReplayResult.Miss || res2.Result == ReplayResult.Miss) + missingCount++; + + if (detailsCsv != null) + { + if (o.applyDiff) + PrintDiffsCsvRow(detailsCsv, mcIndex, (uint)mcb.size, res, res2, hasDiff: false); + else + PrintReplayCsvRow(detailsCsv, mcIndex, (uint)mcb.size, res); + } + } + + // Write a progress message if necessary. + const int progressInterval = 500; + if (jittedCount > 0 && jittedCount % progressInterval == 0) + { + // When the progress is in bytes of method contexts rather than in method contexts, adding + // 'iter' is wildly inaccurate. But then (without a TOC or index list) there's no idea of how + // many method contexts the file has, or of the "average size" of one. + double percentComplete = 100.0 * (progressBeforeCurrentMC + iter) / totalWork; + int perSecond = (int)(progressInterval / st1.Elapsed.TotalSeconds); + if (o.applyDiff) + Logger.LogVerbose(CFormat.Sprintf(" %2.1f%% - Loaded %d Jitted %d Diffs %d FailedCompile %d at %d per second", percentComplete, + loadedCount, jittedCount, diffsCount, failToReplayCount, perSecond)); + else + Logger.LogVerbose(CFormat.Sprintf(" %2.1f%% - Loaded %d Jitted %d FailedCompile %d at %d per second", percentComplete, + loadedCount, jittedCount, failToReplayCount, perSecond)); + st1.Restart(); + } + + if (iter + 1 < o.repeatCount) + mc.Reset(); + } + } + + doneRepeatCount: + if (o.applyDiff) + Logger.LogInfo(CFormat.Sprintf(AsmDiffsSummaryFormatString, loadedCount, jittedCount, failToReplayCount, excludedCount, missingCount, diffsCount)); + else + Logger.LogInfo(CFormat.Sprintf(SummaryFormatString, loadedCount, jittedCount, failToReplayCount, excludedCount, missingCount)); + + Logger.LogVerbose(CFormat.Sprintf("Total time: %fms", st2.Elapsed.TotalMilliseconds)); + + if (o.mclFilename != null) + failingToReplayMCL.CloseMCL(); + + if (errorCount > 0 || errorCount2 > 0) + return (int)SpmiResult.Error; + if (o.applyDiff && diffsCount > 0) + return (int)SpmiResult.Diffs; + if (missingCount > 0) + return (int)SpmiResult.Misses; + return (int)SpmiResult.Success; + } + + // The times of the two JITs that are closest to each other. + // TODO-Bug?: this may not get the lowest cycle times. + private static (ulong, ulong) ClosestTimes(ulong[] times1, ulong[] times2) + { + static ulong Square(ulong a, ulong b) => unchecked((a - b) * (a - b)); + + ulong dif1 = Square(times1[0], times2[0]); + ulong dif2 = Square(times1[0], times2[1]); + ulong dif3 = Square(times1[1], times2[0]); + ulong dif4 = Square(times1[1], times2[1]); + + if (dif1 < dif2) + { + if (dif3 < dif4) + return dif1 < dif3 ? (times1[0], times2[0]) : (times1[1], times2[0]); + return dif1 < dif4 ? (times1[0], times2[0]) : (times1[1], times2[1]); + } + if (dif3 < dif4) + return dif2 < dif3 ? (times1[0], times2[1]) : (times1[1], times2[0]); + return dif2 < dif4 ? (times1[0], times2[1]) : (times1[1], times2[1]); + } + + private static bool WriteRepro(string reproName, int mcIndex, MethodContext mc) + { + string fileName = $"{reproName}-{mcIndex}.mc"; + try + { + using var stream = new FileStream(fileName, FileMode.Create, FileAccess.Write); + mc.saveToFile(stream); + } + catch (Exception e) when (e is IOException or UnauthorizedAccessException) + { + Logger.LogError($"Failed to open output '{fileName}'. GetLastError()={ErrorHandling.LastError(e)}"); + return false; + } + Logger.LogInfo($"Wrote out repro to '{fileName}'"); + return true; + } + + private static NearDifferResult InvokeNearDiffer(NearDiffer nearDiffer, MethodContext mc, CompileResult crl, int mcIndex) + { + try + { + if (nearDiffer.compare(mc, crl, mc.cr)) + return NearDifferResult.SuccessWithoutDiff; + + Logger.LogIssue($" main method {mcIndex} of size {mc.methodSize} differs"); + return NearDifferResult.SuccessWithDiff; + } + catch (Exception e) + { + Logger.LogError($"main method {mcIndex} of size {mc.methodSize} failed to load and compile correctly."); + Logger.LogError($"Exception thrown: {(e is SpmiException ? e.Message : e.ToString())}"); + return NearDifferResult.Failure; + } + } + + private static string ResultToString(ReplayResult result) => result switch + { + ReplayResult.Success => "Success", + ReplayResult.Error => "Error", + ReplayResult.Miss => "Miss", + _ => "Unknown", + }; + + private static void PrintDiffsCsvHeader(FileWriter fw) + { + fw.Print("Context,Context size,Method full name,Tier name,Base result,Diff result,MinOpts,Has diff,Base instructions,Diff instructions"); + foreach (JitMetrics.Metric metric in JitMetrics.All) + fw.Print($",Base {metric.Name},Diff {metric.Name}"); + fw.Print("\n"); + } + + private static void PrintDiffsCsvRow(FileWriter fw, int context, uint contextSize, in ReplayResults baseRes, in ReplayResults diffRes, bool hasDiff) + { + fw.Printf("%d,%u,", context, contextSize); + fw.PrintQuotedCsvField(diffRes.CompileResults.MethodFullName ?? ""); + fw.Printf(",%s,%s,%s,%s,%s,%lld,%lld", diffRes.CompileResults.TieringName ?? "", ResultToString(baseRes.Result), ResultToString(diffRes.Result), + diffRes.IsMinOpts ? "True" : "False", hasDiff ? "True" : "False", baseRes.NumExecutedInstructions, diffRes.NumExecutedInstructions); + for (int i = 0; i < JitMetrics.All.Length; i++) + fw.Print($",{baseRes.CompileResults.Metrics.Format(i)},{diffRes.CompileResults.Metrics.Format(i)}"); + fw.Print("\n"); + } + + private static void PrintReplayCsvHeader(FileWriter fw) + { + fw.Print("Context,Context size,Method full name,Tier name,Result,MinOpts,Instructions"); + foreach (JitMetrics.Metric metric in JitMetrics.All) + fw.Print($",{metric.Name}"); + fw.Print("\n"); + } + + private static void PrintReplayCsvRow(FileWriter fw, int context, uint contextSize, in ReplayResults res) + { + fw.Printf("%d,%u,", context, contextSize); + fw.PrintQuotedCsvField(res.CompileResults.MethodFullName ?? ""); + fw.Printf(",%s,%s,%s,%lld", res.CompileResults.TieringName ?? "", ResultToString(res.Result), res.IsMinOpts ? "True" : "False", res.NumExecutedInstructions); + for (int i = 0; i < JitMetrics.All.Length; i++) + fw.Print($",{res.CompileResults.Metrics.Format(i)}"); + fw.Print("\n"); + } +} diff --git a/src/coreclr/tools/superpmi/managed/superpmi/SpmiJitInterface.cs b/src/coreclr/tools/superpmi/managed/superpmi/SpmiJitInterface.cs new file mode 100644 index 00000000000000..929791c7b1e876 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/superpmi/SpmiJitInterface.cs @@ -0,0 +1,77 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.InteropServices; +using Internal.JitInterface; + +namespace SuperPmi.Replay; + +// The native side of the replay host (src/coreclr/tools/superpmi/jitinterface). +internal static unsafe partial class SpmiJitInterface +{ + private const string Library = "superpmi-jitinterface"; + + // Matches ExceptionKind in jitinterface.cpp. + public enum ExceptionKind + { + EEException, + SuperPmiException, + HostFailure, + } + + [LibraryImport(Library)] + public static partial IntPtr AllocException(ExceptionKind kind); + + [LibraryImport(Library)] + public static partial void FreeException(IntPtr pException); + + [LibraryImport(Library)] + public static partial CorJitResult JitCompileMethod(IntPtr* ppException, uint* pExceptionCode, IntPtr pJit, IntPtr thisHandle, IntPtr callbacks, + CORINFO_METHOD_INFO* methodInfo, uint flags, byte** entryAddress, uint* nativeSizeOfCode); + + [LibraryImport(Library)] + public static partial void JitGetVersionIdentifier(IntPtr pJit, Guid* versionIdentifier); + + [LibraryImport(Library)] + public static partial void JitSetOs(IntPtr pJit, CORINFO_OS os); + + [LibraryImport(Library)] + public static partial IntPtr GetJitHost(IntPtr configProvider); + + [LibraryImport(Library)] + public static partial void Instrumentor_GetInsCount(ulong* result); + + [LibraryImport(Library)] + public static partial ulong GetThreadCycleTime(); + + // The level is 0 for errors, 1 for warnings, and 2 for everything else. + [LibraryImport(Library)] + public static partial IntPtr GetCoreDisToolsPrinters(delegate* unmanaged callback); +} + +// Measures the CPU time of the current thread, less the overhead of measuring it. +internal sealed class CycleTimer +{ + private readonly ulong _overhead = QueryOverhead(); + private ulong _start; + private ulong _stop; + + public void Start() => _start = SpmiJitInterface.GetThreadCycleTime(); + + public void Stop() => _stop = SpmiJitInterface.GetThreadCycleTime(); + + public ulong GetCycles() => _stop - _start - _overhead; + + private static ulong QueryOverhead() + { + const int N = 1000; + ulong total = 0; + for (int i = 0; i < N; i++) + { + ulong start = SpmiJitInterface.GetThreadCycleTime(); + total += SpmiJitInterface.GetThreadCycleTime() - start; + } + return total / N; + } +} diff --git a/src/coreclr/tools/superpmi/managed/superpmi/StreamingReplay.cs b/src/coreclr/tools/superpmi/managed/superpmi/StreamingReplay.cs new file mode 100644 index 00000000000000..12c19a7ced5d91 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/superpmi/StreamingReplay.cs @@ -0,0 +1,188 @@ +// 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.Diagnostics; +using System.IO; + +namespace SuperPmi.Replay; + +// Streaming mode: compiles the method contexts asked for by the lines of a file (or stdin), each a method context +// number optionally followed by "!key=value" force JIT options. Lines starting with '#' are ignored, and +// "quit", a 0 number, or the end of the file stop it. +internal static class StreamingReplay +{ + private const int CacheSize = 100; + + private struct CacheEntry + { + public MethodContext mc; + public int age; + } + + private static readonly CacheEntry[] s_cache = new CacheEntry[CacheSize]; + private static int s_count; + private static int s_age; + + private static MethodContext getMethodContext(int index, MethodContextReader reader) + { + int i = 0; + for (; i < s_count; i++) + { + if (s_cache[i].mc.index == index) + break; + } + + if (i == s_count) + { + Logger.LogDebug($"[streaming] loading MC {index} from file"); + if (i == CacheSize) + { + // The cache is full: evict the oldest entry. + int oldestAge = s_age; + int oldestEntry = -1; + for (int j = 0; j < CacheSize; j++) + { + if (s_cache[j].age < oldestAge) + { + oldestEntry = j; + oldestAge = s_cache[j].age; + } + } + + Logger.LogDebug($"[streaming] evicting MC {s_cache[oldestEntry].mc.index} from cache"); + s_cache[oldestEntry].mc = null; + i = oldestEntry; + } + else + { + s_count++; + } + + reader.Reset([index]); + MethodContextBuffer mcb = reader.GetNextMethodContext(); + if (mcb.Error() || !MethodContext.Initialize(index, mcb.buff, (uint)mcb.size, readCompileResults: false, out MethodContext mc)) + return null; + + s_cache[i].mc = mc; + } + else + { + Logger.LogDebug($"[streaming] found MC {index} in cache"); + } + + // Move it to the front. + (s_cache[0], s_cache[i]) = (s_cache[i], s_cache[0]); + s_cache[0].age = s_age++; + return s_cache[0].mc; + } + + public static int Run(Options o) + { + TextReader streamFile; + try + { + streamFile = string.Equals(o.streamFile, "stdin", StringComparison.OrdinalIgnoreCase) ? Console.In : new StreamReader(o.streamFile); + } + catch (Exception e) when (e is IOException or UnauthorizedAccessException) + { + Logger.LogError($"Failed to open file '{o.streamFile}'. GetLastError()={ErrorHandling.LastError(e)}"); + return 1; + } + + // Just one worker for now: all method selection is done with the stream file. + using var reader = new MethodContextReader(o.nameOfInputMethodContextFile); + if (!reader.isValid()) + return (int)SpmiResult.GeneralFailure; + + JitInstance jit = null; + + while (streamFile.ReadLine() is string line) + { + Logger.LogDebug($"[streaming] Request: '{line}'"); + + if (line.StartsWith('#')) + continue; + + if (line.StartsWith("quit", StringComparison.Ordinal)) + { + Logger.LogDebug("[streaming] Quitting"); + break; + } + + string[] tokens = line.Split('!', StringSplitOptions.RemoveEmptyEntries); + int index = tokens.Length > 0 ? CommandLine.Atoi(tokens[0]) : 0; + if (index == 0) + { + Logger.LogDebug("[streaming] Stopping"); + break; + } + + Logger.LogDebug($"[streaming] Method {index}"); + + LightWeightMap forceJitOptions = null; + bool skip = false; + foreach (string option in tokens.AsSpan(1)) + { + forceJitOptions ??= o.forceJitOptions?.Clone() ?? new LightWeightMap(); + if (!CommandLine.ParseJitOption(option, out string key, out string value)) + { + Logger.LogInfo($"[streaming] unable to parse option '{option}'"); + skip = true; + break; + } + CommandLine.AddJitOption(forceJitOptions, key, value); + } + + if (skip) + continue; + + Logger.LogDebug("[streaming] Launching..."); + MethodContext mc = getMethodContext(index, reader); + if (mc == null) + return (int)SpmiResult.GeneralFailure; + + if (mc.index != index) + { + Logger.LogDebug($"MC cache lookup failure, wanted index {index}, got index {mc.index}\n"); + return (int)SpmiResult.GeneralFailure; + } + + if (jit == null) + { + Logger.LogDebug($"[streaming] loading jit {o.nameOfJit}"); + jit = JitInstance.InitJit(o.nameOfJit, o.breakOnAssert, new Stopwatch(), mc, forceJitOptions, o.jitOptions); + if (jit == null) + return (int)SpmiResult.JitFailedToInit; // InitJit already printed a failure message. + } + else + { + jit.updateForceOptions(forceJitOptions); + jit.resetConfig(mc); + } + + Logger.LogDebug("[streaming] invoking jit"); + Logger.Flush(); + + ReplayResults res = jit.CompileMethod(mc, reader.GetMethodContextIndex(), collectThroughput: false); + if (res.Result == ReplayResult.Success) + { + if (Logger.IsEnabled(LogLevel.Debug)) + mc.cr.dumpToConsole(); // Dump the compile results when debug logging. + } + else if (res.Result == ReplayResult.Error) + { + Logger.LogDebug("[streaming] jit compilation failed"); + Logger.LogError($"Method {reader.GetMethodContextIndex()} of size {mc.methodSize} failed to load and compile correctly ({o.nameOfJit})."); + } + + // The protocol with clients is for them to read stdout, so let them know this is done. + Logger.Out.Write($"[streaming] Done. Status={(int)res.Result}\n"); + Logger.Flush(); + + mc.Reset(); + } + + return (int)SpmiResult.Success; + } +} diff --git a/src/coreclr/tools/superpmi/managed/superpmi/superpmi.csproj b/src/coreclr/tools/superpmi/managed/superpmi/superpmi.csproj new file mode 100644 index 00000000000000..017fed9cb18769 --- /dev/null +++ b/src/coreclr/tools/superpmi/managed/superpmi/superpmi.csproj @@ -0,0 +1,35 @@ + + + superpmi + Exe + true + + + true + true + true + $(PortableOS)-$(TargetArchitecture) + $(RuntimeBinDir) + + true + + + + + + + + + + + + + + + + + + diff --git a/src/coreclr/tools/superpmi/mcs/CMakeLists.txt b/src/coreclr/tools/superpmi/mcs/CMakeLists.txt deleted file mode 100644 index b11fed72e32e6d..00000000000000 --- a/src/coreclr/tools/superpmi/mcs/CMakeLists.txt +++ /dev/null @@ -1,74 +0,0 @@ -project(mcs) - -add_definitions(-DFEATURE_NO_HOST) -add_definitions(-DSELF_NO_HOST) - -if(CLR_CMAKE_HOST_WIN32) - #use static crt - set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded) -endif(CLR_CMAKE_HOST_WIN32) - -include_directories(.) -include_directories(../superpmi-shared) - -set(MCS_SOURCES - commandline.cpp - mcs.cpp - removedup.cpp - verbasmdump.cpp - verbconcat.cpp - verbdump.cpp - verbdumpmap.cpp - verbdumptoc.cpp - verbfracture.cpp - verbjitflags.cpp - verbildump.cpp - verbinteg.cpp - verbmerge.cpp - verbprintjiteeversion.cpp - verbremovedup.cpp - verbstat.cpp - verbstrip.cpp - verbtoc.cpp - ../superpmi-shared/asmdumper.cpp - ../superpmi-shared/callutils.cpp - ../superpmi-shared/compileresult.cpp - ../superpmi-shared/errorhandling.cpp - ../superpmi-shared/hash.cpp - ../superpmi-shared/logging.cpp - ../superpmi-shared/mclist.cpp - ../superpmi-shared/methodcontext.cpp - ../superpmi-shared/methodcontextiterator.cpp - ../superpmi-shared/methodcontextreader.cpp - ../superpmi-shared/simpletimer.cpp - ../superpmi-shared/spmiutil.cpp - ../superpmi-shared/tocfile.cpp - ../superpmi-shared/typeutils.cpp - ../superpmi-shared/spmidumphelper.cpp -) - -add_executable_clr(mcs - ${MCS_SOURCES} -) -target_precompile_headers(mcs PRIVATE "$<$:standardpch.h>") - -if(CLR_CMAKE_HOST_UNIX) - target_link_libraries(mcs - PRIVATE - utilcodestaticnohost - mscorrc - coreclrpal - coreclrminipal - ) -else() - target_link_libraries(mcs - PRIVATE - advapi32.lib - coreclrminipal - ${STATIC_MT_CRT_LIB} - ${STATIC_MT_CPP_LIB} - ) - -endif(CLR_CMAKE_HOST_UNIX) - -install_clr(TARGETS mcs DESTINATIONS . COMPONENT spmi) diff --git a/src/coreclr/tools/superpmi/mcs/commandline.cpp b/src/coreclr/tools/superpmi/mcs/commandline.cpp deleted file mode 100644 index 86ce6023375d1f..00000000000000 --- a/src/coreclr/tools/superpmi/mcs/commandline.cpp +++ /dev/null @@ -1,642 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// CommandLine.cpp - tiny very specific command line parser -//---------------------------------------------------------- - -#include "standardpch.h" -#include "commandline.h" -#include "logging.h" -#include "mclist.h" - -void CommandLine::DumpHelp(const char* program) -{ - printf("MCS is a utility for examining and manipulating SuperPMI MC files.\n"); - printf("\n"); - printf("Usage: %s [options] {verb} {verb options}", program); - printf("\n"); - printf("Options:\n"); - printf("\n"); - printf(" -v[erbosity] messagetypes\n"); - printf(" Controls which types of messages MCS logs. Specify a string of\n"); - printf(" characters representing message categories to enable, where:\n"); - printf(" e - errors (internal fatal errors that are non-recoverable)\n"); - printf(" w - warnings (internal conditions that are unusual, but not serious)\n"); - printf(" m - missing (failures due to missing JIT-EE interface details)\n"); - printf(" n - information (notifications/summaries, e.g. 'Loaded 42, Saved 23')\n"); - printf(" v - verbose (status messages, e.g. 'Jit startup took 151.12ms')\n"); - printf(" d - debug (lots of detailed output)\n"); - printf(" a - all (enable all message types; overrides other enable message types)\n"); - printf(" q - quiet (disable all output; overrides all others)\n"); - printf(" e.g. '-v ew' only writes error and warning messages to the console.\n"); - printf(" 'q' takes precedence over any other message type specified.\n"); - printf(" Default set of messages enabled is 'ewmnv'.\n"); - printf("\n"); - printf(" -writeLogFile logfile\n"); - printf(" Write log messages to the specified file.\n"); - printf("\n"); - printf("Verbs:\n"); - printf("\n"); - printf(" -ASMDump {optional range} inputfile outputfile\n"); - printf(" Dump out the asm file for each input methodContext.\n"); - printf(" inputfile is read and output is written to outputfile.\n"); - printf(" e.g. -ASMDump a.mc a.asm\n"); - printf("\n"); - printf(" -concat file1 file2\n"); - printf(" Concatenate two files without regard to internal formatting.\n"); - printf(" file2 is appended to file1.\n"); - printf(" e.g. -concat a.mch b.mch\n"); - printf("\n"); - printf(" -copy range file1 file2\n"); - printf(" Copy methodContext numbers in range from file1 to file2.\n"); - printf(" file1 is read and file2 is written\n"); - printf(" e.g. -copy a.mch b.mch\n"); - printf("\n"); - printf(" -dump {optional range} inputfile [-simple]\n"); - printf(" Dump details for each methodContext.\n"); - printf(" With -simple, don't display the function name/arguments in the header (useful for debugging mcs itself).\n"); - printf(" e.g. -dump a.mc\n"); - printf("\n"); - printf(" -dumpMap inputfile\n"); - printf(" Dump a map from MC index to function name to the console, in CSV format\n"); - printf(" e.g. -dumpMap a.mc\n"); - printf("\n"); - printf(" -dumpToc inputfile\n"); - printf(" Dump a TOC file\n"); - printf(" e.g. -dumpToc a.mct\n"); - printf("\n"); - printf(" -fracture range inputfile outputfile\n"); - printf(" Break the input file into chunks sized by range.\n"); - printf(" If '-thin' is also passed, CompileResults are stripped from the input file when written.\n"); - printf(" e.g. '-fracture 3 a.mch b-' leads to b-0.mch, b-1.mch, etc., with 3 mc's in each file.\n"); - printf("\n"); - printf(" -ildump {optional range} inputfile\n"); - printf(" Dump raw IL for each methodContext\n"); - printf(" e.g. -ildump a.mc\n"); - printf("\n"); - printf(" -integ inputfile\n"); - printf(" Check the integrity of each methodContext\n"); - printf(" e.g. -integ a.mc\n"); - printf("\n"); - printf(" -merge outputfile pattern [-dedup [-thin]]\n"); - printf(" Merge all the input files matching the pattern.\n"); - printf(" With -dedup, skip duplicates when copying (like using -removeDup). With -thin, also strip CompileResults.\n"); - printf(" e.g. -merge a.mch *.mc\n"); - printf(" e.g. -merge a.mch c:\\foo\\bar\\*.mc\n"); - printf(" e.g. -merge a.mch relpath\\*.mc\n"); - printf(" e.g. -merge a.mch .\n"); - printf(" e.g. -merge a.mch onedir\n"); - printf(" e.g. -merge a.mch *.mc -dedup -thin\n"); - printf("\n"); - printf(" -merge outputfile pattern -recursive [-dedup [-thin]]\n"); - printf(" Merge all the input files matching the pattern, in the specified and all child directories.\n"); - printf(" With -dedup, skip duplicates when copying (like using -removeDup). With -thin, also strip CompileResults.\n"); - printf(" e.g. -merge a.mch *.mc -recursive\n"); - printf(" e.g. -merge a.mch *.mc -recursive -dedup -thin\n"); - printf("\n"); - printf(" -printJITEEVersion\n"); - printf(" Print the JITEEVersion GUID with which this was built, in the form: a5eec3a4-4176-43a7-8c2b-a05b551d4f49\n"); - printf("\n"); - printf(" -removeDup inputfile outputfile\n"); - printf(" Copy methodContexts from inputfile to outputfile, skipping duplicates.\n"); - printf(" e.g. -removeDup a.mc b.mc\n"); - printf("\n"); - printf(" -removeDup -legacy inputfile outputfile\n"); - printf(" Copy methodContexts from inputfile to outputfile, skipping duplicates.\n"); - printf(" Comparisons are performed using the legacy method and may take much longer\n"); - printf(" e.g. -removeDup -legacy a.mc b.mc\n"); - printf("\n"); - printf(" -removeDup -thin inputfile outputfile\n"); - printf(" Copy methodContexts from inputfile to outputfile, skipping duplicates.\n"); - printf(" CompileResults are stripped from the input file when written.\n"); - printf(" e.g. -removeDup -thin a.mc b.mc\n"); - printf(" e.g. -removeDup -legacy -thin a.mc b.mc\n"); - printf("\n"); - printf(" -stat {optional range} inputfile outputfile\n"); - printf(" Report various statistics per method context.\n"); - printf(" inputfile is read and statistics are written into outputfile\n"); - printf(" e.g. -stat a.mc a.csv\n"); - printf("\n"); - printf(" -strip range inputfile outputfile\n"); - printf(" Copy method contexts from one file to another, skipping ranged items.\n"); - printf(" inputfile is read and records not in range are written to outputfile.\n"); - printf(" If range is empty (e.g., from an empty .mcl file due to a clean replay),\n"); - printf(" the file is simply copied.\n"); - printf(" e.g. -strip 2 a.mc b.mc\n"); - printf("\n"); - printf(" -toc inputfile\n"); - printf(" Create a Table of Contents file for inputfile to allow better random access\n"); - printf(" to the mch file.\n"); - printf(" e.g. '-toc a.mch' creates a.mch.mct\n"); - printf("\n"); - printf(" -jitflags inputfile\n"); - printf(" Summarize interesting jitflags for the method contexts\n"); - printf(" e.g. '-jitflags a.mch'\n"); - printf("\n"); - printf("Range descriptions are either a single number, or a text file with .mcl extension\n"); - printf("containing a sorted list of line delimited numbers.\n"); - printf(" e.g. -strip 2 a.mc b.mc\n"); - printf(" e.g. -strip list.mcl a.mc b.mc\n"); - printf("\n"); - printf("Note: Inputs are case insensitive.\n"); -} - -// Assumption: All inputs are initialized to default or real value. we'll just set the stuff in what we see on the -// command line. Assumption: Single byte names are passed in.. mb stuff doesnt cause an obvious problem... but it might -// have issues... Assumption: Values larger than 2^31 aren't expressible from the commandline.... (atoi) Unless you pass -// in negatives.. :-| -bool CommandLine::Parse(int argc, char* argv[], /* OUT */ Options* o) -{ - size_t argLen = 0; - size_t tempLen = 0; - - bool foundVerb = false; - bool foundFile1 = false; - bool foundFile2 = false; - - if (argc == 1) // Print help when no args are passed - { - DumpHelp(argv[0]); - return false; - } - - for (int i = 1; i < argc; i++) - { - bool isASwitch = (argv[i][0] == '-'); -#ifndef TARGET_UNIX - if (argv[i][0] == '/') // Also accept "/" on Windows - { - isASwitch = true; - } -#endif // !TARGET_UNIX - - // Process a switch - if (isASwitch) - { - argLen = strlen(argv[i]); - - if (argLen > 1) - argLen--; // adjust for leading switch - else - { - DumpHelp(argv[0]); - return false; - } - - if ((_strnicmp(&argv[i][1], "help", argLen) == 0) || (_strnicmp(&argv[i][1], "?", argLen) == 0)) - { - DumpHelp(argv[0]); - return false; - } - else if ((_strnicmp(&argv[i][1], "ASMDump", argLen) == 0)) - { - tempLen = strlen(argv[i]); - foundVerb = true; - o->actionASMDump = true; - if (i + 1 < argc) // Peek to see if we have an mcl file or an integer next - goto processMCL; - } - else if ((_strnicmp(&argv[i][1], "concat", argLen) == 0)) - { - tempLen = strlen(argv[i]); - foundVerb = true; - o->actionConcat = true; - } - else if ((_strnicmp(&argv[i][1], "copy", argLen) == 0)) - { - tempLen = strlen(argv[i]); - foundVerb = true; - o->actionCopy = true; - if (i + 1 < argc) // Peek to see if we have an mcl file or an integer next - goto processMCL; - } - else if ((_strnicmp(&argv[i][1], "dump", argLen) == 0)) - { - tempLen = strlen(argv[i]); - foundVerb = true; - o->actionDump = true; - if (i + 1 < argc) // Peek to see if we have an mcl file or an integer next - goto processMCL; - } - else if ((_strnicmp(&argv[i][1], "fracture", argLen) == 0)) - { - tempLen = strlen(argv[i]); - foundVerb = true; - o->actionFracture = true; - if (i + 1 < argc) // Peek to see if we have an mcl file or an integer next - goto processMCL; - } - else if ((_strnicmp(&argv[i][1], "dumpmap", argLen) == 0)) - { - tempLen = strlen(argv[i]); - foundVerb = true; - o->actionDumpMap = true; - } - else if ((_strnicmp(&argv[i][1], "dumptoc", argLen) == 0)) - { - tempLen = strlen(argv[i]); - foundVerb = true; - o->actionDumpToc = true; - } - else if ((_strnicmp(&argv[i][1], "jitflags", argLen) == 0)) - { - tempLen = strlen(argv[i]); - foundVerb = true; - o->actionJitFlags = true; - } - else if ((_strnicmp(&argv[i][1], "ildump", argLen) == 0)) - { - tempLen = strlen(argv[i]); - foundVerb = true; - o->actionILDump = true; - if (i + 1 < argc) // Peek to see if we have an mcl file or an integer next - goto processMCL; - } - else if ((_strnicmp(&argv[i][1], "merge", argLen) == 0)) - { - tempLen = strlen(argv[i]); - foundVerb = true; - o->actionMerge = true; - } - else if ((_strnicmp(&argv[i][1], "printjiteeversion", argLen) == 0)) - { - tempLen = strlen(argv[i]); - foundVerb = true; - o->actionPrintJITEEVersion = true; - } - else if ((_strnicmp(&argv[i][1], "recursive", argLen) == 0)) - { - tempLen = strlen(argv[i]); - o->recursive = true; - } - else if ((_strnicmp(&argv[i][1], "dedup", argLen) == 0)) - { - tempLen = strlen(argv[i]); - o->dedup = true; - } - else if ((_strnicmp(&argv[i][1], "toc", argLen) == 0)) - { - tempLen = strlen(argv[i]); - foundVerb = true; - o->actionTOC = true; - } - else if ((_strnicmp(&argv[i][1], "input", argLen) == 0)) - { - if (++i >= argc) - { - DumpHelp(argv[0]); - return false; - } - - processInput: - - tempLen = strlen(argv[i]); - if (tempLen == 0) - { - printf("ERROR: CommandLine::Parse() Arg '%s' is invalid, name of file missing.\n", argv[i]); - DumpHelp(argv[0]); - return false; - } - if (foundFile1 == false) - { - o->nameOfFile1 = new char[tempLen + 1]; - strcpy_s(o->nameOfFile1, tempLen + 1, argv[i]); - foundFile1 = true; - } - else if (foundFile2 == false) - { - o->nameOfFile2 = new char[tempLen + 1]; - strcpy_s(o->nameOfFile2, tempLen + 1, argv[i]); - foundFile2 = true; - } - else - { - printf("ERROR: CommandLine::Parse() Arg '%s' is invalid, too many files given.\n", argv[i]); - DumpHelp(argv[0]); - return false; - } - } - else if ((_strnicmp(&argv[i][1], "integ", argLen) == 0)) - { - tempLen = strlen(argv[i]); - foundVerb = true; - o->actionInteg = true; - } - else if ((_strnicmp(&argv[i][1], "mcl", argLen) == 0)) - { - if (i + 1 >= argc) - { - DumpHelp(argv[0]); - return false; - } - - processMCL: - i++; - processMCL2: - - bool isValidList = MCList::processArgAsMCL(argv[i], &o->indexCount, &o->indexes); - if (!isValidList) - i--; - } - else if ((_strnicmp(&argv[i][1], "removeDup", argLen) == 0)) - { - tempLen = strlen(argv[i]); - foundVerb = true; - o->actionRemoveDup = true; - } - else if ((_strnicmp(&argv[i][1], "stat", argLen) == 0)) - { - tempLen = strlen(argv[i]); - foundVerb = true; - o->actionStat = true; - if (i + 1 < argc) // Peek to see if we have an mcl file or an integer next - goto processMCL; - } - else if ((_strnicmp(&argv[i][1], "strip", argLen) == 0)) - { - tempLen = strlen(argv[i]); - foundVerb = true; - o->actionStrip = true; - if (i + 1 < argc) // Peek to see if we have an mcl file or an integer next - goto processMCL; - } - else if ((_strnicmp(&argv[i][1], "thin", argLen) == 0)) - { - o->stripCR = true; - } - else if ((_strnicmp(&argv[i][1], "legacy", argLen) == 0)) - { - o->legacyCompare = true; - } - else if ((_strnicmp(&argv[i][1], "verbosity", argLen) == 0)) - { - if (++i >= argc) - { - DumpHelp(argv[0]); - return false; - } - - Logger::SetLogLevel(Logger::ParseLogLevelString(argv[i])); - } - else if ((_strnicmp(&argv[i][1], "writeLogFile", argLen) == 0)) - { - if (++i >= argc) - { - DumpHelp(argv[0]); - return false; - } - - Logger::OpenLogFile(argv[i]); - } - else if ((_strnicmp(&argv[i][1], "simple", argLen) == 0)) - { - o->simple = true; - } - else - { - LogError("CommandLine::Parse() - Unknown verb '%s'", argv[i]); - DumpHelp(argv[0]); - return false; - } - } - // Process an input filename - else - { - char* lastdot = strrchr(argv[i], '.'); - if (lastdot != nullptr) - { - if (_stricmp(lastdot, ".mcl") == 0) - goto processMCL2; - } - goto processInput; - } - } - - if (o->simple) - { - if (!o->actionDump) - { - LogError("CommandLine::Parse() '-simple' requires -dump."); - DumpHelp(argv[0]); - return false; - } - } - - if (o->recursive) - { - if (!o->actionMerge) - { - LogError("CommandLine::Parse() '-recursive' requires -merge."); - DumpHelp(argv[0]); - return false; - } - } - - if (o->dedup) - { - if (!o->actionMerge) - { - LogError("CommandLine::Parse() '-dedup' requires -merge."); - DumpHelp(argv[0]); - return false; - } - } - - if (o->stripCR) - { - if (o->actionMerge) - { - if (!o->dedup) - { - LogError("CommandLine::Parse() '-thin' in '-merge' requires -dedup."); - DumpHelp(argv[0]); - return false; - } - } - else if (o->actionRemoveDup || o->actionStrip || o->actionFracture || o->actionCopy) - { - } - else - { - LogError("CommandLine::Parse() '-thin' requires -merge, -removeDup, -strip, -fracture, or -copy."); - DumpHelp(argv[0]); - return false; - } - } - - if (o->actionASMDump) - { - if ((!foundFile1) || (!foundFile2)) - { - LogError("CommandLine::Parse() -ASMDump needs one input file and one output file."); - DumpHelp(argv[0]); - return false; - } - return true; - } - if (o->actionConcat) - { - if ((!foundFile1) || (!foundFile2)) - { - LogError("CommandLine::Parse() '-concat' needs two input files (second will be used as output)."); - DumpHelp(argv[0]); - return false; - } - return true; - } - if (o->actionMerge) - { - if ((!foundFile1) || (!foundFile2)) - { - LogError("CommandLine::Parse() '-merge' needs an output file (the first) and a file pattern (the second)."); - DumpHelp(argv[0]); - return false; - } - return true; - } - if (o->actionCopy) - { - if ((!foundFile1) || (!foundFile2)) - { - LogError("CommandLine::Parse() '-copy' needs one input and one output."); - DumpHelp(argv[0]); - return false; - } - if (o->indexCount == 0) - { - LogError("CommandLine::Parse() -copy requires a range."); - DumpHelp(argv[0]); - return false; - } - return true; - } - if (o->actionDump) - { - if (!foundFile1) - { - LogError("CommandLine::Parse() '-dump' needs one input file, but didn't see one."); - DumpHelp(argv[0]); - return false; - } - return true; - } - if (o->actionFracture) - { - if ((!foundFile1) || (!foundFile2)) - { - LogError("CommandLine::Parse() '-fracture' needs one input and one output."); - DumpHelp(argv[0]); - return false; - } - if (o->indexCount == 0) - { - LogError("CommandLine::Parse() -fracture requires a range."); - DumpHelp(argv[0]); - return false; - } - if (o->indexCount > 1) - { - LogWarning("CommandLine::Parse() -fracture found multiple ranges, we'll use the first one."); - } - return true; - } - if (o->actionDumpMap) - { - if (!foundFile1) - { - LogError("CommandLine::Parse() '-dumpMap' needs one input."); - DumpHelp(argv[0]); - return false; - } - return true; - } - if (o->actionDumpToc) - { - if (!foundFile1) - { - LogError("CommandLine::Parse() '-dumpToc' needs one input."); - DumpHelp(argv[0]); - return false; - } - return true; - } - if (o->actionJitFlags) - { - if (!foundFile1) - { - LogError("CommandLine::Parse() '-jitFlags' needs one input."); - DumpHelp(argv[0]); - return false; - } - return true; - } - if (o->actionILDump) - { - if (!foundFile1) - { - LogError("CommandLine::Parse() '-ildump' needs one input."); - DumpHelp(argv[0]); - return false; - } - return true; - } - if (o->actionTOC) - { - if (!foundFile1) - { - LogError("CommandLine::Parse() '-toc' needs one input."); - DumpHelp(argv[0]); - return false; - } - return true; - } - if (o->actionInteg) - { - if (!foundFile1) - { - LogError("CommandLine::Parse() '-integ' needs one input file, but didn't see one."); - DumpHelp(argv[0]); - return false; - } - return true; - } - if (o->actionRemoveDup) - { - if ((!foundFile1) || (!foundFile2)) - { - LogError("CommandLine::Parse() -removeDup needs one input file and one output file."); - DumpHelp(argv[0]); - return false; - } - return true; - } - if (o->actionStat) - { - if ((!foundFile1) || (!foundFile2)) - { - LogError("CommandLine::Parse() '-stat' needs one input file and one output file."); - DumpHelp(argv[0]); - return false; - } - return true; - } - if (o->actionStrip) - { - if ((!foundFile1) || (!foundFile2)) - { - LogError("CommandLine::Parse() -strip needs one input file and one output file."); - DumpHelp(argv[0]); - return false; - } - return true; - } - if (o->actionPrintJITEEVersion) - { - // No arguments to check - return true; - } - - DumpHelp(argv[0]); - return false; -} diff --git a/src/coreclr/tools/superpmi/mcs/commandline.h b/src/coreclr/tools/superpmi/mcs/commandline.h deleted file mode 100644 index ea78f456f91a96..00000000000000 --- a/src/coreclr/tools/superpmi/mcs/commandline.h +++ /dev/null @@ -1,79 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// CommandLine.h - tiny very specific command line parser -//---------------------------------------------------------- -#ifndef _CommandLine -#define _CommandLine - -class CommandLine -{ -public: - class Options - { - public: - Options() - : actionASMDump(false) - , actionConcat(false) - , actionCopy(false) - , actionDump(false) - , actionDumpMap(false) - , actionDumpToc(false) - , actionFracture(false) - , actionJitFlags(false) - , actionILDump(false) - , actionInteg(false) - , actionMerge(false) - , actionPrintJITEEVersion(false) - , actionRemoveDup(false) - , actionStat(false) - , actionStrip(false) - , actionTOC(false) - , legacyCompare(false) - , recursive(false) - , dedup(false) - , stripCR(false) - , simple(false) - , nameOfFile1(nullptr) - , nameOfFile2(nullptr) - , nameOfFile3(nullptr) - , indexCount(-1) - , indexes(nullptr) - { - } - - bool actionASMDump; - bool actionConcat; - bool actionCopy; - bool actionDump; - bool actionDumpMap; - bool actionDumpToc; - bool actionFracture; - bool actionJitFlags; - bool actionILDump; - bool actionInteg; - bool actionMerge; - bool actionPrintJITEEVersion; - bool actionRemoveDup; - bool actionStat; - bool actionStrip; - bool actionTOC; - bool legacyCompare; - bool recursive; - bool dedup; - bool stripCR; - bool simple; - char* nameOfFile1; - char* nameOfFile2; - char* nameOfFile3; - int indexCount; - int* indexes; - }; - - static bool Parse(int argc, char* argv[], /* OUT */ Options* o); - -private: - static void DumpHelp(const char* program); -}; -#endif diff --git a/src/coreclr/tools/superpmi/mcs/mcs.cpp b/src/coreclr/tools/superpmi/mcs/mcs.cpp deleted file mode 100644 index 2923a4f9186f31..00000000000000 --- a/src/coreclr/tools/superpmi/mcs/mcs.cpp +++ /dev/null @@ -1,111 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "standardpch.h" -#include "mcs.h" -#include "commandline.h" -#include "verbasmdump.h" -#include "verbinteg.h" -#include "verbdump.h" -#include "verbfracture.h" -#include "verbdumpmap.h" -#include "verbdumptoc.h" -#include "verbjitflags.h" -#include "verbildump.h" -#include "verbtoc.h" -#include "verbremovedup.h" -#include "verbstat.h" -#include "verbconcat.h" -#include "verbmerge.h" -#include "verbstrip.h" -#include "verbprintjiteeversion.h" -#include "logging.h" - -int __cdecl main(int argc, char* argv[]) -{ -#ifdef TARGET_UNIX - if (0 != PAL_Initialize(argc, argv)) - { - fprintf(stderr, "Error: Fail to PAL_Initialize\n"); - exit(1); - } -#endif // TARGET_UNIX - - Logger::Initialize(); - - CommandLine::Options o; - if (!CommandLine::Parse(argc, argv, &o)) - { - return -1; - } - - // execute the chosen command. - int exitCode = 0; - if (o.actionASMDump) - { - exitCode = verbASMDump::DoWork(o.nameOfFile1, o.nameOfFile2, o.indexCount, o.indexes); - } - if (o.actionConcat) - { - exitCode = verbConcat::DoWork(o.nameOfFile1, o.nameOfFile2); - } - if (o.actionMerge) - { - exitCode = verbMerge::DoWork(o.nameOfFile1, o.nameOfFile2, o.recursive, o.dedup, o.stripCR); - } - if (o.actionCopy) - { - exitCode = verbStrip::DoWork(o.nameOfFile1, o.nameOfFile2, o.indexCount, o.indexes, false, o.stripCR); - } - if (o.actionDump) - { - exitCode = verbDump::DoWork(o.nameOfFile1, o.indexCount, o.indexes, o.simple); - } - if (o.actionFracture) - { - exitCode = verbFracture::DoWork(o.nameOfFile1, o.nameOfFile2, o.indexCount, o.indexes, o.stripCR); - } - if (o.actionDumpMap) - { - exitCode = verbDumpMap::DoWork(o.nameOfFile1); - } - if (o.actionDumpToc) - { - exitCode = verbDumpToc::DoWork(o.nameOfFile1); - } - if (o.actionILDump) - { - exitCode = verbILDump::DoWork(o.nameOfFile1, o.indexCount, o.indexes); - } - if (o.actionInteg) - { - exitCode = verbInteg::DoWork(o.nameOfFile1); - } - if (o.actionRemoveDup) - { - exitCode = verbRemoveDup::DoWork(o.nameOfFile1, o.nameOfFile2, o.stripCR, o.legacyCompare); - } - if (o.actionStat) - { - exitCode = verbStat::DoWork(o.nameOfFile1, o.nameOfFile2, o.indexCount, o.indexes); - } - if (o.actionStrip) - { - exitCode = verbStrip::DoWork(o.nameOfFile1, o.nameOfFile2, o.indexCount, o.indexes, true, o.stripCR); - } - if (o.actionTOC) - { - exitCode = verbTOC::DoWork(o.nameOfFile1); - } - if (o.actionPrintJITEEVersion) - { - exitCode = verbPrintJITEEVersion::DoWork(); - } - if (o.actionJitFlags) - { - exitCode = verbJitFlags::DoWork(o.nameOfFile1); - } - - Logger::Shutdown(); - return exitCode; -} diff --git a/src/coreclr/tools/superpmi/mcs/mcs.h b/src/coreclr/tools/superpmi/mcs/mcs.h deleted file mode 100644 index b3083e0957f05c..00000000000000 --- a/src/coreclr/tools/superpmi/mcs/mcs.h +++ /dev/null @@ -1,7 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#ifndef _MCS -#define _MCS - -#endif diff --git a/src/coreclr/tools/superpmi/mcs/removedup.cpp b/src/coreclr/tools/superpmi/mcs/removedup.cpp deleted file mode 100644 index b2ba784e633f15..00000000000000 --- a/src/coreclr/tools/superpmi/mcs/removedup.cpp +++ /dev/null @@ -1,169 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "standardpch.h" -#include "verbremovedup.h" -#include "simpletimer.h" -#include "lightweightmap.h" -#include "methodcontext.h" -#include "methodcontextiterator.h" -#include "removedup.h" - -RemoveDup::~RemoveDup() -{ - if (m_cleanup) - { - if (m_inFile != nullptr) - { - for (int i = 0; i < (int)m_inFile->GetCount(); i++) - { - DenseLightWeightMap* md5HashMap = m_inFile->GetItem(i); - if (md5HashMap != nullptr) - { - // go through and delete items - for (int j = 0; j < (int)md5HashMap->GetCount(); j++) - { - char* p = md5HashMap->GetItem(j); - delete[] p; - } - delete md5HashMap; - } - } - delete m_inFile; - m_inFile = nullptr; - } - if (m_inFileLegacy != nullptr) - { - for (int i = 0; i < (int)m_inFileLegacy->GetCount(); i++) - { - DenseLightWeightMap* md5HashMap = m_inFileLegacy->GetItem(i); - if (md5HashMap != nullptr) - { - // go through and delete items - for (int j = 0; j < (int)md5HashMap->GetCount(); j++) - { - MethodContext* p = md5HashMap->GetItem(j); - delete p; - } - delete md5HashMap; - } - } - delete m_inFileLegacy; - m_inFileLegacy = nullptr; - } - } -} - -bool RemoveDup::unique(MethodContext* mc) -{ - if (m_inFile == nullptr) - m_inFile = new LightWeightMap*>(); - - CORINFO_METHOD_INFO newInfo; - unsigned newFlags = 0; - CORINFO_OS newOs = CORINFO_WINNT; - mc->repCompileMethod(&newInfo, &newFlags, &newOs); - - // Assume that there are lots of duplicates, so don't allocate a new buffer for the MD5 hash data - // until we know we're going to add it to the map. - char md5Buff[MM3_HASH_BUFFER_SIZE]; - mc->dumpMethodHashToBuffer(md5Buff, MM3_HASH_BUFFER_SIZE, /* ignoreMethodName */ true, &newInfo, newFlags); - - if (m_inFile->GetIndex(newInfo.ILCodeSize) == -1) - m_inFile->Add(newInfo.ILCodeSize, new DenseLightWeightMap()); - - DenseLightWeightMap* ourRank = m_inFile->Get(newInfo.ILCodeSize); - - for (unsigned i = 0; i < ourRank->GetCount(); i++) - { - char* md5Buff2 = ourRank->Get(i); - if (strncmp(md5Buff, md5Buff2, MM3_HASH_BUFFER_SIZE) == 0) - { - return false; - } - } - - char* newmd5Buff = new char[MM3_HASH_BUFFER_SIZE]; - memcpy(newmd5Buff, md5Buff, MM3_HASH_BUFFER_SIZE); - ourRank->Append(newmd5Buff); - return true; -} - -bool RemoveDup::uniqueLegacy(MethodContext* mc) -{ - if (m_inFileLegacy == nullptr) - m_inFileLegacy = new LightWeightMap*>(); - - CORINFO_METHOD_INFO newInfo; - unsigned newFlags = 0; - CORINFO_OS newOs = CORINFO_WINNT; - mc->repCompileMethod(&newInfo, &newFlags, &newOs); - - if (m_inFileLegacy->GetIndex(newInfo.ILCodeSize) == -1) - m_inFileLegacy->Add(newInfo.ILCodeSize, new DenseLightWeightMap()); - - DenseLightWeightMap* ourRank = m_inFileLegacy->Get(newInfo.ILCodeSize); - - for (unsigned i = 0; i < ourRank->GetCount(); i++) - { - MethodContext* scratch = ourRank->Get(i); - if (mc->Equal(scratch)) - { - return false; - } - } - - // We store the MethodContext in our map. - ourRank->Append(mc); - return true; -} - -bool RemoveDup::CopyAndRemoveDups(const char* nameOfInput, HANDLE hFileOut) -{ - MethodContextIterator mci(/* progressReport */ true); - if (!mci.Initialize(nameOfInput)) - return false; - - int savedCount = 0; - - while (mci.MoveNext()) - { - MethodContext* mc = mci.CurrentTakeOwnership(); - if (m_stripCR) - { - delete mc->cr; - mc->cr = new CompileResult(); - } - if (m_legacyCompare) - { - if (uniqueLegacy(mc)) - { - mc->saveToFile(hFileOut); - savedCount++; - - // In this case, for the legacy comparer, it has placed the 'mc' in the 'm_inFileLegacy' table, so we - // can't delete it. - } - else - { - delete mc; // we no longer need this - } - } - else - { - if (unique(mc)) - { - mc->saveToFile(hFileOut); - savedCount++; - } - delete mc; // we no longer need this - } - } - - LogInfo("Loaded %d, Saved %d", mci.MethodContextNumber(), savedCount); - - if (!mci.Destroy()) - return false; - - return true; -} diff --git a/src/coreclr/tools/superpmi/mcs/removedup.h b/src/coreclr/tools/superpmi/mcs/removedup.h deleted file mode 100644 index ee14e636ef7fff..00000000000000 --- a/src/coreclr/tools/superpmi/mcs/removedup.h +++ /dev/null @@ -1,61 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// RemoveDup.h - Functions to remove dups from a method context hive (MCH) -//---------------------------------------------------------- -#ifndef _RemoveDup -#define _RemoveDup - -#include "methodcontext.h" -#include "lightweightmap.h" - -class RemoveDup -{ -public: - - RemoveDup() - : m_stripCR(false) - , m_legacyCompare(false) - , m_cleanup(false) - , m_inFile(nullptr) - , m_inFileLegacy(nullptr) - {} - - bool Initialize(bool stripCR = false, bool legacyCompare = false, bool cleanup = true) - { - m_stripCR = stripCR; - m_legacyCompare = legacyCompare; - m_cleanup = cleanup; - m_inFile = nullptr; - m_inFileLegacy = nullptr; - - return true; - } - - ~RemoveDup(); - - bool CopyAndRemoveDups(const char* nameOfInput, HANDLE hFileOut); - -private: - - bool m_stripCR; // 'true' if we remove CompileResults when removing duplicates. - bool m_legacyCompare; // 'true' to use the legacy comparer. - - // If false, we don't spend time cleaning up the `m_inFile` and `m_inFileLegacy` - // data structures. Only set it to `false` if you're ok with memory leaks, e.g., - // if the process will exit soon afterwards. - bool m_cleanup; - - // We use a hash to limit the number of comparisons we need to do. - // The first level key to our hash map is ILCodeSize and the second - // level map key is just an index and the value is an existing MC Hash. - - LightWeightMap*>* m_inFile; - LightWeightMap*>* m_inFileLegacy; - - bool unique(MethodContext* mc); - bool uniqueLegacy(MethodContext* mc); -}; - -#endif diff --git a/src/coreclr/tools/superpmi/mcs/verbasmdump.cpp b/src/coreclr/tools/superpmi/mcs/verbasmdump.cpp deleted file mode 100644 index 6d70077b8c7a4e..00000000000000 --- a/src/coreclr/tools/superpmi/mcs/verbasmdump.cpp +++ /dev/null @@ -1,67 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "standardpch.h" -#include "verbasmdump.h" -#include "simpletimer.h" -#include "methodcontext.h" -#include "methodcontextiterator.h" -#include "asmdumper.h" -#include "errorhandling.h" - -#define BUFFER_SIZE 0xFFFFFF - -int verbASMDump::DoWork(const char* nameOfInput, const char* nameOfOutput, int indexCount, const int* indexes) -{ - LogVerbose("Loading from '%s' and writing ASM output into '%s-MC#.asm'", nameOfInput, nameOfOutput); - - MethodContextIterator mci(indexCount, indexes, true); - if (!mci.Initialize(nameOfInput)) - return -1; - - int savedCount = 0; - - while (mci.MoveNext()) - { - MethodContext* mc = mci.Current(); - - char buff[500]; - sprintf_s(buff, 500, "%s-%d.asm", nameOfOutput, mci.MethodContextNumber()); - - HANDLE hFileOut = CreateFileA(buff, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); - if (hFileOut == INVALID_HANDLE_VALUE) - { - LogError("Failed to open output '%s'. GetLastError()=%u", buff, GetLastError()); - return -1; - } - - if (mc->cr->IsEmpty()) - { - const size_t bufflen = 4096; - DWORD bytesWritten; - char buff[bufflen]; - ZeroMemory(buff, bufflen * sizeof(char)); - int buff_offset = sprintf_s(buff, bufflen, ";;Method context has no compile result"); - WriteFile(hFileOut, buff, buff_offset * sizeof(char), &bytesWritten, nullptr); - } - else - { - ASMDumper::DumpToFile(hFileOut, mc, mc->cr); - } - - if (!CloseHandle(hFileOut)) - { - LogError("CloseHandle failed. GetLastError()=%u", GetLastError()); - return -1; - } - savedCount++; - } - - LogInfo("Asm'd %d", savedCount); - - if (!mci.Destroy()) - return -1; - - return 0; -} diff --git a/src/coreclr/tools/superpmi/mcs/verbasmdump.h b/src/coreclr/tools/superpmi/mcs/verbasmdump.h deleted file mode 100644 index c37a859aa012a3..00000000000000 --- a/src/coreclr/tools/superpmi/mcs/verbasmdump.h +++ /dev/null @@ -1,15 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// verbASMDump.h - verb that -//---------------------------------------------------------- -#ifndef _verbASMDump -#define _verbASMDump - -class verbASMDump -{ -public: - static int DoWork(const char* nameOfInput1, const char* nameOfOutput, int indexCount, const int* indexes); -}; -#endif diff --git a/src/coreclr/tools/superpmi/mcs/verbconcat.cpp b/src/coreclr/tools/superpmi/mcs/verbconcat.cpp deleted file mode 100644 index 9d6f7b39c0e291..00000000000000 --- a/src/coreclr/tools/superpmi/mcs/verbconcat.cpp +++ /dev/null @@ -1,102 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "standardpch.h" -#include "verbconcat.h" -#include "simpletimer.h" -#include "logging.h" - -#define BUFFER_SIZE 0xFFFFFF - -int verbConcat::DoWork(const char* nameOfFile1, const char* nameOfFile2) -{ - SimpleTimer st1; - - LogVerbose("Concatenating '%s'+'%s' into %s", nameOfFile1, nameOfFile2, nameOfFile1); - - LARGE_INTEGER DataTemp1; - LARGE_INTEGER DataTemp2; - - HANDLE hFileIn1 = CreateFileA(nameOfFile1, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); - if (hFileIn1 == INVALID_HANDLE_VALUE) - { - LogError("Failed to open input 1 '%s'. GetLastError()=%u", nameOfFile1, GetLastError()); - return -1; - } - if (GetFileSizeEx(hFileIn1, &DataTemp1) == 0) - { - LogError("GetFileSizeEx failed. GetLastError()=%u", GetLastError()); - return -1; - } - - LONG highDWORD = 0; - DWORD dwPtr = SetFilePointer(hFileIn1, 0, &highDWORD, FILE_END); - if (dwPtr == INVALID_SET_FILE_POINTER) - { - LogError("Failed to SetFilePointer on input 1 '%s'. GetLastError()=%u", nameOfFile1, GetLastError()); - return -1; - } - - HANDLE hFileIn2 = CreateFileA(nameOfFile2, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); - if (hFileIn2 == INVALID_HANDLE_VALUE) - { - LogError("Failed to open input 2 '%s'. GetLastError()=%u", nameOfFile2, GetLastError()); - return -1; - } - if (GetFileSizeEx(hFileIn2, &DataTemp2) == 0) - { - LogError("2nd GetFileSizeEx failed. GetLastError()=%u", GetLastError()); - return -1; - } - - unsigned char* buffer = new unsigned char[BUFFER_SIZE]; - - st1.Start(); - for (LONGLONG offset = 0; offset < DataTemp2.QuadPart; offset += BUFFER_SIZE) - { - DWORD bytesRead = -1; - BOOL res = ReadFile(hFileIn2, buffer, BUFFER_SIZE, &bytesRead, nullptr); - if (res == 0) - { - LogError("Failed to read '%s' from offset %lld. GetLastError()=%u", nameOfFile2, offset, GetLastError()); - delete[] buffer; - return -1; - } - DWORD bytesWritten = -1; - BOOL res2 = WriteFile(hFileIn1, buffer, bytesRead, &bytesWritten, nullptr); - if (res2 == 0) - { - LogError("Failed to write '%s' at offset %lld. GetLastError()=%u", nameOfFile1, offset, GetLastError()); - delete[] buffer; - return -1; - } - if (bytesRead != bytesWritten) - { - LogError("Failed to read/write matching bytes %u!=%u", bytesRead, bytesWritten); - delete[] buffer; - return -1; - } - } - st1.Stop(); - - delete[] buffer; - - if (CloseHandle(hFileIn1) == 0) - { - LogError("CloseHandle failed. GetLastError()=%u", GetLastError()); - return -1; - } - if (CloseHandle(hFileIn2) == 0) - { - LogError("2nd CloseHandle failed. GetLastError()=%u", GetLastError()); - return -1; - } - - LogInfo("Read/Wrote %lld MB @ %4.2f MB/s.\n", DataTemp2.QuadPart / (1000 * 1000), - (((double)DataTemp2.QuadPart) / (1000 * 1000)) / - st1.GetSeconds()); // yes yes.. http://en.wikipedia.org/wiki/Megabyte_per_second#Megabyte_per_second - - return 0; -} diff --git a/src/coreclr/tools/superpmi/mcs/verbconcat.h b/src/coreclr/tools/superpmi/mcs/verbconcat.h deleted file mode 100644 index be0d6438f5d0ca..00000000000000 --- a/src/coreclr/tools/superpmi/mcs/verbconcat.h +++ /dev/null @@ -1,15 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// verbConcat.h - verb that concatenates two files -//---------------------------------------------------------- -#ifndef _verbConcat -#define _verbConcat - -class verbConcat -{ -public: - static int DoWork(const char* nameOfFile1, const char* nameOfFile2); -}; -#endif diff --git a/src/coreclr/tools/superpmi/mcs/verbdump.cpp b/src/coreclr/tools/superpmi/mcs/verbdump.cpp deleted file mode 100644 index ab8f3833343e86..00000000000000 --- a/src/coreclr/tools/superpmi/mcs/verbdump.cpp +++ /dev/null @@ -1,34 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "standardpch.h" -#include "verbdump.h" -#include "logging.h" -#include "methodcontext.h" -#include "methodcontextiterator.h" -#include "errorhandling.h" - -int verbDump::DoWork(const char* nameOfInput, int indexCount, const int* indexes, bool simple) -{ - LogVerbose("Dumping '%s' to console", nameOfInput); - - MethodContextIterator mci(indexCount, indexes); - if (!mci.Initialize(nameOfInput)) - return -1; - - int dumpedCount = 0; - - while (mci.MoveNext()) - { - MethodContext* mc = mci.Current(); - mc->dumpToConsole(mci.MethodContextNumber(), simple); - dumpedCount++; - } - - LogVerbose("Dumped %d methodContexts", dumpedCount); - - if (!mci.Destroy()) - return -1; - - return 0; -} diff --git a/src/coreclr/tools/superpmi/mcs/verbdump.h b/src/coreclr/tools/superpmi/mcs/verbdump.h deleted file mode 100644 index c51846a698d83b..00000000000000 --- a/src/coreclr/tools/superpmi/mcs/verbdump.h +++ /dev/null @@ -1,15 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// verbDump.h - verb that Dumps a MC file -//---------------------------------------------------------- -#ifndef _verbDump -#define _verbDump - -class verbDump -{ -public: - static int DoWork(const char* nameofInput, int indexCount, const int* indexes, bool simple); -}; -#endif diff --git a/src/coreclr/tools/superpmi/mcs/verbdumpmap.cpp b/src/coreclr/tools/superpmi/mcs/verbdumpmap.cpp deleted file mode 100644 index 9e4bd15f2f0ce4..00000000000000 --- a/src/coreclr/tools/superpmi/mcs/verbdumpmap.cpp +++ /dev/null @@ -1,160 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "standardpch.h" -#include "simpletimer.h" -#include "methodcontext.h" -#include "methodcontextiterator.h" -#include "verbdumpmap.h" -#include "verbildump.h" -#include "spmiutil.h" -#include "spmidumphelper.h" - -// Dump the CSV format header for all the columns we're going to dump. -void DumpMapHeader() -{ - printf("index,"); - // printf("process name,"); - printf("method name,"); - printf("full signature,"); - printf("jit flags,"); - printf("os\n"); -} - -void DumpMap(int index, MethodContext* mc) -{ - CORINFO_METHOD_INFO cmi; - unsigned int flags = 0; - CORINFO_OS os; - - mc->repCompileMethod(&cmi, &flags, &os); - - char methodName[256]; - mc->repPrintMethodName(cmi.ftn, methodName, sizeof(methodName)); - char className[256]; - mc->repPrintClassName(mc->repGetMethodClass(cmi.ftn), className, sizeof(className)); - - printf("%d,", index); - // printf("\"%s\",", mc->cr->repProcessName()); - printf("%s:%s,", className, methodName); - - // Also, dump the full method signature - printf("\""); - DumpAttributeToConsoleBare(mc->repGetMethodAttribs(cmi.ftn)); - DumpPrimToConsoleBare(mc, cmi.args.retType, CastHandle(cmi.args.retTypeClass)); - printf(" %s", methodName); - - // Show class and method generic params, if there are any - CORINFO_SIG_INFO sig; - mc->repGetMethodSig(cmi.ftn, &sig, nullptr); - - const unsigned classInst = sig.sigInst.classInstCount; - if (classInst > 0) - { - for (unsigned i = 0; i < classInst; i++) - { - CORINFO_CLASS_HANDLE ci = sig.sigInst.classInst[i]; - mc->repPrintClassName(ci, className, sizeof(className)); - - printf("%s%s%s%s", - i == 0 ? "[" : "", - i > 0 ? ", " : "", - className, - i == classInst - 1 ? "]" : ""); - } - } - - const unsigned methodInst = sig.sigInst.methInstCount; - if (methodInst > 0) - { - for (unsigned i = 0; i < methodInst; i++) - { - CORINFO_CLASS_HANDLE ci = sig.sigInst.methInst[i]; - mc->repPrintClassName(ci, className, sizeof(className)); - - printf("%s%s%s%s", - i == 0 ? "[" : "", - i > 0 ? ", " : "", - className, - i == methodInst - 1 ? "]" : ""); - } - } - - printf("("); - DumpSigToConsoleBare(mc, &cmi.args); - printf(")\""); - - // Dump the jit flags - CORJIT_FLAGS corJitFlags; - mc->repGetJitFlags(&corJitFlags, sizeof(corJitFlags)); - unsigned long long rawFlags = corJitFlags.GetFlagsRaw(); - - // Add in the "fake" pgo flags - bool hasEdgeProfile = false; - bool hasClassProfile = false; - bool hasMethodProfile = false; - bool hasLikelyClass = false; - bool hasLikelyMethod = false; - ICorJitInfo::PgoSource pgoSource = ICorJitInfo::PgoSource::Unknown; - if (mc->hasPgoData(hasEdgeProfile, hasClassProfile, hasMethodProfile, hasLikelyClass, hasLikelyMethod, pgoSource)) - { - rawFlags |= 1ULL << (EXTRA_JIT_FLAGS::HAS_PGO); - - if (hasEdgeProfile) - { - rawFlags |= 1ULL << (EXTRA_JIT_FLAGS::HAS_EDGE_PROFILE); - } - - if (hasClassProfile) - { - rawFlags |= 1ULL << (EXTRA_JIT_FLAGS::HAS_CLASS_PROFILE); - } - - if (hasMethodProfile) - { - rawFlags |= 1ULL << (EXTRA_JIT_FLAGS::HAS_METHOD_PROFILE); - } - - if (hasLikelyClass) - { - rawFlags |= 1ULL << (EXTRA_JIT_FLAGS::HAS_LIKELY_CLASS); - } - - if (hasLikelyMethod) - { - rawFlags |= 1ULL << (EXTRA_JIT_FLAGS::HAS_LIKELY_METHOD); - } - - if (pgoSource == ICorJitInfo::PgoSource::Static) - { - rawFlags |= 1ULL << (EXTRA_JIT_FLAGS::HAS_STATIC_PROFILE); - } - - if (pgoSource == ICorJitInfo::PgoSource::Dynamic) - { - rawFlags |= 1ULL << (EXTRA_JIT_FLAGS::HAS_DYNAMIC_PROFILE); - } - } - - printf(", %s, %d\n", SpmiDumpHelper::DumpJitFlags(rawFlags).c_str(), (int)os); -} - -int verbDumpMap::DoWork(const char* nameOfInput) -{ - MethodContextIterator mci; - if (!mci.Initialize(nameOfInput)) - return -1; - - DumpMapHeader(); - - while (mci.MoveNext()) - { - MethodContext* mc = mci.Current(); - DumpMap(mci.MethodContextNumber(), mc); - } - - if (!mci.Destroy()) - return -1; - - return 0; -} diff --git a/src/coreclr/tools/superpmi/mcs/verbdumpmap.h b/src/coreclr/tools/superpmi/mcs/verbdumpmap.h deleted file mode 100644 index 86d41502852c31..00000000000000 --- a/src/coreclr/tools/superpmi/mcs/verbdumpmap.h +++ /dev/null @@ -1,15 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// verbDumpMap.h - verb that dumps a map of index to function name for an MC file -//---------------------------------------------------------- -#ifndef _verbDumpMap -#define _verbDumpMap - -class verbDumpMap -{ -public: - static int DoWork(const char* nameofInput); -}; -#endif diff --git a/src/coreclr/tools/superpmi/mcs/verbdumptoc.cpp b/src/coreclr/tools/superpmi/mcs/verbdumptoc.cpp deleted file mode 100644 index 2219441440e668..00000000000000 --- a/src/coreclr/tools/superpmi/mcs/verbdumptoc.cpp +++ /dev/null @@ -1,30 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "standardpch.h" -#include "verbdumptoc.h" -#include "methodcontext.h" -#include "tocfile.h" -#include "runtimedetails.h" - -int verbDumpToc::DoWork(const char* nameOfInput) -{ - TOCFile tf; - - tf.LoadToc(nameOfInput, false); - - for (size_t i = 0; i < tf.GetTocCount(); i++) - { - const TOCElement* te = tf.GetElementPtr(i); - printf("%4u: %016" PRIX64 " ", te->Number, te->Offset); - - for (size_t j = 0; j < sizeof(te->Hash); j++) - { - printf("%02x ", te->Hash[j]); - } - - printf("\n"); - } - - return 0; -} diff --git a/src/coreclr/tools/superpmi/mcs/verbdumptoc.h b/src/coreclr/tools/superpmi/mcs/verbdumptoc.h deleted file mode 100644 index 2a9f29ab090935..00000000000000 --- a/src/coreclr/tools/superpmi/mcs/verbdumptoc.h +++ /dev/null @@ -1,15 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// verbDumpToc.h - verb that dumps a MCH Table of Context file -//---------------------------------------------------------- -#ifndef _verbDumpToc -#define _verbDumpToc - -class verbDumpToc -{ -public: - static int DoWork(const char* nameOfInput1); -}; -#endif diff --git a/src/coreclr/tools/superpmi/mcs/verbfracture.cpp b/src/coreclr/tools/superpmi/mcs/verbfracture.cpp deleted file mode 100644 index 549e4ed9322149..00000000000000 --- a/src/coreclr/tools/superpmi/mcs/verbfracture.cpp +++ /dev/null @@ -1,75 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "standardpch.h" -#include "verbfracture.h" -#include "simpletimer.h" -#include "methodcontext.h" -#include "methodcontextiterator.h" -#include "errorhandling.h" -#include "logging.h" - -int verbFracture::DoWork( - const char* nameOfInput, const char* nameOfOutput, int indexCount, const int* indexes, bool stripCR) -{ - int rangeSize = indexes[0]; - - LogVerbose("Reading from '%s' copying %d MethodContexts files into each output file of '%s'", nameOfInput, - rangeSize, nameOfOutput); - - MethodContextIterator mci(true); - if (!mci.Initialize(nameOfInput)) - return -1; - - int fileCount = 0; - char fileName[512]; - - HANDLE hFileOut = INVALID_HANDLE_VALUE; - while (mci.MoveNext()) - { - MethodContext* mc = mci.Current(); - - if ((hFileOut == INVALID_HANDLE_VALUE) || (((mci.MethodContextNumber() - 1) % rangeSize) == 0)) - { - if (hFileOut != INVALID_HANDLE_VALUE) - { - if (!CloseHandle(hFileOut)) - { - LogError("1st CloseHandle failed. GetLastError()=%u", GetLastError()); - return -1; - } - hFileOut = INVALID_HANDLE_VALUE; - } - sprintf_s(fileName, 512, "%s-%0*d.mch", nameOfOutput, 5, fileCount++); - hFileOut = CreateFileA(fileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); - if (hFileOut == INVALID_HANDLE_VALUE) - { - LogError("Failed to open output file '%s'. GetLastError()=%u", fileName, GetLastError()); - return -1; - } - } - if (stripCR) - { - delete mc->cr; - mc->cr = new CompileResult(); - } - mc->saveToFile(hFileOut); - } - - if (hFileOut != INVALID_HANDLE_VALUE) - { - if (!CloseHandle(hFileOut)) - { - LogError("2nd CloseHandle failed. GetLastError()=%u", GetLastError()); - return -1; - } - } - - LogInfo("Output fileCount %d", fileCount); - - if (!mci.Destroy()) - return -1; - - return 0; -} diff --git a/src/coreclr/tools/superpmi/mcs/verbfracture.h b/src/coreclr/tools/superpmi/mcs/verbfracture.h deleted file mode 100644 index 534ace0e3f5197..00000000000000 --- a/src/coreclr/tools/superpmi/mcs/verbfracture.h +++ /dev/null @@ -1,16 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// verbFracture.h - verb that copies N items into each child file. -//---------------------------------------------------------- -#ifndef _verbFracture -#define _verbFracture - -class verbFracture -{ -public: - static int DoWork( - const char* nameOfInput1, const char* nameOfOutput, int indexCount, const int* indexes, bool stripCR); -}; -#endif diff --git a/src/coreclr/tools/superpmi/mcs/verbildump.cpp b/src/coreclr/tools/superpmi/mcs/verbildump.cpp deleted file mode 100644 index 2e17f08817ef40..00000000000000 --- a/src/coreclr/tools/superpmi/mcs/verbildump.cpp +++ /dev/null @@ -1,995 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "standardpch.h" -#include "simpletimer.h" -#include "methodcontext.h" -#include "methodcontextiterator.h" -#include "verbildump.h" -#include "spmiutil.h" - -void DumpPrimToConsoleBare(MethodContext* mc, CorInfoType prim, DWORDLONG classHandle) -{ - switch (prim) - { - case CORINFO_TYPE_VOID: - printf("void"); - return; - case CORINFO_TYPE_BOOL: - printf("bool"); - return; - case CORINFO_TYPE_CHAR: - printf("char"); - return; - case CORINFO_TYPE_BYTE: - printf("int8"); - return; - case CORINFO_TYPE_UBYTE: - printf("unsigned int8"); - return; - case CORINFO_TYPE_SHORT: - printf("int16"); - return; - case CORINFO_TYPE_USHORT: - printf("unsigned int16"); - return; - case CORINFO_TYPE_INT: - printf("int32"); - return; - case CORINFO_TYPE_UINT: - printf("unsigned int32"); - return; - case CORINFO_TYPE_LONG: - printf("int64"); - return; - case CORINFO_TYPE_ULONG: - printf("unsigned int64"); - return; - case CORINFO_TYPE_NATIVEINT: - printf("native int"); - return; - case CORINFO_TYPE_NATIVEUINT: - printf("native unsigned int"); - return; - case CORINFO_TYPE_FLOAT: - printf("float32"); - return; - case CORINFO_TYPE_DOUBLE: - printf("float64"); - return; - case CORINFO_TYPE_PTR: - printf("ptr"); - return; - case CORINFO_TYPE_BYREF: - printf("byref"); - return; - case CORINFO_TYPE_VALUECLASS: - case CORINFO_TYPE_CLASS: - { - CORINFO_CLASS_HANDLE cls = (CORINFO_CLASS_HANDLE)classHandle; - unsigned arrayRank = mc->repGetArrayRank(cls); - if (arrayRank > 0) - { - CORINFO_CLASS_HANDLE childCls; - CorInfoType childType = mc->repGetChildType(cls, &childCls); - DumpPrimToConsoleBare(mc, childType, (DWORDLONG)childCls); - - printf("["); - for (unsigned i = 1; i < arrayRank; i++) - { - printf(","); - } - printf("]"); - } - else - { - char className[256]; - mc->repPrintClassName((CORINFO_CLASS_HANDLE)classHandle, className, sizeof(className)); - - printf( - "%s %s", - prim == CORINFO_TYPE_VALUECLASS ? "valueclass" : "class", - className); - } - - return; - } - default: - LogWarning("unknown type in PrimToString(0x%x)", prim); - DEBUG_BREAK; - return; - } -} -void DumpSigToConsoleBare(MethodContext* mc, CORINFO_SIG_INFO* pSig) -{ - CORINFO_ARG_LIST_HANDLE currentItem = pSig->args; - DWORD exceptionCode; - - for (int i = 0; i < (int)pSig->numArgs; i++) - { - DWORDLONG dl; - CorInfoTypeWithMod type = mc->repGetArgType(pSig, currentItem, (CORINFO_CLASS_HANDLE*)&dl, &exceptionCode); - CorInfoType cit = strip(type); - if (cit == CORINFO_TYPE_CLASS) - dl = CastHandle(mc->repGetArgClass(pSig, currentItem, &exceptionCode)); - if ((type & CORINFO_TYPE_MOD_PINNED) == CORINFO_TYPE_MOD_PINNED) - printf("pinned "); - DumpPrimToConsoleBare(mc, cit, dl); - currentItem = mc->repGetArgNext(currentItem); - if (i + 1 < (int)pSig->numArgs) - printf(", "); - } -} - -void DumpILToConsoleBare(unsigned char* ilCode, int len) -{ - int i, j, k; - for (i = 0; i < len; i++) - { - printf("IL_%04x: ", i); - switch (ilCode[i]) - { - case 0x00: - printf("nop"); - continue; - case 0x01: - printf("break"); - continue; - case 0x02: - printf("ldarg.0"); - continue; - case 0x03: - printf("ldarg.1"); - continue; - case 0x04: - printf("ldarg.2"); - continue; - case 0x05: - printf("ldarg.3"); - continue; - case 0x06: - printf("ldloc.0"); - continue; - case 0x07: - printf("ldloc.1"); - continue; - case 0x08: - printf("ldloc.2"); - continue; - case 0x09: - printf("ldloc.3"); - continue; - case 0x0a: - printf("stloc.0"); - continue; - case 0x0b: - printf("stloc.1"); - continue; - case 0x0c: - printf("stloc.2"); - continue; - case 0x0d: - printf("stloc.3"); - continue; - case 0x0e: // ldarg.s X - printf("ldarg.s 0x%02x", ilCode[i + 1]); - i += 1; - continue; - case 0x0f: // ldarga.s X - printf("ldarga.s 0x%02x", ilCode[i + 1]); - i += 1; - continue; - case 0x10: // starg.s X - printf("starg.s 0x%02x", ilCode[i + 1]); - i += 1; - continue; - case 0x11: // ldloc.s X - printf("ldloc.s 0x%02x", ilCode[i + 1]); - i += 1; - continue; - case 0x12: // ldloca.s X - printf("ldloca.s 0x%02x", ilCode[i + 1]); - i += 1; - continue; - case 0x13: // stloc.s X - printf("stloc.s 0x%02x", ilCode[i + 1]); - i += 1; - continue; - case 0x14: - printf("ldnull"); - continue; - case 0x15: - printf("ldc.i4.m1"); - continue; - case 0x16: - printf("ldc.i4.0"); - continue; - case 0x17: - printf("ldc.i4.1"); - continue; - case 0x18: - printf("ldc.i4.2"); - continue; - case 0x19: - printf("ldc.i4.3"); - continue; - case 0x1a: - printf("ldc.i4.4"); - continue; - case 0x1b: - printf("ldc.i4.5"); - continue; - case 0x1c: - printf("ldc.i4.6"); - continue; - case 0x1d: - printf("ldc.i4.7"); - continue; - case 0x1e: - printf("ldc.i4.8"); - continue; - case 0x1f: // ldc.i4.s X - printf("ldc.i4.s 0x%02x", ilCode[i + 1]); - i += 1; - continue; - case 0x20: // ldc.i4 XXXX - printf("ldc.i4 0x%02x%02x%02x%02x", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], ilCode[i + 1]); - i += 4; - continue; - case 0x21: // ldc.i8 XXXXXXXX - printf("ldc.i8 0x%02x%02x%02x%02x%02x%02x%02x%02x", ilCode[i + 8], ilCode[i + 7], ilCode[i + 6], - ilCode[i + 5], ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], ilCode[i + 1]); - i += 8; - continue; - case 0x22: // ldc.r4 XXXX - printf("ldc.r4 float32(0x%02x%02x%02x%02x)", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], - ilCode[i + 1]); - i += 4; - continue; - case 0x23: // ldc.r8 XXXXXXXX - printf("ldc.r8 float64(0x%02x%02x%02x%02x%02x%02x%02x%02x)", ilCode[i + 8], ilCode[i + 7], - ilCode[i + 6], ilCode[i + 5], ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], ilCode[i + 1]); - i += 8; - continue; - case 0x25: - printf("dup"); - continue; - case 0x26: - printf("pop"); - continue; - case 0x27: // JMP - printf("jmp <0x%02x%02x%02x%02x>", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], ilCode[i + 1]); - i += 4; - continue; - case 0x28: // call - printf("call <0x%02x%02x%02x%02x>", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], ilCode[i + 1]); - i += 4; - continue; - case 0x29: // calli - printf("calli <0x%02x%02x%02x%02x>", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], ilCode[i + 1]); - i += 4; - continue; - case 0x2a: - printf("ret"); - continue; - case 0x2b: // br.s X - printf("br.s IL_%04x", i + 2 + ilCode[i + 1]); - ; - i += 1; - continue; - case 0x2c: // brfalse.s X - printf("brfalse.s IL_%04x", i + 2 + ilCode[i + 1]); - ; - i += 1; - continue; - case 0x2d: // brtrue.s X - printf("brtrue.s IL_%04x", i + 2 + ilCode[i + 1]); - ; - i += 1; - continue; - case 0x2e: // beq.s X - printf("beq.s IL_%04x", i + 2 + ilCode[i + 1]); - ; - i += 1; - continue; - case 0x2f: // bgt.s X - printf("bgt.s IL_%04x", i + 2 + ilCode[i + 1]); - ; - i += 1; - continue; - case 0x30: // bgt.s X - printf("bgt.s IL_%04x", i + 2 + ilCode[i + 1]); - ; - i += 1; - continue; - case 0x31: // ble.s X - printf("ble.s IL_%04x", i + 2 + ilCode[i + 1]); - ; - i += 1; - continue; - case 0x32: // blt.s X - printf("blt.s IL_%04x", i + 2 + ilCode[i + 1]); - ; - i += 1; - continue; - case 0x33: // bne.un.s X - printf("bne.un.s IL_%04x", i + 2 + ilCode[i + 1]); - ; - i += 1; - continue; - case 0x34: // bge.un.s X - printf("bge.un.s IL_%04x", i + 2 + ilCode[i + 1]); - ; - i += 1; - continue; - case 0x35: // bgt.un.s X - printf("bgt.un.s IL_%04x", i + 2 + ilCode[i + 1]); - ; - i += 1; - continue; - case 0x36: // ble.un.s X - printf("ble.un.s IL_%04x", i + 2 + ilCode[i + 1]); - ; - i += 1; - continue; - case 0x37: // blt.un.s X - printf("blt.un.s IL_%04x", i + 2 + ilCode[i + 1]); - ; - i += 1; - continue; - case 0x38: // br XXXX - printf("br IL_%04x", - i + 5 + (ilCode[i + 4] << 24 | ilCode[i + 3] << 16 | ilCode[i + 2] << 8 | ilCode[i + 1])); - i += 4; - continue; - case 0x39: // brfalse XXXX - printf("brfalse IL_%04x", - i + 5 + (ilCode[i + 4] << 24 | ilCode[i + 3] << 16 | ilCode[i + 2] << 8 | ilCode[i + 1])); - i += 4; - continue; - case 0x3a: // brtrue XXXX - printf("brtrue IL_%04x", - i + 5 + (ilCode[i + 4] << 24 | ilCode[i + 3] << 16 | ilCode[i + 2] << 8 | ilCode[i + 1])); - i += 4; - continue; - case 0x3b: // beq XXXX - printf("beq IL_%04x", - i + 5 + (ilCode[i + 4] << 24 | ilCode[i + 3] << 16 | ilCode[i + 2] << 8 | ilCode[i + 1])); - i += 4; - continue; - case 0x3c: // bgt XXXX - printf("bgt IL_%04x", - i + 5 + (ilCode[i + 4] << 24 | ilCode[i + 3] << 16 | ilCode[i + 2] << 8 | ilCode[i + 1])); - i += 4; - continue; - case 0x3d: // bgt XXXX - printf("bgt IL_%04x", - i + 5 + (ilCode[i + 4] << 24 | ilCode[i + 3] << 16 | ilCode[i + 2] << 8 | ilCode[i + 1])); - i += 4; - continue; - case 0x3e: // ble XXXX - printf("ble IL_%04x", - i + 5 + (ilCode[i + 4] << 24 | ilCode[i + 3] << 16 | ilCode[i + 2] << 8 | ilCode[i + 1])); - i += 4; - continue; - case 0x3f: // blt XXXX - printf("blt IL_%04x", - i + 5 + (ilCode[i + 4] << 24 | ilCode[i + 3] << 16 | ilCode[i + 2] << 8 | ilCode[i + 1])); - i += 4; - continue; - case 0x40: // bne.un XXXX - printf("bne.un IL_%04x", - i + 5 + (ilCode[i + 4] << 24 | ilCode[i + 3] << 16 | ilCode[i + 2] << 8 | ilCode[i + 1])); - i += 4; - continue; - case 0x41: // bge.un XXXX - printf("bge.un IL_%04x", - i + 5 + (ilCode[i + 4] << 24 | ilCode[i + 3] << 16 | ilCode[i + 2] << 8 | ilCode[i + 1])); - i += 4; - continue; - case 0x42: // bgt.un XXXX - printf("bgt.un IL_%04x", - i + 5 + (ilCode[i + 4] << 24 | ilCode[i + 3] << 16 | ilCode[i + 2] << 8 | ilCode[i + 1])); - i += 4; - continue; - case 0x43: // ble.un XXXX - printf("ble.un IL_%04x", - i + 5 + (ilCode[i + 4] << 24 | ilCode[i + 3] << 16 | ilCode[i + 2] << 8 | ilCode[i + 1])); - i += 4; - continue; - case 0x44: // blt.un XXXX - printf("blt.un IL_%04x", - i + 5 + (ilCode[i + 4] << 24 | ilCode[i + 3] << 16 | ilCode[i + 2] << 8 | ilCode[i + 1])); - i += 4; - continue; - case 0x45: // switch NNNN NNNN*XXXX - printf("switch (0x%02x%02x%02x%02x)", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], ilCode[i + 1]); - k = (ilCode[i + 4] << 24) | (ilCode[i + 3] << 16) | (ilCode[i + 2] << 8) | (ilCode[i + 1] << 0); - i += 4; - for (j = 0; j < k; j++) - { - printf(" <0x%02x%02x%02x%02x>", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], ilCode[i + 1]); - i += 4; - } - continue; - case 0x46: - printf("ldind.i1"); - continue; - case 0x47: - printf("ldind.u1"); - continue; - case 0x48: - printf("ldind.i2"); - continue; - case 0x49: - printf("ldind.u2"); - continue; - case 0x4a: - printf("ldind.i4"); - continue; - case 0x4b: - printf("ldind.u4"); - continue; - case 0x4c: - printf("ldind.i8"); - continue; - case 0x4d: - printf("ldind.u8"); - continue; - case 0x4e: - printf("ldind.r4"); - continue; - case 0x4f: - printf("ldind.r8"); - continue; - case 0x50: - printf("ldind.ref"); - continue; - case 0x51: - printf("stind.ref"); - continue; - case 0x52: - printf("stind.i1"); - continue; - case 0x53: - printf("stind.i2"); - continue; - case 0x54: - printf("stind.i4"); - continue; - case 0x55: - printf("stind.i8"); - continue; - case 0x56: - printf("stind.r4"); - continue; - case 0x57: - printf("stind.r8"); - continue; - case 0x58: - printf("add"); - continue; - case 0x59: - printf("sub"); - continue; - case 0x5a: - printf("mul"); - continue; - case 0x5b: - printf("div"); - continue; - case 0x5c: - printf("div.un"); - continue; - case 0x5d: - printf("rem"); - continue; - case 0x5e: - printf("rem.un"); - continue; - case 0x5f: - printf("and"); - continue; - case 0x60: - printf("or"); - continue; - case 0x61: - printf("xor"); - continue; - case 0x62: - printf("shl"); - continue; - case 0x63: - printf("shr"); - continue; - case 0x64: - printf("shr.un"); - continue; - case 0x65: - printf("neg"); - continue; - case 0x66: - printf("not"); - continue; - case 0x67: - printf("conv.i1"); - continue; - case 0x68: - printf("conv.i2"); - continue; - case 0x69: - printf("conv.i4"); - continue; - case 0x6a: - printf("conv.i8"); - continue; - case 0x6b: - printf("conv.r4"); - continue; - case 0x6c: - printf("conv.r8"); - continue; - case 0x6d: - printf("conv.u4"); - continue; - case 0x6e: - printf("conv.u8"); - continue; - case 0x6f: // callvirt - printf("callvirt <0x%02x%02x%02x%02x>", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], ilCode[i + 1]); - i += 4; - continue; - case 0x70: // cpobj - printf("cpobj <0x%02x%02x%02x%02x>", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], ilCode[i + 1]); - i += 4; - continue; - case 0x71: // ldobj - printf("ldobj <0x%02x%02x%02x%02x>", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], ilCode[i + 1]); - i += 4; - continue; - case 0x72: // ldstr - printf("ldstr <0x%02x%02x%02x%02x>", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], ilCode[i + 1]); - i += 4; - continue; - case 0x73: // newobj - printf("newobj <0x%02x%02x%02x%02x>", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], ilCode[i + 1]); - i += 4; - continue; - case 0x74: // castclass - printf("castclass <0x%02x%02x%02x%02x>", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], ilCode[i + 1]); - i += 4; - continue; - case 0x75: // isinst - printf("isinst <0x%02x%02x%02x%02x>", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], ilCode[i + 1]); - i += 4; - continue; - case 0x76: - printf("conv.r.un"); - continue; - case 0x79: // unbox - printf("unbox <0x%02x%02x%02x%02x>", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], ilCode[i + 1]); - i += 4; - continue; - case 0x7a: - printf("throw"); - continue; - case 0x7b: // ldfld - printf("ldfld <0x%02x%02x%02x%02x>", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], ilCode[i + 1]); - i += 4; - continue; - case 0x7c: // ldflda - printf("ldflda <0x%02x%02x%02x%02x>", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], ilCode[i + 1]); - i += 4; - continue; - case 0x7d: // stfld - printf("stfld <0x%02x%02x%02x%02x>", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], ilCode[i + 1]); - i += 4; - continue; - case 0x7e: // ldsfld - printf("ldsfld <0x%02x%02x%02x%02x>", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], ilCode[i + 1]); - i += 4; - continue; - case 0x7f: // ldsflda - printf("ldsflda <0x%02x%02x%02x%02x>", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], ilCode[i + 1]); - i += 4; - continue; - case 0x80: // stsfld - printf("stsfld <0x%02x%02x%02x%02x>", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], ilCode[i + 1]); - i += 4; - continue; - case 0x81: // stobj - printf("stobj <0x%02x%02x%02x%02x>", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], ilCode[i + 1]); - i += 4; - continue; - case 0x82: - printf("conv.ovf.i1.un"); - continue; - case 0x83: - printf("conv.ovf.i2.un"); - continue; - case 0x84: - printf("conv.ovf.i4.un"); - continue; - case 0x85: - printf("conv.ovf.i8.un"); - continue; - case 0x86: - printf("conv.ovf.u1.un"); - continue; - case 0x87: - printf("conv.ovf.u2.un"); - continue; - case 0x88: - printf("conv.ovf.u4.un"); - continue; - case 0x89: - printf("conv.ovf.u8.un"); - continue; - case 0x8a: - printf("conv.ovf.i.un"); - continue; - case 0x8b: - printf("conv.ovf.u.un"); - continue; - case 0x8c: // box - printf("box <0x%02x%02x%02x%02x>", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], ilCode[i + 1]); - i += 4; - continue; - case 0x8d: // newarr - printf("newarr <0x%02x%02x%02x%02x>", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], ilCode[i + 1]); - i += 4; - continue; - case 0x8e: - printf("ldlen"); - continue; - case 0x8f: - printf("ldelema <0x%02x%02x%02x%02x>", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], ilCode[i + 1]); - i += 4; - continue; - case 0x90: - printf("ldelem.i1"); - continue; - case 0x91: - printf("ldelem.u1"); - continue; - case 0x92: - printf("ldelem.i2"); - continue; - case 0x93: - printf("ldelem.u2"); - continue; - case 0x94: - printf("ldelem.i4"); - continue; - case 0x95: - printf("ldelem.u4"); - continue; - case 0x96: - printf("ldelem.i8"); - continue; - case 0x97: - printf("ldelem.i"); - continue; - case 0x98: - printf("ldelem.r4"); - continue; - case 0x99: - printf("ldelem.r8"); - continue; - case 0x9a: - printf("ldelem.ref"); - continue; - case 0x9b: - printf("stelem.i"); - continue; - case 0x9c: - printf("stelem.i1"); - continue; - case 0x9d: - printf("stelem.i2"); - continue; - case 0x9e: - printf("stelem.i4"); - continue; - case 0x9f: - printf("stelem.i8"); - continue; - case 0xa0: - printf("stelem.r4"); - continue; - case 0xa1: - printf("stelem.r8"); - continue; - case 0xa2: - printf("stelem.ref"); - continue; - case 0xa3: - printf("stelem <0x%02x%02x%02x%02x>", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], ilCode[i + 1]); - i += 4; - continue; - case 0xa4: - printf("stelem <0x%02x%02x%02x%02x>", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], ilCode[i + 1]); - i += 4; - continue; - case 0xa5: - printf("unbox.any <0x%02x%02x%02x%02x>", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], ilCode[i + 1]); - i += 4; - continue; - case 0xb3: - printf("conv.ovf.i1"); - continue; - case 0xb4: - printf("conv.ovf.u1"); - continue; - case 0xb5: - printf("conv.ovf.i2"); - continue; - case 0xb6: - printf("conv.ovf.u2"); - continue; - case 0xb7: - printf("conv.ovf.i4"); - continue; - case 0xb8: - printf("conv.ovf.u4"); - continue; - case 0xb9: - printf("conv.ovf.i8"); - continue; - case 0xba: - printf("conv.ovf.u8"); - continue; - case 0xc2: // refanyval - printf("refanyval <0x%02x%02x%02x%02x>", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], ilCode[i + 1]); - i += 4; - continue; - case 0xc3: - printf("ckfinite"); - continue; - case 0xc6: // mkrefany - printf("mkrefany <0x%02x%02x%02x%02x>", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], ilCode[i + 1]); - i += 4; - continue; - case 0xd0: // ldtoken - printf("ldtoken <0x%02x%02x%02x%02x>", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], ilCode[i + 1]); - i += 4; - continue; - case 0xd1: - printf("conv.u2"); - continue; - case 0xd2: - printf("conv.u1"); - continue; - case 0xd3: - printf("conv.i"); - continue; - case 0xd4: - printf("conv.ovf.i"); - continue; - case 0xd5: - printf("conv.ovf.u"); - continue; - case 0xd6: - printf("add.ovf"); - continue; - case 0xd7: - printf("add.ovf.un"); - continue; - case 0xd8: - printf("mul.ovf"); - continue; - case 0xd9: - printf("mul.ovf.un"); - continue; - case 0xda: - printf("sub.ovf"); - continue; - case 0xdb: - printf("sub.ovf.un"); - continue; - case 0xdc: - printf("endfinally"); - continue; - case 0xdd: // leave XXXX - printf("leave 0x%02x%02x%02x%02x", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], ilCode[i + 1]); - i += 4; - continue; - case 0xde: // leave.s X - printf("leave 0x%02x", ilCode[i + 1]); - i += 1; - continue; - case 0xdf: - printf("stind.i"); - continue; - case 0xe0: - printf("conv.u"); - continue; - case 0xfe: - i++; - switch (ilCode[i]) - { - case 0x00: - printf("arglist"); - continue; - case 0x01: - printf("ceq"); - continue; - case 0x02: - printf("cgt"); - continue; - case 0x03: - printf("cgt.un"); - continue; - case 0x04: - printf("clt"); - continue; - case 0x05: - printf("clt.un"); - continue; - case 0x06: // ldftn - printf("ldftn <0x%02x%02x%02x%02x>", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], - ilCode[i + 1]); - i += 4; - continue; - case 0x07: // ldvirtftn - printf("ldvirtftn <0x%02x%02x%02x%02x>", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], - ilCode[i + 1]); - i += 4; - continue; - case 0x09: // ldarg XX - printf("ldarg 0x%02x%02x", ilCode[i + 2], ilCode[i + 1]); - i += 2; - continue; - case 0x0a: // ldarga XX - printf("ldarga 0x%02x%02x", ilCode[i + 2], ilCode[i + 1]); - i += 2; - continue; - case 0x0b: // starg XX - printf("starg 0x%02x%02x", ilCode[i + 2], ilCode[i + 1]); - i += 2; - continue; - case 0x0c: // ldloc XX - printf("ldloc 0x%02x%02x", ilCode[i + 2], ilCode[i + 1]); - i += 2; - continue; - case 0x0d: // ldloca XX - printf("ldloca 0x%02x%02x", ilCode[i + 2], ilCode[i + 1]); - i += 2; - continue; - case 0x0e: // stloc XX - printf("stloc 0x%02x%02x", ilCode[i + 2], ilCode[i + 1]); - i += 2; - continue; - case 0x0f: - printf("localloc"); - continue; - case 0x11: - printf("endfilter"); - continue; - case 0x12: // unaligned X - printf("unaligned. 0x%02x", ilCode[i + 1]); - i += 1; - continue; - case 0x13: - printf("volatile."); - continue; - case 0x14: - printf("tail."); - continue; - case 0x15: // initobj - printf("initobj <0x%02x%02x%02x%02x>", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], - ilCode[i + 1]); - i += 4; - continue; - case 0x16: // incomplete? - printf("constrained. <0x%02x%02x%02x%02x>", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], - ilCode[i + 1]); - i += 4; - continue; - case 0x17: - printf("cpblk"); - continue; - case 0x18: - printf("initblk"); - continue; - case 0x19: - printf("no."); - continue; // incomplete? - case 0x1a: - printf("rethrow"); - continue; - case 0x1c: // sizeof - printf("sizeof <0x%02x%02x%02x%02x>", ilCode[i + 4], ilCode[i + 3], ilCode[i + 2], - ilCode[i + 1]); - i += 4; - continue; - case 0x1d: - printf("refanytype"); - continue; - default: - LogError("unknown ilCode 0xfe%2x at offset %d in MethodGen::PrettyPrint", ilCode[i], i); - break; - } - break; - default: - LogError("unknown ilCode 0x%02x at offset %d in MethodGen::PrettyPrint", ilCode[i], i); - break; - } - printf("\n"); - } -} -char* DumpAttributeToConsoleBare(DWORD attribute) -{ - const char* s_static = "static"; - const char* s_dontInline = "$dontInline "; - const char* s_constructor = "$constructor"; - -#define ifPrint(s, t) \ - else if ((s & attribute) == s) \ - { \ - printf("%s ", t); \ - } - - if (0) - ; - ifPrint(CORINFO_FLG_STATIC, s_static) - ifPrint(CORINFO_FLG_DONT_INLINE, s_dontInline) - ifPrint(CORINFO_FLG_CONSTRUCTOR, s_constructor) - return nullptr; - -#undef ifPrint -} - -void DumpIL(MethodContext* mc) -{ - CORINFO_METHOD_INFO cmi; - unsigned int flags = 0; - CORINFO_OS os = CORINFO_WINNT; - - mc->repCompileMethod(&cmi, &flags, &os); - - printf("// ProcessName - '%s'\n", mc->cr->repProcessName()); - printf(".assembly extern mscorlib{}\n"); - printf(".assembly dumped_asm\n"); - printf(".class %s\n", getClassName(mc, mc->repGetMethodClass(cmi.ftn)).c_str()); - printf("{\n"); - printf(" .method "); - DumpAttributeToConsoleBare(mc->repGetMethodAttribs(cmi.ftn)); - DumpPrimToConsoleBare(mc, cmi.args.retType, CastHandle(cmi.args.retTypeClass)); - printf(" %s(", getMethodName(mc, cmi.ftn).c_str()); - DumpSigToConsoleBare(mc, &cmi.args); - printf(")\n"); - printf(" {\n"); - printf(" .maxstack %u\n", cmi.maxStack); - printf(" .locals%s(", (((cmi.options & CORINFO_OPT_INIT_LOCALS) == CORINFO_OPT_INIT_LOCALS) ? " init " : " ")); - DumpSigToConsoleBare(mc, &cmi.locals); - printf(")\n"); - DumpILToConsoleBare(cmi.ILCode, cmi.ILCodeSize); - printf(" }\n"); - printf("}\n"); -} - -int verbILDump::DoWork(const char* nameOfInput, int indexCount, const int* indexes) -{ - LogVerbose("// Reading from '%s' dumping raw IL for MC Indexes to console", nameOfInput); - - MethodContextIterator mci(indexCount, indexes); - if (!mci.Initialize(nameOfInput)) - return -1; - - int dumpedCount = 0; - - while (mci.MoveNext()) - { - MethodContext* mc = mci.Current(); - DumpIL(mc); - dumpedCount++; - } - - LogInfo("// Dumped %d", dumpedCount); - - if (!mci.Destroy()) - return -1; - - return 0; -} diff --git a/src/coreclr/tools/superpmi/mcs/verbildump.h b/src/coreclr/tools/superpmi/mcs/verbildump.h deleted file mode 100644 index c78352f5a12404..00000000000000 --- a/src/coreclr/tools/superpmi/mcs/verbildump.h +++ /dev/null @@ -1,22 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// verbILDump.h - verb that attempts to dump the raw IL for a MC -//---------------------------------------------------------- -#ifndef _verbILDump -#define _verbILDump - -#include "methodcontext.h" - -class verbILDump -{ -public: - static int DoWork(const char* nameOfInput1, int indexCount, const int* indexes); -}; - -void DumpPrimToConsoleBare(MethodContext* mc, CorInfoType prim, DWORDLONG classHandle); -void DumpSigToConsoleBare(MethodContext* mc, CORINFO_SIG_INFO* pSig); -char* DumpAttributeToConsoleBare(DWORD attribute); - -#endif diff --git a/src/coreclr/tools/superpmi/mcs/verbinteg.cpp b/src/coreclr/tools/superpmi/mcs/verbinteg.cpp deleted file mode 100644 index 1ea2767fb2fb5e..00000000000000 --- a/src/coreclr/tools/superpmi/mcs/verbinteg.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "standardpch.h" -#include "verbinteg.h" -#include "simpletimer.h" -#include "methodcontext.h" -#include "methodcontextiterator.h" - -int verbInteg::DoWork(const char* nameOfInput) -{ - LogVerbose("Checking the integrity of '%s'", nameOfInput); - - SimpleTimer st2; - st2.Start(); - - MethodContextIterator mci(true); - if (!mci.Initialize(nameOfInput)) - return -1; - - while (mci.MoveNext()) - { - MethodContext* mc = mci.Current(); - // Nothing to do except load the current one. - } - - st2.Stop(); - LogInfo("Checked the integrity of %d methodContexts at %d per second", mci.MethodContextNumber(), - (int)((double)mci.MethodContextNumber() / st2.GetSeconds())); - - if (!mci.Destroy()) - return -1; - - return 0; -} diff --git a/src/coreclr/tools/superpmi/mcs/verbinteg.h b/src/coreclr/tools/superpmi/mcs/verbinteg.h deleted file mode 100644 index c4a85431cfb54f..00000000000000 --- a/src/coreclr/tools/superpmi/mcs/verbinteg.h +++ /dev/null @@ -1,15 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// verbInteg.h - verb that checks the integrity of a MC file -//---------------------------------------------------------- -#ifndef _verbInteg -#define _verbInteg - -class verbInteg -{ -public: - static int DoWork(const char* nameofInput); -}; -#endif diff --git a/src/coreclr/tools/superpmi/mcs/verbjitflags.cpp b/src/coreclr/tools/superpmi/mcs/verbjitflags.cpp deleted file mode 100644 index 33190d3fbd9960..00000000000000 --- a/src/coreclr/tools/superpmi/mcs/verbjitflags.cpp +++ /dev/null @@ -1,130 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "standardpch.h" -#include "verbjitflags.h" -#include "methodcontext.h" -#include "methodcontextiterator.h" -#include "errorhandling.h" -#include "spmidumphelper.h" - -int verbJitFlags::DoWork(const char* nameOfInput) -{ - MethodContextIterator mci; - if (!mci.Initialize(nameOfInput)) - return -1; - - LightWeightMap flagMap; - unsigned mcCount = 0; - - while (mci.MoveNext()) - { - MethodContext* mc = mci.Current(); - CORJIT_FLAGS corJitFlags; - mc->repGetJitFlags(&corJitFlags, sizeof(corJitFlags)); - unsigned long long rawFlags = corJitFlags.GetFlagsRaw(); - - // We co-opt unused flag bits to note if there's pgo data, - // and if so, what kind - // - bool hasEdgeProfile = false; - bool hasClassProfile = false; - bool hasMethodProfile = false; - bool hasLikelyClass = false; - bool hasLikelyMethod = false; - ICorJitInfo::PgoSource pgoSource = ICorJitInfo::PgoSource::Unknown; - if (mc->hasPgoData(hasEdgeProfile, hasClassProfile, hasMethodProfile, hasLikelyClass, hasLikelyMethod, pgoSource)) - { - rawFlags |= 1ULL << (EXTRA_JIT_FLAGS::HAS_PGO); - - if (hasEdgeProfile) - { - rawFlags |= 1ULL << (EXTRA_JIT_FLAGS::HAS_EDGE_PROFILE); - } - - if (hasClassProfile) - { - rawFlags |= 1ULL << (EXTRA_JIT_FLAGS::HAS_CLASS_PROFILE); - } - - if (hasMethodProfile) - { - rawFlags |= 1ULL << (EXTRA_JIT_FLAGS::HAS_METHOD_PROFILE); - } - - if (hasLikelyClass) - { - rawFlags |= 1ULL << (EXTRA_JIT_FLAGS::HAS_LIKELY_CLASS); - } - - if (hasLikelyMethod) - { - rawFlags |= 1ULL << (EXTRA_JIT_FLAGS::HAS_LIKELY_METHOD); - } - - if (pgoSource == ICorJitInfo::PgoSource::Static) - { - rawFlags |= 1ULL << (EXTRA_JIT_FLAGS::HAS_STATIC_PROFILE); - } - - if (pgoSource == ICorJitInfo::PgoSource::Dynamic) - { - rawFlags |= 1ULL << (EXTRA_JIT_FLAGS::HAS_DYNAMIC_PROFILE); - } - } - - int index = flagMap.GetIndex(rawFlags); - if (index == -1) - { - flagMap.Add(rawFlags, 1); - } - else - { - int oldVal = flagMap.GetItem(index); - flagMap.Update(index, oldVal + 1); - } - - mcCount++; - } - - if (!mci.Destroy()) - return -1; - - printf("\nGrouped Flag Appearances (%u contexts)\n\n", mcCount); - printf("%-16s %8s %8s parsed\n", "bits", "count", "percent"); - - unsigned appearancesPerBit[64] = {}; - - const unsigned int count = flagMap.GetCount(); - unsigned long long* pFlags = flagMap.GetRawKeys(); - - for (unsigned int i = 0; i < count; i++) - { - const unsigned long long flags = *pFlags++; - const int index = flagMap.GetIndex(flags); - const unsigned appearances = flagMap.GetItem(index); - - printf("%016llx %8u %7.2f%% %s\n", flags, appearances, 100.0 * ((double) appearances / mcCount), SpmiDumpHelper::DumpJitFlags(flags).c_str()); - - for (unsigned int bit = 0; bit < 64; bit++) - { - if (flags & (1ull << bit)) - { - appearancesPerBit[bit] += appearances; - } - } - } - - printf("\nIndividual Flag Appearances\n\n"); - for (unsigned int bit = 0; bit < 64; bit++) - { - unsigned perBit = appearancesPerBit[bit]; - if (perBit > 0) - { - printf("%8u %7.2f%% %s\n", perBit, 100.0 * (double) perBit / mcCount, SpmiDumpHelper::DumpJitFlags(1ull< -#ifdef TARGET_UNIX -#include -#include -#include -#if !HAVE_DIRENT_D_TYPE -#define DT_UNKNOWN 0 -#define DT_DIR 4 -#define DT_REG 8 -#define DT_LNK 10 -#endif // !HAVE_DIRENT_D_TYPE -#endif // TARGET_UNIX - -#include - -// Do reads/writes in large 256MB chunks. -#define BUFFER_SIZE 0x10000000 - -// static member -RemoveDup verbMerge::m_removeDups; - -// MergePathStrings: take two file system path components, compose them together, and return the merged pathname string. -// The caller must delete the returned string with delete[]. -// -// static -LPWSTR verbMerge::MergePathStrings(LPCWSTR dir, LPCWSTR file) -{ - size_t dirlen = u16_strlen(dir); - size_t filelen = u16_strlen(file); - size_t newlen = dirlen + 1 /* slash */ + filelen + 1 /* null */; - LPWSTR newpath = new WCHAR[newlen]; - u16_strcpy_s(newpath, newlen, dir); - u16_strcat_s(newpath, newlen, DIRECTORY_SEPARATOR_STR_W); - u16_strcat_s(newpath, newlen, file); - return newpath; -} - -char* verbMerge::ConvertWideCharToMultiByte(LPCWSTR wstr) -{ - unsigned int codePage = CP_UTF8; - int sizeNeeded = WideCharToMultiByte(codePage, 0, wstr, -1, NULL, 0, NULL, NULL); - char* encodedStr = new char[sizeNeeded]; - WideCharToMultiByte(codePage, 0, wstr, -1, encodedStr, sizeNeeded, NULL, NULL); - return encodedStr; -} - -WCHAR* verbMerge::ConvertMultiByteToWideChar(LPCSTR str) -{ - unsigned int codePage = CP_UTF8; - int sizeNeeded = MultiByteToWideChar(codePage, 0, str, -1, NULL, 0); - WCHAR* encodedStr = new WCHAR[sizeNeeded]; - MultiByteToWideChar(codePage, 0, str, -1, encodedStr, sizeNeeded); - return encodedStr; -} - -// AppendFileRaw: append the file named by 'fileFullPath' to the output file referred to by 'hFileOut'. The 'hFileOut' -// handle is assumed to be open, and the file position is assumed to be at the correct spot for writing, to append. -// The file is simply appended. -// -// 'buffer' is memory that can be used to do reading/buffering. -// -// static -int verbMerge::AppendFileRaw(HANDLE hFileOut, LPCWSTR fileFullPath, unsigned char* buffer, size_t bufferSize) -{ - int result = 0; // default to zero == success - - char* fileNameAsChar = ConvertWideCharToMultiByte(fileFullPath); - LogInfo("Appending file '%s'", fileNameAsChar); - - HANDLE hFileIn = CreateFileW(fileFullPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); - if (hFileIn == INVALID_HANDLE_VALUE) - { - // If you use a relative path, you can get GetLastError()==3, if the absolute path is longer - // than MAX_PATH. - LogError("Failed to open input file '%s'. GetLastError()=%u", fileNameAsChar, GetLastError()); - return -1; - } - - LARGE_INTEGER fileSize; - if (GetFileSizeEx(hFileIn, &fileSize) == 0) - { - LogError("GetFileSizeEx on '%s' failed. GetLastError()=%u", fileNameAsChar, GetLastError()); - result = -1; - goto CLEAN_UP; - } - - for (LONGLONG offset = 0; offset < fileSize.QuadPart; offset += bufferSize) - { - DWORD bytesRead = -1; - BOOL res = ReadFile(hFileIn, buffer, (DWORD)bufferSize, &bytesRead, nullptr); - if (!res) - { - LogError("Failed to read '%s' from offset %lld. GetLastError()=%u", fileNameAsChar, offset, GetLastError()); - result = -1; - goto CLEAN_UP; - } - DWORD bytesWritten = -1; - BOOL res2 = WriteFile(hFileOut, buffer, bytesRead, &bytesWritten, nullptr); - if (!res2) - { - LogError("Failed to write output file at offset %lld. GetLastError()=%u", offset, GetLastError()); - result = -1; - goto CLEAN_UP; - } - if (bytesRead != bytesWritten) - { - LogError("Failed to read/write matching bytes %u!=%u", bytesRead, bytesWritten); - result = -1; - goto CLEAN_UP; - } - } - -CLEAN_UP: - - delete[] fileNameAsChar; - - if (CloseHandle(hFileIn) == 0) - { - LogError("CloseHandle failed. GetLastError()=%u", GetLastError()); - result = -1; - } - - return result; -} - -// AppendFile: append the file named by 'fileFullPath' to the output file referred to by 'hFileOut'. The 'hFileOut' -// handle is assumed to be open, and the file position is assumed to be at the correct spot for writing, to append. -// -// 'buffer' is memory that can be used to do reading/buffering. -// -// static -int verbMerge::AppendFile(HANDLE hFileOut, LPCWSTR fileFullPath, bool dedup, unsigned char* buffer, size_t bufferSize) -{ - int result = 0; // default to zero == success - - if (dedup) - { - // Need to conver the fileFullPath to non-Unicode. - char* fileFullPathAsChar = ConvertWideCharToMultiByte(fileFullPath); - LogInfo("Appending file '%s'", fileFullPathAsChar); - bool ok = m_removeDups.CopyAndRemoveDups(fileFullPathAsChar, hFileOut); - delete[] fileFullPathAsChar; - if (!ok) - { - LogError("Failed to remove dups"); - return -1; - } - } - else - { - result = AppendFileRaw(hFileOut, fileFullPath, buffer, bufferSize); - } - - return result; -} - -// Return true if this is a directory -// -// static -bool verbMerge::DirectoryFilterDirectories(FilterArgType* findData) -{ -#ifdef TARGET_WINDOWS - if ((findData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) - { -// It's a directory. See if we want to exclude it because of other reasons, such as: -// 1. reparse points: avoid the possibility of loops -// 2. system directories -// 3. hidden directories -// 4. "." or ".." - if ((findData->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) - return false; - if ((findData->dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) != 0) - return false; - if ((findData->dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0) - return false; - - if (u16_strcmp(findData->cFileName, W(".")) == 0) - return false; - if (u16_strcmp(findData->cFileName, W("..")) == 0) - return false; - - return true; - } -#else // TARGET_WINDOWS - if (findData->d_type == DT_DIR) - { - if (u16_strcmp(findData->cFileName, W(".")) == 0) - return false; - if (u16_strcmp(findData->cFileName, W("..")) == 0) - return false; - - return true; - } -#endif // TARGET_WINDOWS - - return false; -} - -// Return true if this is a file. -// -// static -bool verbMerge::DirectoryFilterFile(FilterArgType* findData) -{ -#ifdef TARGET_WINDOWS - if ((findData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) -#else // TARGET_WINDOWS - if (findData->d_type != DT_DIR) -#endif // TARGET_WINDOWS - { - // This is not a directory, so it must be a file. - return true; - } - - return false; -} - -// static -int __cdecl verbMerge::FindData_qsort_helper(const void* p1, const void* p2) -{ - const FindData* file1 = (FindData*)p1; - const FindData* file2 = (FindData*)p2; - return u16_strcmp(file1->cFileName, file2->cFileName); -} - -// Enumerate a directory for the files specified by "searchPattern". For each element in the directory, -// pass it to the filter function. If the filter returns true, we keep it, otherwise we ignore it. Return -// an array of information for the files that we kept, sorted by filename. -// -// Returns 0 on success, non-zero on failure. -// If success, fileArray and elemCount are set. -// -// static -int verbMerge::FilterDirectory(LPCWSTR dir, - LPCWSTR searchPattern, - DirectoryFilterFunction_t filter, - /* out */ FindData** ppFileArray, - int* pElemCount) -{ - - - // First, build up a list, then create an array and sort it after we know how many elements there are. - struct findDataList - { - findDataList(FindData* newFindData, findDataList* newNext) : findData(std::move(*newFindData)), next(newNext) - { - } - - static void DeleteList(findDataList* root) - { - for (findDataList* loop = root; loop != nullptr;) - { - findDataList* tmp = loop; - loop = loop->next; - delete tmp; - } - } - - FindData findData; - findDataList* next; - }; - - FindData* retArray = nullptr; - findDataList* first = nullptr; - - int result = 0; // default to zero == success - int elemCount = 0; - - // NOTE: this function only works on Windows 7 and later. - -#ifdef TARGET_UNIX - std::string dirUtf8 = ConvertToUtf8(dir); - std::string searchPatternUtf8 = ConvertToUtf8(searchPattern); - - DIR* pDir = opendir(dirUtf8.c_str()); - if (pDir != nullptr) - { - while (true) - { - dirent *pEntry; - int dirEntryType; - - errno = 0; - pEntry = readdir(pDir); - if (pEntry == nullptr) - break; - -#if HAVE_DIRENT_D_TYPE - dirEntryType = pEntry->d_type; -#else - dirEntryType = DT_UNKNOWN; -#endif - // On some systems, dirent contains a d_type field, but note: - // some file systems MAY leave d_type == DT_UNKNOWN, - // expecting the consumer to stat the file. On systems - // without a d_type simply always stat the file. - - if (dirEntryType == DT_UNKNOWN) - { - struct stat sb; - - if (fstatat(dirfd(pDir), pEntry->d_name, &sb, 0) == -1) - continue; - - if (S_ISDIR(sb.st_mode)) - dirEntryType = DT_DIR; - else if (S_ISREG(sb.st_mode)) - dirEntryType = DT_REG; - else if (S_ISLNK(sb.st_mode)) - dirEntryType = DT_LNK; - else - dirEntryType = DT_UNKNOWN; - - } - - if (dirEntryType == DT_UNKNOWN) - continue; - - if (fnmatch(searchPatternUtf8.c_str(), pEntry->d_name, 0) != 0) - continue; - - // Call the filter with &FindData like the Windows code below. - FindData findData(dirEntryType, ConvertMultiByteToWideChar(pEntry->d_name)); - if (filter(&findData)) - { - // Prepend it to the list. - first = new findDataList(&findData, first); - ++elemCount; - } - } - - if (errno != 0) - { - LogError("Failed to read directory. errno=%d", errno); - result = -1; - goto CLEAN_UP; - } - } - else - { - if (errno == ENOENT) - { - // This is ok; there was just nothing matching the pattern. - } - else - { - std::string searchPatternUtf8 = ConvertToUtf8(searchPattern); - LogError("Failed to find pattern '%s'. errno=%d", searchPatternUtf8.c_str(), errno); - result = -1; - } - goto CLEAN_UP; - } - -#else // !TARGET_UNIX - FindData findData; - HANDLE hSearch; - LPWSTR completeSearchPattern = MergePathStrings(dir, searchPattern); - hSearch = FindFirstFileExW(completeSearchPattern, - FindExInfoBasic, // We don't care about the short names - &findData, - FindExSearchNameMatch, // standard name matching - NULL, FIND_FIRST_EX_LARGE_FETCH); - - delete [] completeSearchPattern; - - if (hSearch == INVALID_HANDLE_VALUE) - { - DWORD lastErr = GetLastError(); - if (lastErr == ERROR_FILE_NOT_FOUND) - { - // This is ok; there was just nothing matching the pattern. - } - else - { - std::string searchPatternUtf8 = ConvertToUtf8(searchPattern); - LogError("Failed to find pattern '%s'. GetLastError()=%u", searchPatternUtf8.c_str(), GetLastError()); - result = -1; - } - goto CLEAN_UP; - } - - while (true) - { - // Do something with findData... - - if (filter(&findData)) - { - // Prepend it to the list. - first = new findDataList(&findData, first); - ++elemCount; - } - - BOOL ok = FindNextFileW(hSearch, &findData); - if (!ok) - { - DWORD err = GetLastError(); - if (err != ERROR_NO_MORE_FILES) - { - LogError("Failed to find next file. GetLastError()=%u", GetLastError()); - result = -1; - goto CLEAN_UP; - } - break; - } - } -#endif // !TARGET_UNIX - - // Now sort the list. Create an array to put everything in. - - int i; - - retArray = new FindData[elemCount]; - i = 0; - for (findDataList* tmp = first; tmp != nullptr; tmp = tmp->next) - { - retArray[i++] = std::move(tmp->findData); - } - - qsort(retArray, elemCount, sizeof(retArray[0]), FindData_qsort_helper); - -CLEAN_UP: - - findDataList::DeleteList(first); -#ifdef TARGET_WINDOWS - if ((hSearch != INVALID_HANDLE_VALUE) && !FindClose(hSearch)) - { - LogError("Failed to close search handle. GetLastError()=%u", GetLastError()); - delete[] retArray; - return -1; - } -#else // TARGET_WINDOWS - if (pDir != nullptr && (closedir(pDir) != 0)) - { - LogError("Failed to close directory. errno=%d", errno); - delete[] retArray; - return -1; - } -#endif // TARGET_WINDOWS - - *ppFileArray = retArray; - *pElemCount = elemCount; - return result; -} - -// Append all files in the given directory matching the file pattern. -// -// static -int verbMerge::AppendAllInDir(HANDLE hFileOut, - LPCWSTR dir, - LPCWSTR file, - unsigned char* buffer, - size_t bufferSize, - bool recursive, - bool dedup, - /* out */ LONGLONG* size) -{ - int result = 0; // default to zero == success - LONGLONG totalSize = 0; - - FindData* fileArray = nullptr; - int elemCount = 0; - result = FilterDirectory(dir, file, DirectoryFilterFile, &fileArray, &elemCount); - if (result != 0) - { - goto CLEAN_UP; - } - - for (int i = 0; i < elemCount; i++) - { - const FindData& findData = fileArray[i]; - LPWSTR fileFullPath = MergePathStrings(dir, findData.cFileName); - -#ifdef TARGET_WINDOWS - if (u16_strlen(fileFullPath) > MAX_PATH) // This path is too long, use \\?\ to access it. - { - if (u16_strcmp(dir, W(".")) == 0) - { - LogError("can't access the relative path with UNC"); - goto CLEAN_UP; - } - size_t newBufferLen = u16_strlen(fileFullPath) + 30; - LPWSTR newBuffer = new WCHAR[newBufferLen]; - u16_strcpy_s(newBuffer, newBufferLen, W("\\\\?\\")); - if (*fileFullPath == '\\') // It is UNC path, use \\?\UNC\serverName to access it. - { - LPWSTR serverName = fileFullPath; - u16_strcat_s(newBuffer, newBufferLen, W("UNC\\")); - while (*serverName == '\\') - { - serverName++; - } - u16_strcat_s(newBuffer, newBufferLen, serverName); - } - else - { - u16_strcat_s(newBuffer, newBufferLen, fileFullPath); - } - delete[] fileFullPath; - - fileFullPath = newBuffer; - } - - uint64_t fileSize = ((uint64_t)findData.nFileSizeHigh << 32) | findData.nFileSizeLow; - -#else // TARGET_WINDOWS - struct stat fileStat; - char *fileFullPathUtf8 = ConvertWideCharToMultiByte(fileFullPath); - int st = stat(fileFullPathUtf8, &fileStat); - if (st != 0) - { - LogError("Failed to stat file '%s'. errno=%d", fileFullPathUtf8, errno); - result = -1; - delete[] fileFullPath; - delete[] fileFullPathUtf8; - goto CLEAN_UP; - } - delete[] fileFullPathUtf8; - uint64_t fileSize = fileStat.st_size; -#endif // TARGET_WINDOWS - - // Is it zero length? If so, skip it. - if (fileSize == 0) - { - char* fileFullPathAsChar = ConvertWideCharToMultiByte(fileFullPath); - LogInfo("Skipping zero-length file '%s'", fileFullPathAsChar); - delete[] fileFullPathAsChar; - } - else - { - result = AppendFile(hFileOut, fileFullPath, dedup, buffer, bufferSize); - if (result != 0) - { - // Error was already logged. - delete[] fileFullPath; - goto CLEAN_UP; - } - } - - delete[] fileFullPath; - totalSize += fileSize; - } - - // If we need to recurse, then search the directory again for directories, and recursively search each one. - if (recursive) - { - delete[] fileArray; - - fileArray = nullptr; - elemCount = 0; - result = FilterDirectory(dir, W("*"), DirectoryFilterDirectories, &fileArray, &elemCount); - if (result != 0) - { - goto CLEAN_UP; - } - - LONGLONG dirSize = 0; - for (int i = 0; i < elemCount; i++) - { - const FindData& findData = fileArray[i]; - LPWSTR subDir = MergePathStrings(dir, findData.cFileName); - result = AppendAllInDir(hFileOut, subDir, file, buffer, bufferSize, recursive, dedup, &dirSize); - delete [] subDir; - - if (result != 0) - { - // Error was already logged. - goto CLEAN_UP; - } - - totalSize += dirSize; - } - } - -CLEAN_UP: - - delete[] fileArray; - - if (result == 0) - { - *size = totalSize; - } - - return result; -} - -// Merge a set of .MC files into an output .MCH file. The .MC files to merge are given as a pattern, one of: -// 1. *.mc -- simple pattern. Assumes current directory. -// 2. foo\bar\*.mc -- simple pattern with relative directory. -// 3. c:\foo\bar\baz\*.mc -- simple pattern with full path. -// If no pattern is given, then the last component of the path is expected to be a directory name, and the pattern is -// assumed to be "*" (that is, all files). -// -// If "recursive" is true, then the pattern is searched for in the specified directory (or implicit current directory) -// and all sub-directories, recursively. -// -// If "dedup" is true, the we remove duplicates while we are merging. If "stripCR" is also true, we remove CompileResults -// while deduplicating. -// -// static -int verbMerge::DoWork(const char* nameOfOutputFile, const char* pattern, bool recursive, bool dedup, bool stripCR) -{ - int result = 0; // default to zero == success - SimpleTimer st1; - - LogInfo("Merging files matching '%s' into '%s'", pattern, nameOfOutputFile); - - if (dedup) - { - // Initialize the deduplication object - if (!m_removeDups.Initialize(stripCR, /* legacyCompare */ false, /* cleanup */ false)) - { - LogError("Failed to initialize the deduplicator"); - return -1; - } - } - - int nameLength = (int)strlen(nameOfOutputFile) + 1; - LPWSTR nameOfOutputFileAsWchar = new WCHAR[nameLength]; - MultiByteToWideChar(CP_ACP, 0, nameOfOutputFile, -1, nameOfOutputFileAsWchar, nameLength); - - int patternLength = (int)strlen(pattern) + 1; - LPWSTR patternAsWchar = new WCHAR[patternLength]; - MultiByteToWideChar(CP_ACP, 0, pattern, -1, patternAsWchar, patternLength); - - HANDLE hFileOut = CreateFileW(nameOfOutputFileAsWchar, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); - if (hFileOut == INVALID_HANDLE_VALUE) - { - LogError("Failed to open output file '%s'. GetLastError()=%u", nameOfOutputFile, GetLastError()); - return -1; - } - - // Create a buffer we can use for all the copies. - unsigned char* buffer = new unsigned char[BUFFER_SIZE]; - LPCWSTR dir = nullptr; - LPCWSTR file = nullptr; - - LPWSTR lastSlash = (WCHAR*)u16_strrchr(patternAsWchar, DIRECTORY_SEPARATOR_CHAR_A); - if (lastSlash == NULL) - { - // The user may have passed a relative path without a slash, or the current directory. - // If there is a wildcard, we use it as the file pattern. If there isn't, we assume it's a relative directory - // name and use it as a directory, with "*" as the file pattern. - LPCWSTR wildcard = u16_strchr(patternAsWchar, '*'); - if (wildcard == NULL) - { - file = W("*"); - dir = patternAsWchar; - } - else - { - file = patternAsWchar; - dir = W("."); - } - } - else - { - dir = patternAsWchar; - LPCWSTR wildcard = u16_strchr(lastSlash, '*'); - if (wildcard == NULL) - { - file = W("*"); - - // Minor canonicalization: if there is a trailing last slash, strip it (probably should do this in a - // loop...) - if (*(lastSlash + 1) == '\0') - { - *lastSlash = '\0'; - } - } - else - { - // ok, we found a wildcard after the last slash, so assume there is a pattern. Strip it at the last slash. - *lastSlash = '\0'; - file = lastSlash + 1; - } - } - - LONGLONG totalSize = 0; - LONGLONG dirSize = 0; - - st1.Start(); - - result = AppendAllInDir(hFileOut, dir, file, buffer, BUFFER_SIZE, recursive, dedup, &dirSize); - if (result != 0) - { - goto CLEAN_UP; - } - totalSize += dirSize; - - st1.Stop(); - - LogInfo("Read/Wrote %lld MB @ %4.2f MB/s.", totalSize / (1000 * 1000), - (((double)totalSize) / (1000 * 1000)) / - st1.GetSeconds()); // yes yes.. http://en.wikipedia.org/wiki/Megabyte_per_second#Megabyte_per_second - -CLEAN_UP: - - delete[] patternAsWchar; - delete[] buffer; - - if (CloseHandle(hFileOut) == 0) - { - LogError("CloseHandle failed. GetLastError()=%u", GetLastError()); - result = -1; - } - - if (result != 0) - { - // There was a failure. Delete the output file, to avoid leaving some half-created file. - int st = remove(nameOfOutputFile); - if (st != 0) - { - LogError("Failed to delete file after MCS /merge failed. GetLastError()=%u", GetLastError()); - } - } - else - { - if (totalSize == 0) - { - // If the total size of merged files is zero, or there were no files found to merge, - // then there was some problem. - LogError("No files found to merge."); - result = 1; - } - } - - delete[] nameOfOutputFileAsWchar; - - return result; -} diff --git a/src/coreclr/tools/superpmi/mcs/verbmerge.h b/src/coreclr/tools/superpmi/mcs/verbmerge.h deleted file mode 100644 index ce1eee96b7c522..00000000000000 --- a/src/coreclr/tools/superpmi/mcs/verbmerge.h +++ /dev/null @@ -1,99 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// verbMerge.h - verb that merges multiple .MC into one .MCH file -// It allows .MC names to be Unicode names with long paths. -//---------------------------------------------------------- -#ifndef _verbMerge -#define _verbMerge - -#include "removedup.h" - -#ifdef TARGET_WINDOWS -typedef _WIN32_FIND_DATAW FindData; -#else -struct FindData -{ - unsigned char d_type; - WCHAR *cFileName; - - FindData() : d_type(0), cFileName(nullptr) - { - } - - FindData(unsigned char type, WCHAR *fileName) - { - d_type = type; - cFileName = fileName; - } - - // Prevent copying of the FindData, only allow moving so that the cFileName doesn't need to be duplicated. - FindData(const FindData& other) = delete; - FindData& operator=(const FindData& other) = delete; - - FindData(FindData&& other) : d_type(other.d_type), cFileName(other.cFileName) - { - other.d_type = 0; - other.cFileName = nullptr; - } - - FindData& operator=(FindData&& other) - { - d_type = other.d_type; - cFileName = other.cFileName; - other.d_type = 0; - other.cFileName = nullptr; - - return *this; - } - - ~FindData() - { - delete [] cFileName; - } -}; -#endif - -class verbMerge -{ -public: - static int DoWork(const char* nameOfOutputFile, const char* pattern, bool recursive, bool dedup, bool stripCR); - -private: - -#ifdef TARGET_WINDOWS - typedef _WIN32_FIND_DATAW FilterArgType; -#else - typedef struct FindData FilterArgType; -#endif - - typedef bool (*DirectoryFilterFunction_t)(FilterArgType*); - static bool DirectoryFilterDirectories(FilterArgType* findData); - static bool DirectoryFilterFile(FilterArgType* findData); - static int __cdecl FindData_qsort_helper(const void* p1, const void* p2); - static int FilterDirectory(LPCWSTR dir, - LPCWSTR searchPattern, - DirectoryFilterFunction_t filter, - /* out */ FindData** ppFileArray, - int* pElemCount); - - static LPWSTR MergePathStrings(LPCWSTR dir, LPCWSTR file); - - static char* ConvertWideCharToMultiByte(LPCWSTR wstr); - static WCHAR* ConvertMultiByteToWideChar(LPCSTR str); - - static int AppendFileRaw(HANDLE hFileOut, LPCWSTR fileFullPath, unsigned char* buffer, size_t bufferSize); - static int AppendFile(HANDLE hFileOut, LPCWSTR fileFullPath, bool dedup, unsigned char* buffer, size_t bufferSize); - static int AppendAllInDir(HANDLE hFileOut, - LPCWSTR dir, - LPCWSTR file, - unsigned char* buffer, - size_t bufferSize, - bool recursive, - bool dedup, - /* out */ LONGLONG* size); - - static RemoveDup m_removeDups; -}; -#endif diff --git a/src/coreclr/tools/superpmi/mcs/verbprintjiteeversion.cpp b/src/coreclr/tools/superpmi/mcs/verbprintjiteeversion.cpp deleted file mode 100644 index 13c6ea65308ad5..00000000000000 --- a/src/coreclr/tools/superpmi/mcs/verbprintjiteeversion.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "standardpch.h" -#include "verbprintjiteeversion.h" -#include "runtimedetails.h" - -// Print the GUID in format a5eec3a4-4176-43a7-8c2b-a05b551d4f49 -// -// This is useful for tools that want to determine which MCH file to use for a -// particular JIT: if the JIT and MCS are built from the same source tree, then -// use this function to print out the JITEEVersion, and use that to determine -// which MCH files to use. -// -int verbPrintJITEEVersion::DoWork() -{ - const GUID& g = JITEEVersionIdentifier; - printf("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", - g.Data1, - g.Data2, - g.Data3, - g.Data4[0], - g.Data4[1], - g.Data4[2], - g.Data4[3], - g.Data4[4], - g.Data4[5], - g.Data4[6], - g.Data4[7]); - - return 0; -} diff --git a/src/coreclr/tools/superpmi/mcs/verbprintjiteeversion.h b/src/coreclr/tools/superpmi/mcs/verbprintjiteeversion.h deleted file mode 100644 index 6870a452f57d46..00000000000000 --- a/src/coreclr/tools/superpmi/mcs/verbprintjiteeversion.h +++ /dev/null @@ -1,16 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// verbPrintJITEEVersion.h - verb that prints the JITEEVersion GUID that this was built with -//---------------------------------------------------------- -#ifndef _verbPrintJITEEVersion -#define _verbPrintJITEEVersion - -class verbPrintJITEEVersion -{ -public: - static int DoWork(); -}; - -#endif diff --git a/src/coreclr/tools/superpmi/mcs/verbremovedup.cpp b/src/coreclr/tools/superpmi/mcs/verbremovedup.cpp deleted file mode 100644 index a67f7f8debc400..00000000000000 --- a/src/coreclr/tools/superpmi/mcs/verbremovedup.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "standardpch.h" -#include "verbremovedup.h" -#include "removedup.h" - -int verbRemoveDup::DoWork(const char* nameOfInput, const char* nameOfOutput, bool stripCR, bool legacyCompare) -{ - LogVerbose("Removing duplicates from '%s', writing to '%s'", nameOfInput, nameOfOutput); - - HANDLE hFileOut = CreateFileA(nameOfOutput, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); - if (hFileOut == INVALID_HANDLE_VALUE) - { - LogError("Failed to open output '%s'. GetLastError()=%u", nameOfOutput, GetLastError()); - return -1; - } - - RemoveDup removeDups; - if (!removeDups.Initialize(stripCR, legacyCompare, /* cleanup */ false) - || !removeDups.CopyAndRemoveDups(nameOfInput, hFileOut)) - { - LogError("Failed to remove dups"); - return -1; - } - - if (CloseHandle(hFileOut) == 0) - { - LogError("CloseHandle failed. GetLastError()=%u", GetLastError()); - return -1; - } - - return 0; -} diff --git a/src/coreclr/tools/superpmi/mcs/verbremovedup.h b/src/coreclr/tools/superpmi/mcs/verbremovedup.h deleted file mode 100644 index 0f2394d2434425..00000000000000 --- a/src/coreclr/tools/superpmi/mcs/verbremovedup.h +++ /dev/null @@ -1,15 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// verbRemoveDup.h - verb that attempts to remove dups -//---------------------------------------------------------- -#ifndef _verbRemoveDup -#define _verbRemoveDup - -class verbRemoveDup -{ -public: - static int DoWork(const char* nameOfInput1, const char* nameOfOutput, bool stripCR, bool legacyCompare); -}; -#endif diff --git a/src/coreclr/tools/superpmi/mcs/verbstat.cpp b/src/coreclr/tools/superpmi/mcs/verbstat.cpp deleted file mode 100644 index e3cc44de1a0317..00000000000000 --- a/src/coreclr/tools/superpmi/mcs/verbstat.cpp +++ /dev/null @@ -1,73 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "standardpch.h" -#include "verbstat.h" -#include "simpletimer.h" -#include "methodcontext.h" -#include "methodcontextiterator.h" -#include "errorhandling.h" - -int verbStat::DoWork(const char* nameOfInput, const char* nameOfOutput, int indexCount, const int* indexes) -{ - LogVerbose("Stat'ing from '%s' and writing output into '%s'", nameOfInput, nameOfOutput); - - MethodContextIterator mci(indexCount, indexes, true); - if (!mci.Initialize(nameOfInput)) - return -1; - - int savedCount = 0; - - HANDLE hFileOut = CreateFileA(nameOfOutput, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); - if (hFileOut == INVALID_HANDLE_VALUE) - { - LogError("Failed to open input 1 '%s'. GetLastError()=%u", nameOfOutput, GetLastError()); - return -1; - } - -#define bufflen 50000 - DWORD bytesWritten; - char buff[bufflen]; - int offset = 0; - ZeroMemory(&buff[0], bufflen); - offset += sprintf_s(buff, bufflen, "Title,MC#,"); - offset += MethodContext::dumpStatTitleToBuffer(&buff[offset], bufflen - offset); - buff[offset++] = 0x0d; - buff[offset++] = 0x0a; - WriteFile(hFileOut, &buff[0], offset, &bytesWritten, nullptr); - - while (mci.MoveNext()) - { - MethodContext* mc = mci.Current(); - - offset = 0; - ZeroMemory(&buff[0], bufflen); - if ((mc->cr->ProcessName != nullptr) && (mc->cr->ProcessName->GetCount() > 0)) - { - const char* procname = mc->cr->repProcessName(); - strcpy_s(&buff[offset], bufflen, procname); - offset += (int)strlen(procname); - } - buff[offset++] = ','; - offset += sprintf_s(&buff[offset], bufflen - offset, "%d,", mci.MethodContextNumber()); - offset += mc->dumpStatToBuffer(&buff[offset], bufflen - offset); - buff[offset++] = 0x0d; - buff[offset++] = 0x0a; - WriteFile(hFileOut, &buff[0], offset, &bytesWritten, nullptr); - savedCount++; - } - - if (!CloseHandle(hFileOut)) - { - LogError("2nd CloseHandle failed. GetLastError()=%u", GetLastError()); - return -1; - } - - LogInfo("Loaded %d, Stat'd %d", mci.MethodContextNumber(), savedCount); - - if (!mci.Destroy()) - return -1; - - return 0; -} diff --git a/src/coreclr/tools/superpmi/mcs/verbstat.h b/src/coreclr/tools/superpmi/mcs/verbstat.h deleted file mode 100644 index 2c0e072cf0f9f5..00000000000000 --- a/src/coreclr/tools/superpmi/mcs/verbstat.h +++ /dev/null @@ -1,15 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// verbStat.h - verb that -//---------------------------------------------------------- -#ifndef _verbStat -#define _verbStat - -class verbStat -{ -public: - static int DoWork(const char* nameOfInput1, const char* nameOfOutput, int indexCount, const int* indexes); -}; -#endif diff --git a/src/coreclr/tools/superpmi/mcs/verbstrip.cpp b/src/coreclr/tools/superpmi/mcs/verbstrip.cpp deleted file mode 100644 index 5f76e1021ffdc9..00000000000000 --- a/src/coreclr/tools/superpmi/mcs/verbstrip.cpp +++ /dev/null @@ -1,148 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "standardpch.h" -#include "verbstrip.h" -#include "simpletimer.h" -#include "methodcontext.h" -#include "errorhandling.h" -#include "methodcontextreader.h" -#include "methodcontextiterator.h" - -// verbStrip::DoWork handles both "-copy" and "-strip". These both copy from input file to output file, -// but treat the passed-in indexes in opposite ways. -int verbStrip::DoWork( - const char* nameOfInput, const char* nameOfOutput, int indexCount, const int* indexes, bool strip, bool stripCR) -{ - if (strip) - return DoWorkTheOldWay(nameOfInput, nameOfOutput, indexCount, indexes, stripCR); - SimpleTimer* st1 = new SimpleTimer(); - - LogVerbose("Reading from '%s' removing Mc Indexes and writing into '%s'", nameOfInput, nameOfOutput); - - int loadedCount = 0; - MethodContext* mc = nullptr; - int savedCount = 0; - int index = 0; - - // The method context reader handles skipping any unrequested method contexts - // Used in conjunction with an MCI file, it does a lot less work... - MethodContextReader* reader = new MethodContextReader(nameOfInput, indexes, indexCount); - if (!reader->isValid()) - { - return -1; - } - - HANDLE hFileOut = CreateFileA(nameOfOutput, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); - if (hFileOut == INVALID_HANDLE_VALUE) - { - LogError("Failed to open input 1 '%s'. GetLastError()=%u", nameOfOutput, GetLastError()); - return -1; - } - - if (indexCount == -1) - strip = true; // Copy command with no indexes listed should copy all the inputs... - while (true) - { - MethodContextBuffer mcb = reader->GetNextMethodContext(); - if (mcb.Error()) - { - return -1; - } - else if (mcb.allDone()) - { - break; - } - - loadedCount++; - if ((loadedCount % 500 == 0) && (loadedCount > 0)) - { - st1->Stop(); - LogVerbose("%2.1f%% - Loaded %d at %d per second", reader->PercentComplete(), loadedCount, - (int)((double)500 / st1->GetSeconds())); - st1->Start(); - } - - if (!MethodContext::Initialize(loadedCount, mcb.buff, mcb.size, !stripCR, &mc)) - return -1; - - mc->saveToFile(hFileOut); - savedCount++; - delete mc; - } - if (CloseHandle(hFileOut) == 0) - { - LogError("2nd CloseHandle failed. GetLastError()=%u", GetLastError()); - return -1; - } - LogInfo("Loaded %d, Saved %d", loadedCount, savedCount); - - return 0; -} - -// This is only used for "-strip". -int verbStrip::DoWorkTheOldWay( - const char* nameOfInput, const char* nameOfOutput, int indexCount, const int* indexes, bool stripCR) -{ - LogVerbose("Reading from '%s' removing MC Indexes and writing into '%s'", nameOfInput, nameOfOutput); - - MethodContextIterator mci(true); - if (!mci.Initialize(nameOfInput)) - return -1; - - int savedCount = 0; - bool write; - int index = 0; // Can't use MethodContextIterator indexing, since we want the opposite of that. - - HANDLE hFileOut = CreateFileA(nameOfOutput, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); - if (hFileOut == INVALID_HANDLE_VALUE) - { - LogError("Failed to open input 1 '%s'. GetLastError()=%u", nameOfOutput, GetLastError()); - return -1; - } - - while (mci.MoveNext()) - { - MethodContext* mc = mci.Current(); - - write = true; // assume we'll write it - if (index < indexCount) - { - if (indexes[index] == mci.MethodContextNumber()) - { - index++; - write = false; - } - } - - if (write) - { - if (stripCR) - { - delete mc->cr; - mc->cr = new CompileResult(); - } - mc->saveToFile(hFileOut); - savedCount++; - } - } - - if (CloseHandle(hFileOut) == 0) - { - LogError("2nd CloseHandle failed. GetLastError()=%u", GetLastError()); - return -1; - } - - if (index < indexCount) - LogWarning("Didn't use all of index count input %d < %d (i.e. didn't see MC #%d)", index, indexCount, - indexes[index]); - - LogInfo("Loaded %d, Saved %d", mci.MethodContextNumber(), savedCount); - - if (!mci.Destroy()) - return -1; - - return 0; -} diff --git a/src/coreclr/tools/superpmi/mcs/verbstrip.h b/src/coreclr/tools/superpmi/mcs/verbstrip.h deleted file mode 100644 index bed49af5dcc1d6..00000000000000 --- a/src/coreclr/tools/superpmi/mcs/verbstrip.h +++ /dev/null @@ -1,22 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// verbStrip.h - verb that removes a list of mc's from an MCH file -//---------------------------------------------------------- -#ifndef _verbStrip -#define _verbStrip - -class verbStrip -{ -public: - static int DoWork(const char* nameOfInput1, - const char* nameOfOutput, - int indexCount, - const int* indexes, - bool strip, - bool stripCR); - static int DoWorkTheOldWay( - const char* nameOfInput, const char* nameOfOutput, int indexCount, const int* indexes, bool stripCR); -}; -#endif diff --git a/src/coreclr/tools/superpmi/mcs/verbtoc.cpp b/src/coreclr/tools/superpmi/mcs/verbtoc.cpp deleted file mode 100644 index d2a384388c12fd..00000000000000 --- a/src/coreclr/tools/superpmi/mcs/verbtoc.cpp +++ /dev/null @@ -1,107 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "standardpch.h" -#include "verbtoc.h" -#include "methodcontext.h" -#include "methodcontextreader.h" -#include "methodcontextiterator.h" -#include "simpletimer.h" - -class TOCElementNode -{ -public: - TOCElementNode* Next; - TOCElement tocElement; - - TOCElementNode(int number, int64_t offset) : Next(nullptr), tocElement(number, offset) - { - } -}; - -int verbTOC::DoWork(const char* nameOfInput) -{ - LogVerbose("Indexing from '%s' into '%s.mct'", nameOfInput, nameOfInput); - - MethodContextIterator mci; - if (!mci.Initialize(nameOfInput)) - return -1; - - int savedCount = 0; - - TOCElementNode* head = nullptr; - TOCElementNode* curElem = nullptr; - - while (mci.MoveNext()) - { - MethodContext* mc = mci.Current(); - - TOCElementNode* nxt = new TOCElementNode(mci.MethodContextNumber(), mci.CurrentPos()); - mc->dumpMethodHashToBuffer(nxt->tocElement.Hash, MM3_HASH_BUFFER_SIZE); - - if (curElem != nullptr) - { - curElem->Next = nxt; - } - else - { - head = nxt; - } - curElem = nxt; - savedCount++; - } - - size_t maxLen = strlen(nameOfInput) + 5; - char* nameOfOutput = (char*)_alloca(maxLen); - strcpy_s(nameOfOutput, maxLen, nameOfInput); - strcat_s(nameOfOutput, maxLen, ".mct"); - HANDLE hFileOut = - CreateFileA(nameOfOutput, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (hFileOut == INVALID_HANDLE_VALUE) - { - LogError("Failed to open input 1 '%s'. GetLastError()=%u", nameOfOutput, GetLastError()); - return -1; - } - - DWORD written; - // Write out the signature "INDX" and then the element count - LARGE_INTEGER token; - token.u.LowPart = *(const int*)"INDX"; // cuz Type Safety is for languages that have good IO facilities - token.u.HighPart = savedCount; - if (!WriteFile(hFileOut, &token, sizeof(token), &written, nullptr) || written != sizeof(token)) - { - LogError("Failed to write index header. GetLastError()=%u", GetLastError()); - } - - // Now just dump sizeof(TOCElement) byte chunks into the file. - // I could probably do this more efficiently, but I don't think it matters - DWORD chunkSize = sizeof(TOCElement); - for (curElem = head; curElem != nullptr; curElem = curElem->Next) - { - if (!WriteFile(hFileOut, &curElem->tocElement, chunkSize, &written, nullptr) || written != chunkSize) - { - LogError("Failed to write index element '%d'. GetLastError()=%u", curElem->tocElement.Number, - GetLastError()); - return -1; - } - } - // Now write out a final "INDX" to flag the end of the file... - if (!WriteFile(hFileOut, &token.u.LowPart, sizeof(token.u.LowPart), &written, nullptr) || - (written != sizeof(token.u.LowPart))) - { - LogError("Failed to write index terminal. GetLastError()=%u", GetLastError()); - } - - LogInfo("Loaded %d, added %d to Table of Contents", mci.MethodContextNumber(), savedCount); - - if (CloseHandle(hFileOut) == 0) - { - LogError("CloseHandle failed. GetLastError()=%u", GetLastError()); - return -1; - } - - if (!mci.Destroy()) - return -1; - - return 0; -} diff --git a/src/coreclr/tools/superpmi/mcs/verbtoc.h b/src/coreclr/tools/superpmi/mcs/verbtoc.h deleted file mode 100644 index e9666bcad40844..00000000000000 --- a/src/coreclr/tools/superpmi/mcs/verbtoc.h +++ /dev/null @@ -1,15 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// verbTOC.h - verb that creates a Table of Context for a MCH file -//---------------------------------------------------------- -#ifndef _verbTOC -#define _verbTOC - -class verbTOC -{ -public: - static int DoWork(const char* nameOfInput1); -}; -#endif diff --git a/src/coreclr/tools/superpmi/readme.md b/src/coreclr/tools/superpmi/readme.md index e1b32d464f5a71..b1b20c6edafc3a 100644 --- a/src/coreclr/tools/superpmi/readme.md +++ b/src/coreclr/tools/superpmi/readme.md @@ -48,8 +48,23 @@ These are then compared either visually, or with the jitutils tool # Tools -There are two native executable tools: `superpmi` and `mcs`. To do the collection, -there is the `superpmi-shim-collector` binary (`.dll` or `.so` or `.dylib`). +There are two executable tools: `superpmi`, which replays method contexts, and `mcs`, which +manipulates the collections. To do the collection, there is the `superpmi-shim-collector` +library (`.dll` or `.so` or `.dylib`), which the runtime loads as its JIT; the `superpmi-shim-counter` +and `superpmi-shim-simple` libraries work the same way, to count the JIT-EE interface calls and to +measure the cost of the shims. + +All of them are written in C# (in `managed`), and published with NativeAOT next to the JIT: + +* `managed/SuperPmi.Shared`: the method context format, and the recording (`rec*`), replaying (`rep*`) + and dumping (`dmp*`) of the JIT-EE interface calls. +* `managed/superpmi`, `managed/mcs`: the executable tools. Without NativeAOT for the platform, they are + single-file apps. +* `managed/superpmi-shim-*`, with the code they share in `managed/shim`: the shims, which need NativeAOT. +* `jitinterface`: the native code they need, to call the JIT and the runtime through their C++ interfaces. + Most of it is generated with the JIT interface (`src/coreclr/tools/Common/JitInterface/ThunkGenerator`). + It is built as static libraries in `superpmi-lib`, which NativeAOT links into the tools; a single-file + `superpmi` gets a copy of the `superpmi-jitinterface` shared library next to it instead. To harness collection, there is a .NET Core C# program that is built as part of the coreclr tests build called superpmicollect.exe diff --git a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h deleted file mode 100644 index 3c9308a21ca017..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h +++ /dev/null @@ -1,897 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// agnostic.h - Definition of platform-agnostic data types used by SuperPMI. -// MethodContext and CompileResult types use these. -//---------------------------------------------------------- -#ifndef _Agnostic -#define _Agnostic - -#pragma pack(push, 1) - -struct Agnostic_CORINFO_SIG_INFO -{ - DWORD callConv; - DWORDLONG retTypeClass; - DWORDLONG retTypeSigClass; - DWORD retType; - DWORD flags; - DWORD numArgs; - DWORD sigInst_classInstCount; - DWORD sigInst_classInst_Index; - DWORD sigInst_methInstCount; - DWORD sigInst_methInst_Index; - DWORDLONG args; - DWORD pSig_Index; - DWORD cbSig; - DWORDLONG methodSignature; - DWORDLONG scope; - DWORD token; -}; - -struct Agnostic_CORINFO_CONST_LOOKUP -{ - DWORD accessType; - DWORDLONG handle; // actually a union of two pointer sized things -}; - -struct Agnostic_CORINFO_LOOKUP_KIND -{ - DWORD needsRuntimeLookup; - DWORD runtimeLookupKind; -}; - -struct Agnostic_CORINFO_RUNTIME_LOOKUP -{ - DWORDLONG signature; - DWORD helper; - DWORD indirections; - DWORD testForNull; - WORD sizeOffset; - DWORDLONG offsets[CORINFO_MAXINDIRECTIONS]; - DWORD indirectFirstOffset; - DWORD indirectSecondOffset; - Agnostic_CORINFO_CONST_LOOKUP helperEntryPoint; -}; - -struct Agnostic_CORINFO_LOOKUP -{ - Agnostic_CORINFO_LOOKUP_KIND lookupKind; - Agnostic_CORINFO_RUNTIME_LOOKUP runtimeLookup; // This and constLookup actually a union, but with different - // layouts.. :-| copy the right one based on lookupKinds value - Agnostic_CORINFO_CONST_LOOKUP constLookup; -}; - -struct Agnostic_CORINFO_METHOD_INFO -{ - DWORDLONG ftn; - DWORDLONG scope; - DWORD ILCode_offset; - DWORD ILCodeSize; - DWORD maxStack; - DWORD EHcount; - DWORD options; - DWORD regionKind; - Agnostic_CORINFO_SIG_INFO args; - Agnostic_CORINFO_SIG_INFO locals; -}; - -struct Agnostic_CompileMethod -{ - Agnostic_CORINFO_METHOD_INFO info; - DWORD flags; - DWORD os; -}; - -struct Agnostic_InitClass -{ - DWORDLONG field; - DWORDLONG method; - DWORDLONG context; -}; - -struct DLDL -{ - DWORDLONG A; - DWORDLONG B; -}; - -struct Agnostic_CanInline -{ - DWORD result; - DWORD exceptionCode; -}; - -struct Agnostic_GetClassGClayout -{ - DWORD gcPtrs_Index; - DWORD len; - DWORD valCount; -}; - -struct DLD -{ - DWORDLONG A; - DWORD B; -}; - -struct DLDD -{ - DWORDLONG A; - DWORD B; - DWORD C; -}; - -struct DLDDD -{ - DWORDLONG A; - DWORD B; - DWORD C; - DWORD D; -}; - -struct Agnostic_CORINFO_METHODNAME_TOKENin -{ - DWORDLONG ftn; - DWORD className; - DWORD namespaceName; - DWORD maxEnclosingClassNames; -}; - -struct Agnostic_CORINFO_METHODNAME_TOKENout -{ - DWORD methodName; - DWORD className; - DWORD namespaceName; - DWORD enclosingClassNames; -}; - -struct Agnostic_CORINFO_RESOLVED_TOKENin -{ - DWORDLONG tokenContext; - DWORDLONG tokenScope; - DWORD token; - DWORD tokenType; -}; - -struct Agnostic_CORINFO_RESOLVED_TOKENout -{ - DWORDLONG hClass; - DWORDLONG hMethod; - DWORDLONG hField; - DWORD pTypeSpec_Index; - DWORD cbTypeSpec; - DWORD pMethodSpec_Index; - DWORD cbMethodSpec; -}; - -struct Agnostic_GetArgType_Key -{ - // Partial CORINFO_SIG_INFO data - DWORD flags; - DWORD numArgs; - DWORD sigInst_classInstCount; - DWORD sigInst_classInst_Index; - DWORD sigInst_methInstCount; - DWORD sigInst_methInst_Index; - DWORDLONG methodSignature; - DWORDLONG scope; - - // Other getArgType() arguments - DWORDLONG args; -}; - -struct Agnostic_GetArgClass_Key -{ - DWORD sigInst_classInstCount; - DWORD sigInst_classInst_Index; - DWORD sigInst_methInstCount; - DWORD sigInst_methInst_Index; - DWORDLONG methodSignature; - DWORDLONG scope; - DWORDLONG args; -}; - -struct Agnostic_GetBoundaries -{ - DWORD cILOffsets; - DWORD pILOffset_offset; - DWORD implicitBoundaries; -}; - -struct Agnostic_CORINFO_EE_INFO -{ - struct Agnostic_InlinedCallFrameInfo - { - DWORD size; - DWORD sizeWithSecretStubArg; - DWORD offsetOfFrameLink; - DWORD offsetOfCallSiteSP; - DWORD offsetOfCalleeSavedFP; - DWORD offsetOfCallTarget; - DWORD offsetOfReturnAddress; - DWORD offsetOfSecretStubArg; - DWORD offsetOfSPAfterProlog; - } inlinedCallFrameInfo; - DWORD offsetOfThreadFrame; - DWORD offsetOfGCState; - DWORD offsetOfDelegateInstance; - DWORD offsetOfDelegateFirstTarget; - DWORD sizeOfReversePInvokeFrame; - DWORD osPageSize; - DWORD maxUncheckedOffsetForNullObject; - DWORD targetAbi; - DWORD osType; -}; - -struct Agnostic_CORINFO_ASYNC_INFO -{ - DWORDLONG continuationClsHnd; - DWORDLONG continuationNextFldHnd; - DWORDLONG continuationResumeInfoFldHnd; - DWORDLONG continuationStateFldHnd; - DWORDLONG continuationFlagsFldHnd; - DWORDLONG captureExecutionContextMethHnd; - DWORDLONG captureContinuationContextMethHnd; - DWORDLONG captureContextsMethHnd; - DWORDLONG restoreContextsMethHnd; - DWORDLONG restoreContextsOnSuspensionMethHnd; - DWORDLONG restoreInlinedFrameContextsMethHnd; - DWORDLONG captureInlinedFrameTransitionWithContinuationContextMethHnd; - DWORDLONG captureInlinedFrameTransitionNoContinuationContextMethHnd; - DWORDLONG captureInlinedFrameTransitionContinueOnThreadPoolMethHnd; - DWORDLONG finishSuspensionNoContinuationContextMethHnd; - DWORDLONG finishSuspensionWithContinuationContextMethHnd; -}; - -struct Agnostic_CORINFO_WASM_WELLKNOWN_GLOBALS -{ - DWORDLONG stackPointer; - DWORDLONG imageBase; - DWORDLONG tableBase; - DWORDLONG asyncContinuation; -}; - -struct Agnostic_GetAwaitReturnCallResult -{ - DWORDLONG methodHnd; - DWORDLONG contextHandle; - Agnostic_CORINFO_LOOKUP instArg; -}; - -struct Agnostic_GetOSRInfo -{ - DWORD index; - unsigned ilOffset; -}; - -struct Agnostic_GetStaticFieldCurrentClass -{ - DWORDLONG classHandle; - bool isSpeculative; -}; - -struct Agnostic_CORINFO_TYPE_LAYOUT_NODE -{ - DWORDLONG simdTypeHnd; - DWORDLONG diagFieldHnd; - DWORD parent; - DWORD offset; - DWORD size; - DWORD numFields; - BYTE type; - bool hasSignificantPadding; -}; - -struct Agnostic_GetTypeLayoutResult -{ - DWORD result; - DWORD nodesBuffer; - DWORD numNodes; -}; - -struct Agnostic_CORINFO_RESOLVED_TOKEN -{ - Agnostic_CORINFO_RESOLVED_TOKENin inValue; - Agnostic_CORINFO_RESOLVED_TOKENout outValue; -}; - -struct Agnostic_GetAwaitAwaiterInContinuationCall -{ - DWORDLONG callerHnd; - Agnostic_CORINFO_RESOLVED_TOKEN ResolvedToken; - DWORD isUnsafe; -}; - -struct Agnostic_GetFieldInfo -{ - Agnostic_CORINFO_RESOLVED_TOKEN ResolvedToken; - DWORDLONG callerHandle; - DWORD flags; -}; - -struct Agnostic_CORINFO_HELPER_ARG -{ - DWORDLONG constant; // one view of a large union of ptr size - DWORD argType; -}; - -struct Agnostic_CORINFO_HELPER_DESC -{ - DWORD helperNum; - DWORD numArgs; - Agnostic_CORINFO_HELPER_ARG args[CORINFO_ACCESS_ALLOWED_MAX_ARGS]; -}; - -struct Agnostic_GetHelperFtn -{ - Agnostic_CORINFO_CONST_LOOKUP helperLookup; - DWORDLONG helperMethod; -}; - -struct Agnostic_CORINFO_FIELD_INFO -{ - DWORD fieldAccessor; - DWORD fieldFlags; - DWORD helper; - DWORD offset; - DWORD fieldType; - DWORDLONG structType; - DWORD accessAllowed; - Agnostic_CORINFO_HELPER_DESC accessCalloutHelper; - Agnostic_CORINFO_CONST_LOOKUP fieldLookup; -}; - -struct DD -{ - DWORD A; - DWORD B; -}; - -struct DDD -{ - DWORD A; - DWORD B; - DWORD C; -}; - -struct Agnostic_CanTailCall -{ - DWORDLONG callerHnd; - DWORDLONG declaredCalleeHnd; - DWORDLONG exactCalleeHnd; - WORD fIsTailPrefix; -}; - -struct Agnostic_Environment -{ - DWORD name_index; - ; - DWORD val_index; -}; - -struct Agnostic_GetCallInfo -{ - Agnostic_CORINFO_RESOLVED_TOKEN ResolvedToken; - Agnostic_CORINFO_RESOLVED_TOKEN ConstrainedResolvedToken; - DWORDLONG callerHandle; - DWORD flags; -}; - -struct Agnostic_CORINFO_CALL_INFO -{ - DWORDLONG hMethod; - DWORD methodFlags; - DWORD classFlags; - Agnostic_CORINFO_SIG_INFO sig; - DWORD accessAllowed; - Agnostic_CORINFO_HELPER_DESC callsiteCalloutHelper; - DWORD thisTransform; - DWORD kind; - DWORD nullInstanceCheck; - DWORDLONG contextHandle; - DWORD exactContextNeedsRuntimeLookup; - Agnostic_CORINFO_LOOKUP stubLookup; // first view of union. others are matching or subordinate - Agnostic_CORINFO_CONST_LOOKUP instParamLookup; - DWORD exceptionCode; -}; - -struct Agnostic_GetMethodInfo -{ - Agnostic_CORINFO_METHOD_INFO info; - bool result; - DWORD exceptionCode; -}; - -struct Agnostic_FindSig -{ - DWORDLONG module; - DWORD sigTOK; - DWORDLONG context; -}; - -struct MethodOrSigInfoValue -{ - DWORDLONG method; - DWORD pSig_Index; - DWORD cbSig; - DWORDLONG scope; -}; - -struct Agnostic_CORINFO_EH_CLAUSE -{ - DWORD Flags; - DWORD TryOffset; - DWORD TryLength; - DWORD HandlerOffset; - DWORD HandlerLength; - DWORD ClassToken; // first view of a two dword union -}; - -struct Agnostic_GetVars -{ - DWORD cVars; - DWORD vars_offset; - DWORD extendOthers; -}; - -struct Agnostic_CanAccessClassIn -{ - Agnostic_CORINFO_RESOLVED_TOKEN ResolvedToken; - DWORDLONG callerHandle; -}; - -struct Agnostic_CanAccessClassOut -{ - Agnostic_CORINFO_HELPER_DESC AccessHelper; - DWORD result; -}; - -struct Agnostic_AppendClassNameIn -{ - DWORD nBufLenIsZero; - DWORDLONG classHandle; -}; - -struct Agnostic_AppendClassNameOut -{ - DWORD nLen; - DWORD name_index; -}; - -struct Agnostic_CheckMethodModifier -{ - DWORDLONG hMethod; - DWORD modifier; - DWORD fOptional; -}; - -struct Agnostic_EmbedGenericHandle -{ - Agnostic_CORINFO_RESOLVED_TOKEN ResolvedToken; - DWORDLONG hCallerHandle; - DWORD fEmbedParent; -}; - -struct Agnostic_ExpandRawHandleIntrinsic -{ - Agnostic_CORINFO_RESOLVED_TOKENin ResolvedToken; - DWORDLONG hCallerHandle; -}; - -struct Agnostic_CORINFO_GENERICHANDLE_RESULT -{ - Agnostic_CORINFO_LOOKUP lookup; - DWORDLONG compileTimeHandle; - DWORD handleType; -}; - -struct Agnostic_GetDelegateCtorIn -{ - DWORDLONG methHnd; - DWORDLONG clsHnd; - DWORDLONG targetMethodHnd; -}; - -struct Agnostic_DelegateCtorArgs -{ - DWORDLONG pMethod; - DWORDLONG pArg3; - DWORDLONG pArg4; - DWORDLONG pArg5; -}; - -struct Agnostic_GetDelegateCtorOut -{ - Agnostic_DelegateCtorArgs CtorData; - DWORDLONG result; -}; - -struct Agnostic_FindCallSiteSig -{ - DWORDLONG module; - DWORD methTok; - DWORDLONG context; -}; - -struct Agnostic_GetCastingHelper -{ - DWORDLONG hClass; - DWORD fThrowing; -}; - -struct Agnostic_GetClassModuleIdForStatics -{ - DWORDLONG Module; - DWORDLONG pIndirection; - DWORDLONG result; -}; - -struct Agnostic_GetIsClassInitedFlagAddress -{ - Agnostic_CORINFO_CONST_LOOKUP addr; - DWORD offset; - DWORD result; -}; - -struct Agnostic_GetStaticBaseAddress -{ - Agnostic_CORINFO_CONST_LOOKUP addr; - DWORD result; -}; - -struct Agnostic_PgoInstrumentationSchema -{ - DWORDLONG Offset; // size_t - DWORD InstrumentationKind; // ICorJitInfo::PgoInstrumentationKind - DWORD ILOffset; // int32_t - DWORD Count; // int32_t - DWORD Other; // int32_t -}; - -struct Agnostic_AllocPgoInstrumentationBySchema -{ - DWORDLONG instrumentationDataAddress; - DWORD schema_index; - DWORD countSchemaItems; - DWORD result; -}; - -struct Agnostic_GetPgoInstrumentationResults -{ - DWORD countSchemaItems; - DWORD schema_index; - DWORD data_index; - DWORD dataByteCount; - DWORD result; - DWORD pgoSource; - DWORD dynamicPgo; -}; - -struct Agnostic_GetProfilingHandle -{ - DWORD bHookFunction; - DWORDLONG ProfilerHandle; - DWORD bIndirectedHandles; -}; - -struct Agnostic_GetThreadLocalStaticBlocksInfo -{ - Agnostic_CORINFO_CONST_LOOKUP tlsIndex; - DWORDLONG tlsGetAddrFtnPtr; - DWORDLONG tlsIndexObject; - DWORDLONG threadVarsSection; - DWORD offsetOfThreadLocalStoragePointer; - DWORD offsetOfMaxThreadStaticBlocks; - DWORD offsetOfThreadStaticBlocks; - DWORD offsetOfBaseOfThreadLocalData; -}; - -struct Agnostic_GetThreadStaticInfo_NativeAOT -{ - DWORD offsetOfThreadLocalStoragePointer; - Agnostic_CORINFO_CONST_LOOKUP tlsRootObject; - Agnostic_CORINFO_CONST_LOOKUP tlsIndexObject; - Agnostic_CORINFO_CONST_LOOKUP threadStaticBaseSlow; - Agnostic_CORINFO_CONST_LOOKUP tlsGetAddrFtnPtr; -}; - -struct Agnostic_GetClassCtorInitializationInfo -{ - Agnostic_CORINFO_CONST_LOOKUP addr; - Agnostic_CORINFO_CONST_LOOKUP targetAddr; - int size; -}; - -struct Agnostic_GetThreadLocalFieldInfo -{ - DWORD staticBlockIndex; -}; - -struct Agnostic_GetTailCallHelpers -{ - Agnostic_CORINFO_RESOLVED_TOKEN callToken; - Agnostic_CORINFO_SIG_INFO sig; - DWORD flags; -}; - -struct Agnostic_CORINFO_TAILCALL_HELPERS -{ - bool result; - DWORD flags; - DWORDLONG hStoreArgs; - DWORDLONG hCallTarget; - DWORDLONG hDispatcher; -}; - -struct Agnostic_GetArgClass_Value -{ - DWORDLONG result; - DWORD exceptionCode; -}; - -struct Agnostic_GetArgType_Value -{ - DWORDLONG vcTypeRet; - DWORD result; - DWORD exceptionCode; -}; - -struct Agnostic_GetExactClassesResult -{ - int numClasses; - DWORD classes; -}; - -// Agnostic_ConfigIntInfo combines as a single key the name -// and defaultValue of a integer config query. -// Note: nameIndex is treated as a DWORD index to the name string. -struct Agnostic_ConfigIntInfo -{ - DWORD nameIndex; - DWORD defaultValue; -}; - -// SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR -struct Agnostic_GetSystemVAmd64PassStructInRegisterDescriptor -{ - DWORD passedInRegisters; // Whether the struct is passable/passed (this includes struct returning) in registers. - DWORD eightByteCount; // Number of eightbytes for this struct. - DWORD eightByteClassifications[CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS]; // The eightbytes type - // classification. - DWORD eightByteSizes[CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS]; // The size of the eightbytes (an - // eightbyte could include padding. - // This represents the no padding - // size of the eightbyte). - DWORD eightByteOffsets[CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS]; // The start offset of the - // eightbytes (in bytes). - DWORD result; -}; - -struct Agnostic_GetSwiftLowering -{ - DWORD byReference; - DWORD loweredElements[MAX_SWIFT_LOWERED_ELEMENTS]; - DWORD offsets[MAX_SWIFT_LOWERED_ELEMENTS]; - DWORD numLoweredElements; -}; - -struct Agnostic_GetFpStructLowering -{ - DWORD byIntegerCallConv; - DWORD loweredElements[MAX_FPSTRUCT_LOWERED_ELEMENTS]; - DWORD offsets[MAX_FPSTRUCT_LOWERED_ELEMENTS]; - DWORD numLoweredElements; -}; - -struct Agnostic_GetContinuationTypeIn -{ - DWORDLONG dataSize; - DWORD objRefs; - DWORD objRefsSize; -}; - -struct Agnostic_GetWasmTypeSymbol -{ - DWORD types; - DWORD typesSize; -}; - -struct Agnostic_ResolveVirtualMethodKey -{ - DWORDLONG virtualMethod; - DWORDLONG objClass; - DWORDLONG context; - DWORD pResolvedTokenVirtualMethodNonNull; - Agnostic_CORINFO_RESOLVED_TOKEN pResolvedTokenVirtualMethod; -}; - -struct Agnostic_ResolveVirtualMethodResult -{ - bool returnValue; - DWORDLONG devirtualizedMethod; - DWORDLONG tokenLookupContext; - DWORD detail; - Agnostic_CORINFO_RESOLVED_TOKEN resolvedTokenDevirtualizedMethod; - Agnostic_CORINFO_RESOLVED_TOKEN resolvedTokenDevirtualizedUnboxedMethod; - Agnostic_CORINFO_LOOKUP instParamLookup; -}; - -struct ResolveTokenValue -{ - Agnostic_CORINFO_RESOLVED_TOKENout tokenOut; - DWORD exceptionCode; -}; - -struct GetTokenTypeAsHandleValue -{ - DWORDLONG hMethod; - DWORDLONG hField; -}; - -struct GetVarArgsHandleValue -{ - DWORD cbSig; - DWORD pSig_Index; - DWORDLONG scope; - DWORD token; - DWORDLONG methHnd; -}; - -struct GetCookieForInterpreterCalliSigValue -{ - DWORD cbSig; - DWORD pSig_Index; - DWORDLONG scope; - DWORD token; -}; - -struct GetReadyToRunHelper_TOKENin -{ - Agnostic_CORINFO_RESOLVED_TOKEN ResolvedToken; - DWORD id; - DWORDLONG callerHandle; -}; - -struct GetReadyToRunHelper_TOKENout -{ - Agnostic_CORINFO_CONST_LOOKUP Lookup; - bool result; -}; - -struct GetReadyToRunDelegateCtorHelper_TOKENIn -{ - Agnostic_CORINFO_RESOLVED_TOKEN TargetMethod; - mdToken targetConstraint; - DWORDLONG delegateType; - DWORDLONG callerHandle; -}; - -struct Agnostic_RecordRelocation -{ - DWORDLONG location; - DWORDLONG target; - DWORD fRelocType; - DWORD addlDelta; -}; - -struct Capture_AllocMemDetails -{ - ULONG hotCodeSize; - ULONG coldCodeSize; - ULONG roDataSize; - ULONG xcptnsCount; - void* hotCodeBlock; - void* coldCodeBlock; - void* roDataBlock; -}; - -struct allocGCInfoDetails -{ - size_t size; - void* retval; -}; - -struct Agnostic_AllocGCInfo -{ - DWORDLONG size; - DWORD retval_offset; -}; - -struct Agnostic_AllocMemDetails -{ - DWORD hotCodeSize; - DWORD coldCodeSize; - DWORD roDataSize; - DWORD xcptnsCount; - DWORD hotCodeBlock_offset; - DWORD coldCodeBlock_offset; - DWORD roDataBlock_offset; - DWORDLONG hotCodeBlock; - DWORDLONG coldCodeBlock; - DWORDLONG roDataBlock; -}; - -struct Agnostic_AllocUnwindInfo -{ - DWORDLONG pHotCode; - DWORDLONG pColdCode; - DWORD startOffset; - DWORD endOffset; - DWORD unwindSize; - DWORD pUnwindBlock_index; - DWORD funcKind; -}; - -struct Agnostic_CompileMethodResults -{ - DWORDLONG nativeEntry; - DWORD nativeSizeOfCode; - DWORD CorJitResult; -}; - -struct Agnostic_ReportInliningDecision -{ - DWORDLONG inlinerHnd; - DWORDLONG inlineeHnd; - DWORD inlineResult; - DWORD reason_offset; -}; - -struct Agnostic_ReportTailCallDecision -{ - DWORDLONG callerHnd; - DWORDLONG calleeHnd; - DWORD fIsTailPrefix; - DWORD tailCallResult; - DWORD reason_index; -}; - -struct Agnostic_ReserveUnwindInfo -{ - DWORD isFunclet; - DWORD isColdCode; - DWORD unwindSize; -}; - -struct Agnostic_SetBoundaries -{ - DWORDLONG ftn; - DWORD cMap; - DWORD pMap_offset; -}; - -struct Agnostic_SetVars -{ - DWORDLONG ftn; - DWORD cVars; - DWORD vars_offset; -}; - -struct Agnostic_SetPatchpointInfo -{ - DWORD index; -}; - -struct Agnostic_RecordCallSite -{ - Agnostic_CORINFO_SIG_INFO callSig; - DWORDLONG methodHandle; -}; - -struct Agnostic_PrintResult -{ - // Required size of a buffer to contain everything including null terminator. - // UINT_MAX if it was not determined during recording. - DWORD requiredBufferSize; - // Index of stored string buffer. We always store this without null terminator. - // May be UINT_MAX if no buffer was stored. - DWORD stringBuffer; - // The size of the buffer stored by stringBuffer. - DWORD stringBufferSize; -}; - -#pragma pack(pop) - -#endif // _Agnostic diff --git a/src/coreclr/tools/superpmi/superpmi-shared/asmdumper.cpp b/src/coreclr/tools/superpmi/superpmi-shared/asmdumper.cpp deleted file mode 100644 index 471033ad2d3906..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/asmdumper.cpp +++ /dev/null @@ -1,109 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "standardpch.h" -#include "asmdumper.h" - -void ASMDumper::DumpToFile(HANDLE hFile, MethodContext* mc, CompileResult* cr) -{ - CORINFO_METHOD_INFO info; - unsigned flags = 0; - CORINFO_OS os = CORINFO_WINNT; - mc->repCompileMethod(&info, &flags, &os); - -#define bufflen 4096 - DWORD bytesWritten; - char buff[bufflen]; - - int buff_offset = 0; - ZeroMemory(buff, bufflen * sizeof(char)); - buff_offset += sprintf_s(&buff[buff_offset], bufflen - buff_offset, - ";;Generated from SuperPMI on original input '%s'", cr->repProcessName()); - - buff_offset += sprintf_s(&buff[buff_offset], bufflen - buff_offset, "\r\n Method Name \"%s\"", - getMethodName(mc, info.ftn).c_str()); - WriteFile(hFile, buff, buff_offset * sizeof(char), &bytesWritten, nullptr); - - ULONG hotCodeSize; - ULONG coldCodeSize; - ULONG roDataSize; - ULONG xcptnsCount; - unsigned char* hotCodeBlock; - unsigned char* coldCodeBlock; - unsigned char* roDataBlock; - void* orig_hotCodeBlock; - void* orig_coldCodeBlock; - void* orig_roDataBlock; - - cr->repAllocMem(&hotCodeSize, &coldCodeSize, &roDataSize, &xcptnsCount, &hotCodeBlock, &coldCodeBlock, - &roDataBlock, &orig_hotCodeBlock, &orig_coldCodeBlock, &orig_roDataBlock); - - RelocContext rc; - - rc.mc = mc; - rc.hotCodeAddress = (size_t)hotCodeBlock; - rc.hotCodeSize = hotCodeSize; - rc.coldCodeAddress = (size_t)coldCodeBlock; - rc.coldCodeSize = coldCodeSize; - rc.roDataAddress = (size_t)roDataBlock; - rc.roDataSize1 = roDataSize; - rc.roDataSize2 = 0; - rc.originalHotCodeAddress = (size_t)orig_hotCodeBlock; - rc.originalColdCodeAddress = (size_t)orig_coldCodeBlock; - rc.originalRoDataAddress1 = (size_t)orig_roDataBlock; - rc.originalRoDataAddress2 = 0; - - cr->applyRelocs(&rc, hotCodeBlock, hotCodeSize, orig_hotCodeBlock); - cr->applyRelocs(&rc, coldCodeBlock, coldCodeSize, orig_coldCodeBlock); - cr->applyRelocs(&rc, roDataBlock, roDataSize, orig_roDataBlock); - -#ifdef USE_MSVCDIS - -#ifdef TARGET_AMD64 - DIS* disasm = DIS::PdisNew(DIS::distX8664); -#elif TARGET_X86 - DIS* disasm = DIS::PdisNew(DIS::distX86); -#endif - size_t offset = 0; - while (offset < hotCodeSize) - { - buff_offset = 0; - ZeroMemory(buff, bufflen * sizeof(char)); - - DIS::INSTRUCTION instr; - DIS::OPERAND ops[3]; - - size_t instrSize = disasm->CbDisassemble(0, (void*)(hotCodeBlock + offset), 15); - if (instrSize == 0) - { - LogWarning("Zero sized instruction"); - break; - } - disasm->FDecode(&instr, ops, 3); - - WCHAR instrMnemonic[64]; // I never know how much to allocate... - disasm->CchFormatInstr(instrMnemonic, 64); - std::string instrMnemonicUtf8 = ConvertToUtf8(instrMnemonic); - buff_offset += sprintf_s(&buff[buff_offset], bufflen - buff_offset, "\r\n%p %s", - (void*)((size_t)orig_hotCodeBlock + offset), instrMnemonicUtf8.c_str()); - buff_offset += sprintf_s(&buff[buff_offset], bufflen - buff_offset, " ; "); - for (unsigned int i = 0; i < instrSize; i++) - buff_offset += - sprintf_s(&buff[buff_offset], bufflen - buff_offset, "%02x ", *((BYTE*)(hotCodeBlock + offset + i))); - WriteFile(hFile, buff, buff_offset * sizeof(char), &bytesWritten, nullptr); - offset += instrSize; - } - - delete disasm; - -#else // !USE_MSVCDIS - - buff_offset = 0; - ZeroMemory(buff, bufflen * sizeof(char)); - buff_offset += sprintf_s(&buff[buff_offset], bufflen - buff_offset, ";; No disassembler available"); - WriteFile(hFile, buff, buff_offset * sizeof(char), &bytesWritten, nullptr); - -#endif // !USE_MSVCDIS - - FlushFileBuffers(hFile); -} diff --git a/src/coreclr/tools/superpmi/superpmi-shared/asmdumper.h b/src/coreclr/tools/superpmi/superpmi-shared/asmdumper.h deleted file mode 100644 index 90af3ef16febfc..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/asmdumper.h +++ /dev/null @@ -1,17 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#ifndef _ASMDumper -#define _ASMDumper - -#include "methodcontext.h" -#include "compileresult.h" -#include "spmiutil.h" - -class ASMDumper -{ -public: - static void DumpToFile(HANDLE hFile, MethodContext* mc, CompileResult* cr); -}; - -#endif diff --git a/src/coreclr/tools/superpmi/superpmi-shared/callutils.cpp b/src/coreclr/tools/superpmi/superpmi-shared/callutils.cpp deleted file mode 100644 index c35481cff0af6b..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/callutils.cpp +++ /dev/null @@ -1,348 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// CallUtils.cpp - Utility code for analyzing and working with managed calls -//---------------------------------------------------------- - -#include "standardpch.h" -#include "callutils.h" -#include "typeutils.h" -#include "errorhandling.h" -#include "logging.h" -#include "spmiutil.h" - -// String representations of the JIT helper functions -const char* kHelperName[CORINFO_HELP_COUNT] = { -#define JITHELPER(code, pfnHelper, binderId) #code, -#define DYNAMICJITHELPER(code, pfnHelper, binderId) #code, -#include "jithelpers.h" -}; - -//------------------------------------------------------------------------------------------------- - -// -// Provides information about the target of an outgoing call, based on where it was emitted in the -// generated code stream. -// -// Primarily, this returns what the destination of the call is (e.g. a method, a helper function), but this -// can also provide: -// -// - A symbolic name for the call target (i.e. the function name). -// - For non-helper methods, the method signature of the call target. -// -// Arguments: -// mc - The method context of the method containing this call site. -// cr - The compile result for the method containing this call site. -// callInstrOffset - The native offset of the call site in the generated code stream. -// outSigInfo - [out] The signature of the outgoing call. Optional (pass nullptr if unwanted). -// outCallTargetSymbol - [out] A string representation of the outgoing call. Optional (pass nullptr if -// unwanted). -// -// Return Value: -// What type of call the outgoing call is. -// -// Notes: -// - This depends on the JIT having registered the call site with the EE through recordCallSite. If the -// JIT didn't do this, GetDirectCallSite can obtain most of the same information for direct calls. -// - If the call site is for a helper method, then outSigInfo will not be changed, since helper calls -// have no signature information. -// - If you pass in a valid pointer for outCallTargetSymbol, this function will allocate memory for it -// if it is able to understand that call (i.e. if it does not return CallType_Unknown). You, the caller, -// are responsible for freeing the memory (with delete[]). -// -CallType CallUtils::GetRecordedCallSiteInfo(MethodContext* mc, - CompileResult* cr, - unsigned int callInstrOffset, - /*out*/ CORINFO_SIG_INFO* outSigInfo, - /*out*/ char** outCallTargetSymbol) -{ - AssertCodeMsg(mc != nullptr, EXCEPTIONCODE_CALLUTILS, - "Null method context passed into GetCallTargetInfo for call at offset %x.", callInstrOffset); - AssertCodeMsg(cr != nullptr, EXCEPTIONCODE_CALLUTILS, - "Null compile result passed into GetCallTargetInfo for call at offset %x.", callInstrOffset); - - CallType targetType = CallType_Unknown; - - CORINFO_SIG_INFO callSig; - bool recordedCallSig = cr->fndRecordCallSiteSigInfo(callInstrOffset, &callSig); - - CORINFO_METHOD_HANDLE methodHandle = nullptr; - bool recordedMethodHandle = cr->fndRecordCallSiteMethodHandle(callInstrOffset, &methodHandle); - - if (recordedCallSig) - { - if (outSigInfo != nullptr) - *outSigInfo = callSig; - - if (outCallTargetSymbol != nullptr) - *outCallTargetSymbol = (char*)GetMethodFullName(mc, methodHandle, callSig); - - targetType = CallType_UserFunction; - } - else if (recordedMethodHandle) - { - CorInfoHelpFunc helperNum = CallUtils::GetHelperNum(methodHandle); - AssertCodeMsg(helperNum != CORINFO_HELP_UNDEF, EXCEPTIONCODE_CALLUTILS, - "Unknown call at offset %x with method handle %016llX.", callInstrOffset, methodHandle); - - size_t length = strlen(kHelperName[helperNum]) + 1; - *outCallTargetSymbol = new char[length]; - strcpy_s(*outCallTargetSymbol, length, kHelperName[helperNum]); - - targetType = CallType_Helper; - } - else - { - LogWarning("Call site at offset %x was not recorded via recordCallSite.", callInstrOffset); - } - - return targetType; -} - -// -// Provides information about the target of an outgoing call, based on the outgoing call's target address. -// -// Primarily, this returns what the destination of the call is (e.g. a method, a helper function), but this -// can also provide: -// -// - A symbolic name for the call target (i.e. the function name). -// - For certain types of managed methods, the method signature of the call target. -// -// Arguments: -// mc - The method context of the method containing this outgoing call. -// callTarget - The target address of the outgoing call. -// outSigInfo - [out] The signature of the outgoing call. Optional (pass nullptr if unwanted). -// outCallTargetSymbol - [out] A string representation of the outgoing call. Optional (pass nullptr if -// unwanted). -// -// Return Value: -// What type of call the outgoing call is. -// -// Assumptions: -// The given method address does not point to a jump stub. -// -// Notes: -// - This only works for direct calls that have a static target address. -// - If you pass in a valid pointer for outCallTargetSymbol, this function will allocate memory for it -// if it is able to understand that call (i.e. if it does not return CallType_Unknown). You, the caller, -// are responsible for freeing the memory (with delete[]). -// - -CallType CallUtils::GetDirectCallSiteInfo(MethodContext* mc, - void* callTarget, - /*out*/ CORINFO_SIG_INFO* outSigInfo, - /*out*/ char** outCallTargetSymbol) -{ - AssertCodeMsg(mc != nullptr, EXCEPTIONCODE_CALLUTILS, - "Null method context passed into GetCallTargetInfo for call to target %016llX.", callTarget); - - CallType targetType = CallType_Unknown; - DLD functionEntryPoint; - CORINFO_METHOD_HANDLE methodHandle; - - // Try to first obtain a method handle associated with this call target - functionEntryPoint.A = CastPointer(callTarget); - functionEntryPoint.B = 0; // TODO-Cleanup: we should be more conscious of this... - - if (mc->fndGetFunctionEntryPoint(functionEntryPoint, &methodHandle)) - { - // Now try to obtain the call info associated with this method handle - - struct Param - { - MethodContext* mc; - CORINFO_SIG_INFO* outSigInfo; - char** outCallTargetSymbol; - CallType* pTargetType; - CORINFO_METHOD_HANDLE* pMethodHandle; - } param; - param.mc = mc; - param.outSigInfo = outSigInfo; - param.outCallTargetSymbol = outCallTargetSymbol; - param.pTargetType = &targetType; - param.pMethodHandle = &methodHandle; - - PAL_TRY(Param*, pParam, ¶m) - { - CORINFO_CALL_INFO callInfo; - - pParam->mc->repGetCallInfoFromMethodHandle(*pParam->pMethodHandle, &callInfo); - - if (pParam->outSigInfo != nullptr) - *pParam->outSigInfo = callInfo.sig; - - if (pParam->outCallTargetSymbol != nullptr) - *pParam->outCallTargetSymbol = - (char*)GetMethodFullName(pParam->mc, *pParam->pMethodHandle, callInfo.sig); - - *pParam->pTargetType = CallType_UserFunction; - } - PAL_EXCEPT_FILTER(FilterSuperPMIExceptions_CatchMC) - { - LogWarning("Didn't find call info for method handle %016llX (call target: %016llX)", methodHandle, - callTarget); - } - PAL_ENDTRY - } - else - { - // No method handle associated with this target, so check if it's a helper - CorInfoHelpFunc helperNum; - - if (mc->fndGetHelperFtn(callTarget, &helperNum)) - { - if (outCallTargetSymbol != nullptr) - { - size_t length = strlen(kHelperName[helperNum]) + 1; - *outCallTargetSymbol = new char[length]; - strcpy_s(*outCallTargetSymbol, length, kHelperName[helperNum]); - } - - targetType = CallType_Helper; - } - else - { - LogWarning("Call to target %016llX has no method handle and is not a helper call.", callTarget); - } - } - - return targetType; -} - -//------------------------------------------------------------------------------------------------- -// Utilty code that was stolen from various sections of the JIT codebase and tweaked to go through -// SuperPMI's method context replaying instead of directly making calls into the JIT/EE interface. -//------------------------------------------------------------------------------------------------- - -// Originally from src/jit/eeinterface.cpp -// If `ignoreMethodName` is `true`, we construct the function signature with a dummy method name that will be the -// same for all methods. -const char* CallUtils::GetMethodFullName(MethodContext* mc, CORINFO_METHOD_HANDLE hnd, CORINFO_SIG_INFO sig, bool ignoreMethodName /* = false */) -{ - const char* returnType = NULL; - - if ((GetHelperNum(hnd) != CORINFO_HELP_UNDEF)) - { - return kHelperName[GetHelperNum(hnd)]; - } - - std::string className = "CLASS"; - std::string methodName = "METHOD"; - - if (!ignoreMethodName) - { - className = getClassName(mc, mc->repGetMethodClass(hnd)); - methodName = getMethodName(mc, hnd); - } - - // Class name and colon - size_t length = className.size() + 1; - unsigned i; - - /* Generating the full signature is a two-pass process. First we have to walk - the components in order to assess the total size, then we allocate the buffer - and copy the elements into it. - */ - - /* Right now there is a race-condition in the EE, className can be NULL */ - - /* initialize length with length of className and '.' */ - - /* add length of methodName and opening bracket */ - length += methodName.size() + 1; - - CORINFO_ARG_LIST_HANDLE argList = sig.args; - - for (i = 0; i < sig.numArgs; i++) - { - // Tweaked to use EE types instead of JIT-specific types - CORINFO_CLASS_HANDLE typeHandle; - DWORD exception; - CorInfoType type = strip(mc->repGetArgType(&sig, argList, &typeHandle, &exception)); - - length += strlen(TypeUtils::GetCorInfoTypeName(type)); - argList = mc->repGetArgNext(argList); - } - - /* add ',' if there is more than one argument */ - - if (sig.numArgs > 1) - length += (sig.numArgs - 1); - - // Tweaked to use EE types instead of JIT-specific types - if (sig.retType != CORINFO_TYPE_VOID) - { - returnType = TypeUtils::GetCorInfoTypeName(sig.retType); - length += strlen(returnType) + 1; // don't forget the delimiter ':' - } - - // Does it have a 'this' pointer? Don't count explicit this, which has the this pointer type as the first element of - // the arg type list - if (sig.hasThis() && !sig.hasExplicitThis()) - { - // Tweaked to avoid using CRT assertions - Assert(strlen(":this") == 5); - length += 5; - } - - /* add closing bracket and null terminator */ - - length += 2; - - char* retName = new char[length]; // Tweaked to use "new" instead of compGetMem - - /* Now generate the full signature string in the allocated buffer */ - - strcpy_s(retName, length, className.c_str()); - strcat_s(retName, length, ":"); - - strcat_s(retName, length, methodName.c_str()); - - // append the signature - strcat_s(retName, length, "("); - - argList = sig.args; - - for (i = 0; i < sig.numArgs; i++) - { - // Tweaked to use EE types instead of JIT-specific types - CORINFO_CLASS_HANDLE typeHandle; - DWORD exception; - CorInfoType type = strip(mc->repGetArgType(&sig, argList, &typeHandle, &exception)); - strcat_s(retName, length, TypeUtils::GetCorInfoTypeName(type)); - - argList = mc->repGetArgNext(argList); - if (i + 1 < sig.numArgs) - strcat_s(retName, length, ","); - } - - strcat_s(retName, length, ")"); - - if (returnType) - { - strcat_s(retName, length, ":"); - strcat_s(retName, length, returnType); - } - - // Does it have a 'this' pointer? Don't count explicit this, which has the this pointer type as the first element of - // the arg type list - if (sig.hasThis() && !sig.hasExplicitThis()) - { - strcat_s(retName, length, ":this"); - } - - // Tweaked to avoid using CRT assertions - Assert(strlen(retName) == (length - 1)); - - return (retName); -} - -// Originally from jit/compiler.hpp -inline CorInfoHelpFunc CallUtils::GetHelperNum(CORINFO_METHOD_HANDLE method) -{ - // Helpers are marked by the fact that they are odd numbers - if (!(((size_t)method) & 1)) - return (CORINFO_HELP_UNDEF); - return ((CorInfoHelpFunc)(((size_t)method) >> 2)); -} diff --git a/src/coreclr/tools/superpmi/superpmi-shared/callutils.h b/src/coreclr/tools/superpmi/superpmi-shared/callutils.h deleted file mode 100644 index 7d29de3d0b789f..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/callutils.h +++ /dev/null @@ -1,35 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// CallUtils.h - Utility code for analyzing and working with managed calls -//---------------------------------------------------------- -#ifndef _CallUtils -#define _CallUtils - -#include "methodcontext.h" - -enum CallType -{ - CallType_UserFunction = 0, - CallType_Helper, - CallType_Unknown = -1 -}; - -class CallUtils -{ -public: - static CallType GetRecordedCallSiteInfo(MethodContext* mc, - CompileResult* cr, - unsigned int callInstrOffset, - /*out*/ CORINFO_SIG_INFO* outSigInfo, - /*out*/ char** outCallTargetSymbol); - static CallType GetDirectCallSiteInfo(MethodContext* mc, - void* callTarget, - /*out*/ CORINFO_SIG_INFO* outSigInfo, - /*out*/ char** outCallTargetSymbol); - static CorInfoHelpFunc GetHelperNum(CORINFO_METHOD_HANDLE method); - static const char* GetMethodFullName(MethodContext* mc, CORINFO_METHOD_HANDLE hnd, CORINFO_SIG_INFO sig, bool ignoreMethodName = false); -}; - -#endif diff --git a/src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp b/src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp deleted file mode 100644 index b4630296e7b81f..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/compileresult.cpp +++ /dev/null @@ -1,1358 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// CompileResult.cpp - CompileResult contains the stuff generated by a compilation -//---------------------------------------------------------- - -#include "standardpch.h" -#include "compileresult.h" -#include "methodcontext.h" -#include "spmirecordhelper.h" -#include "spmidumphelper.h" -#include "spmiutil.h" - -CompileResult::CompileResult() -{ -#define LWM(map, key, value) map = nullptr; -#include "crlwmlist.h" - - // Not persisted to disk. though should it be? - CallTargetTypes = new LightWeightMap(); - - allocMemDets.hotCodeSize = 0; - allocMemDets.coldCodeSize = 0; - allocMemDets.roDataSize = 0; - allocMemDets.xcptnsCount = 0; - allocMemDets.hotCodeBlock = nullptr; - allocMemDets.coldCodeBlock = nullptr; - allocMemDets.roDataBlock = nullptr; - - allocGCInfoDets.retval = nullptr; - allocGCInfoDets.size = 0; - - MethodFullName = nullptr; - TieringName = nullptr; - memoryTracker = nullptr; - -#define JITMETADATAINFO(name, type, flags) -#define JITMETADATAMETRIC(name, type, flags) name = 0; -#include "jitmetadatalist.h" -} - -CompileResult::~CompileResult() -{ -#define LWM(map, key, value) \ - delete map; -#include "crlwmlist.h" - - delete CallTargetTypes; - delete memoryTracker; -} - -// Is the CompileResult empty? Define this as whether all the maps that store information given by the JIT are empty. -// This is useful when determining if a function won't apply after a "mcs -removeDump -thin" operation has been run. -bool CompileResult::IsEmpty() -{ - bool isEmpty = true; - -#define LWM(map, key, value) \ - if (map != nullptr) \ - isEmpty = false; -#include "crlwmlist.h" - - return isEmpty; -} - -MemoryTracker* CompileResult::getOrCreateMemoryTracker() -{ - if (memoryTracker == nullptr) - memoryTracker = new MemoryTracker(); - - return memoryTracker; -} - -// Allocate memory associated with this CompileResult. Keep track of it in a list so we can free it all later. -void* CompileResult::allocateMemory(size_t sizeInBytes) -{ - return getOrCreateMemoryTracker()->allocate(sizeInBytes); -} - -void CompileResult::recAssert(const char* assertText) -{ - if (AssertLog == nullptr) - AssertLog = new DenseLightWeightMap(); - - AssertLog->Append(AssertLog->AddBuffer((const unsigned char*)assertText, (DWORD)strlen(assertText) + 1)); -} -void CompileResult::dmpAssertLog(DWORD key, DWORD value) -{ - const char* assert = (const char*)AssertLog->GetBuffer(value); - printf("AssertLog key %u, value '%s'", key, assert); - AssertLog->Unlock(); -} -const char* CompileResult::repAssert() -{ - if ((AssertLog == nullptr) || (AssertLog->GetCount() == 0)) - return nullptr; - return (const char*)AssertLog->GetBuffer(AssertLog->Get((DWORD)0)); -} - -void CompileResult::AddCall(const char* name) -{ - if (CallLog == nullptr) - CallLog = new DenseLightWeightMap(); - // if(name[0] != '+') - // CallLog->Append(CallLog->AddBuffer((const unsigned char *)name, (DWORD)strlen(name)+1)); -} -unsigned int CompileResult::CallLog_GetCount() -{ - return CallLog->GetCount(); -} - -bool CompileResult::CallLog_Contains(const char* str) -{ - return (CallLog->Contains((unsigned char*)str, (unsigned int)strlen(str)) > 0); -} -void CompileResult::dmpCallLog(DWORD key, DWORD value) -{ - const char* temp = (const char*)CallLog->GetBuffer(value); - printf("CallLog %u '%s'", key, temp); - CallLog->Unlock(); -} - -void CompileResult::dumpToConsole() -{ - printf("***************************************** CompileResult\n"); - -#define LWM(map, key, value) dumpLWM(this, map) -#define DENSELWM(map, value) dumpLWMDense(this, map) -#include "crlwmlist.h" - - printf("-----------------------------------------\n"); -} - -// Note - EE allocates these blocks (and the exception blocks) in a single linear region. -// Note - EE assures that RoBlock is 8 byte aligned -void CompileResult::recAllocMem(ULONG hotCodeSize, - ULONG coldCodeSize, - ULONG roDataSize, - ULONG xcptnsCount, - void* hotCodeBlock, - void* coldCodeBlock, - void* roDataBlock) -{ - // Grab the values, so we can scrape the real answers in the capture method - allocMemDets.hotCodeSize = hotCodeSize; - allocMemDets.coldCodeSize = coldCodeSize; - allocMemDets.roDataSize = roDataSize; - allocMemDets.xcptnsCount = xcptnsCount; - allocMemDets.hotCodeBlock = hotCodeBlock; - allocMemDets.coldCodeBlock = coldCodeBlock; - allocMemDets.roDataBlock = roDataBlock; -} -void CompileResult::recAllocMemCapture() -{ - if (AllocMem == nullptr) - AllocMem = new LightWeightMap(); - - Agnostic_AllocMemDetails value; - - value.hotCodeSize = (DWORD)allocMemDets.hotCodeSize; - value.coldCodeSize = (DWORD)allocMemDets.coldCodeSize; - value.roDataSize = (DWORD)allocMemDets.roDataSize; - value.xcptnsCount = (DWORD)allocMemDets.xcptnsCount; - value.hotCodeBlock_offset = - (DWORD)AllocMem->AddBuffer((const unsigned char*)allocMemDets.hotCodeBlock, allocMemDets.hotCodeSize); - value.coldCodeBlock_offset = - (DWORD)AllocMem->AddBuffer((const unsigned char*)allocMemDets.coldCodeBlock, allocMemDets.coldCodeSize); - value.roDataBlock_offset = - (DWORD)AllocMem->AddBuffer((const unsigned char*)allocMemDets.roDataBlock, allocMemDets.roDataSize); - value.hotCodeBlock = CastPointer(allocMemDets.hotCodeBlock); - value.coldCodeBlock = CastPointer(allocMemDets.coldCodeBlock); - value.roDataBlock = CastPointer(allocMemDets.roDataBlock); - - AllocMem->Add(0, value); -} - -void CompileResult::dmpAllocMem(DWORD key, const Agnostic_AllocMemDetails& value) -{ - printf("AllocMem key 0, value hotCodeSize-%u coldCodeSize-%u roDataSize-%u xcptnsCount-%u " - "hotCodeBlock_offset-%u coldCodeBlock_offset-%u roDataBlock_offset-%u hotCodeBlock-%016" PRIX64 " " - "coldCodeBlock-%016" PRIX64 " roDataBlock-%016" PRIX64, - value.hotCodeSize, value.coldCodeSize, value.roDataSize, value.xcptnsCount, - value.hotCodeBlock_offset, value.coldCodeBlock_offset, value.roDataBlock_offset, value.hotCodeBlock, - value.coldCodeBlock, value.roDataBlock); -} - -// We can't allocate memory at the same address used during recording, so we pass back code/data block pointers -// that point into the AllocMem LightWeightMap, but also return what the original addresses were during recording. -void CompileResult::repAllocMem(ULONG* hotCodeSize, - ULONG* coldCodeSize, - ULONG* roDataSize, - ULONG* xcptnsCount, - unsigned char** hotCodeBlock, - unsigned char** coldCodeBlock, - unsigned char** roDataBlock, - void** orig_hotCodeBlock, - void** orig_coldCodeBlock, - void** orig_roDataBlock) -{ - Agnostic_AllocMemDetails value; - - value = AllocMem->Get(0); - - *hotCodeSize = (ULONG)value.hotCodeSize; - *coldCodeSize = (ULONG)value.coldCodeSize; - *roDataSize = (ULONG)value.roDataSize; - *xcptnsCount = (ULONG)value.xcptnsCount; - - if (*hotCodeSize > 0) - *hotCodeBlock = AllocMem->GetBuffer(value.hotCodeBlock_offset); - else - *hotCodeBlock = nullptr; - - if (*coldCodeSize > 0) - *coldCodeBlock = AllocMem->GetBuffer(value.coldCodeBlock_offset); - else - *coldCodeBlock = nullptr; - - if (*roDataSize > 0) - *roDataBlock = AllocMem->GetBuffer(value.roDataBlock_offset); - else - *roDataBlock = nullptr; - - *orig_hotCodeBlock = (void*)value.hotCodeBlock; - *orig_coldCodeBlock = (void*)value.coldCodeBlock; - *orig_roDataBlock = (void*)value.roDataBlock; -} - -// Note - Ownership of pMap is transferred with this call. In replay icorjitinfo we should free it. -void CompileResult::recSetBoundaries(CORINFO_METHOD_HANDLE ftn, ULONG32 cMap, ICorDebugInfo::OffsetMapping* pMap) -{ - if (SetBoundaries == nullptr) - SetBoundaries = new LightWeightMap(); - - Agnostic_SetBoundaries value; - - value.ftn = CastHandle(ftn); - value.cMap = (DWORD)cMap; - value.pMap_offset = - (DWORD)SetBoundaries->AddBuffer((const unsigned char*)pMap, sizeof(ICorDebugInfo::OffsetMapping) * cMap); - - SetBoundaries->Add(0, value); -} -void CompileResult::dmpSetBoundaries(DWORD key, const Agnostic_SetBoundaries& value) -{ - ICorDebugInfo::OffsetMapping* om = (ICorDebugInfo::OffsetMapping*)SetBoundaries->GetBuffer(value.pMap_offset); - printf("SetBoundaries key 0, value ftn-%016" PRIX64 " cMap-%u %u{", value.ftn, value.cMap, value.pMap_offset); - for (unsigned int i = 0; i < value.cMap; i++) - { - if (i != 0) - printf(", "); - printf("%u %u %u", om[i].ilOffset, om[i].nativeOffset, om[i].source); - } - printf("}"); - SetBoundaries->Unlock(); -} -bool CompileResult::repSetBoundaries(CORINFO_METHOD_HANDLE* ftn, ULONG32* cMap, ICorDebugInfo::OffsetMapping** pMap) -{ - if ((SetBoundaries == nullptr) || (SetBoundaries->GetCount() == 0)) - { - *ftn = (CORINFO_METHOD_HANDLE)-1; - *cMap = -1; - *pMap = nullptr; - return false; - } - Agnostic_SetBoundaries value; - - value = SetBoundaries->Get(0); - - *ftn = (CORINFO_METHOD_HANDLE)value.ftn; - *cMap = (ULONG32)value.cMap; - *pMap = (ICorDebugInfo::OffsetMapping*)SetBoundaries->GetBuffer(value.pMap_offset); - return true; -} - -// Note - Ownership of vars is transferred with this call. In replay icorjitinfo we should free it. -void CompileResult::recSetVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo* vars) -{ - if (SetVars == nullptr) - SetVars = new LightWeightMap(); - - Agnostic_SetVars value; - - value.ftn = CastHandle(ftn); - value.cVars = (DWORD)cVars; - value.vars_offset = (DWORD)SetVars->AddBuffer((const unsigned char*)vars, - sizeof(ICorDebugInfo::NativeVarInfo) * - cVars); // not deep enough.. vlt memory is pointer sized. - - SetVars->Add(0, value); -} -void CompileResult::dmpSetVars(DWORD key, const Agnostic_SetVars& value) -{ - ICorDebugInfo::NativeVarInfo* om = (ICorDebugInfo::NativeVarInfo*)SetVars->GetBuffer(value.vars_offset); - printf("SetVars key %u, value ftn-%016" PRIX64 " cVars-%u %u{", key, value.ftn, value.cVars, value.vars_offset); - for (unsigned int i = 0; i < value.cVars; i++) - { - if (i != 0) - printf(", "); - printf("so-%u eo-%u var-%u", om[i].startOffset, om[i].endOffset, om[i].varNumber); - } - printf("}"); - SetVars->Unlock(); -} -bool CompileResult::repSetVars(CORINFO_METHOD_HANDLE* ftn, ULONG32* cVars, ICorDebugInfo::NativeVarInfo** vars) -{ - if ((SetVars == nullptr) || (SetVars->GetCount() == 0)) - { - *ftn = (CORINFO_METHOD_HANDLE)-1; - *cVars = -1; - *vars = nullptr; - return false; - } - - Agnostic_SetVars value; - - value = SetVars->Get(0); - - *ftn = (CORINFO_METHOD_HANDLE)value.ftn; - *cVars = (ULONG32)value.cVars; - *vars = (ICorDebugInfo::NativeVarInfo*)SetVars->GetBuffer(value.vars_offset); - - return true; -} - -// Note - Ownership of patchpointInfo is transferred with this call. In replay icorjitinfo we should free it. -void CompileResult::recSetPatchpointInfo(PatchpointInfo* patchpointInfo) -{ - if (SetPatchpointInfo == nullptr) - SetPatchpointInfo = new LightWeightMap(); - - Agnostic_SetPatchpointInfo value; - value.index = (DWORD)SetPatchpointInfo->AddBuffer((const unsigned char*) patchpointInfo, patchpointInfo->PatchpointInfoSize()); - SetPatchpointInfo->Add(0, value); -} -void CompileResult::dmpSetPatchpointInfo(DWORD key, const Agnostic_SetPatchpointInfo& value) -{ - PatchpointInfo* patchpointInfo = (PatchpointInfo*)SetPatchpointInfo->GetBuffer(value.index); - printf("SetPatchpointInfo key %u, index %u{", key, value.index); - // todo -- dump contents - printf("}"); - SetPatchpointInfo->Unlock(); -} -bool CompileResult::repSetPatchpointInfo(PatchpointInfo** patchpointInfo) -{ - if ((SetPatchpointInfo == nullptr) || (SetPatchpointInfo->GetCount() == 0)) - { - *patchpointInfo = nullptr; - return false; - } - - Agnostic_SetPatchpointInfo value; - value = SetPatchpointInfo->Get(0); - *patchpointInfo = (PatchpointInfo*)SetPatchpointInfo->GetBuffer(value.index); - return true; -} - -void CompileResult::recAllocGCInfo(size_t size, void* retval) -{ - allocGCInfoDets.size = size; - allocGCInfoDets.retval = retval; -} -void CompileResult::recAllocGCInfoCapture() -{ - if (AllocGCInfo == nullptr) - AllocGCInfo = new LightWeightMap(); - - Agnostic_AllocGCInfo value; - - value.size = allocGCInfoDets.size; - value.retval_offset = - (DWORD)AllocGCInfo->AddBuffer((const unsigned char*)allocGCInfoDets.retval, (DWORD)allocGCInfoDets.size); - - AllocGCInfo->Add(0, value); -} -void CompileResult::dmpAllocGCInfo(DWORD key, const Agnostic_AllocGCInfo& value) -{ - const unsigned char* buff = AllocGCInfo->GetBuffer(value.retval_offset); - printf("AllocGCInfo key 0, "); - printf("sz-%" PRIu64 " %p{ ", value.size, buff); - for (unsigned int i = 0; i < value.size; i++) - printf("%02X ", *(buff + i)); - printf("}"); - AllocGCInfo->Unlock(); -} -void CompileResult::repAllocGCInfo(size_t* size, void** retval) -{ - Agnostic_AllocGCInfo value; - - value = AllocGCInfo->Get(0); - - *size = (size_t)value.size; - if (*size > 0) - *retval = (void*)AllocGCInfo->GetBuffer(value.retval_offset); -} - -void CompileResult::recCompileMethod(uint8_t** nativeEntry, uint32_t* nativeSizeOfCode, CorJitResult result) -{ - if (CompileMethod == nullptr) - CompileMethod = new LightWeightMap(); - - Agnostic_CompileMethodResults value; - value.nativeEntry = CastPointer(*nativeEntry); - value.nativeSizeOfCode = (DWORD)*nativeSizeOfCode; - value.CorJitResult = (DWORD)result; - - CompileMethod->Add(0, value); -} -void CompileResult::dmpCompileMethod(DWORD key, const Agnostic_CompileMethodResults& value) -{ - printf("CompileMethod key %u, value nativeEntry-%016" PRIX64 " nativeSizeOfCode-%u CorJitResult-%u", key, - value.nativeEntry, value.nativeSizeOfCode, value.CorJitResult); -} -void CompileResult::repCompileMethod(BYTE** nativeEntry, ULONG* nativeSizeOfCode, CorJitResult* result) -{ - Agnostic_CompileMethodResults value; - value = CompileMethod->Get(0); - *nativeEntry = (BYTE*)value.nativeEntry; - *nativeSizeOfCode = (ULONG)value.nativeSizeOfCode; - *result = (CorJitResult)value.CorJitResult; -} - -void CompileResult::recMessageLog(const char* fmt, ...) -{ - // TODO-Cleanup: ??? - return; - if (MessageLog == nullptr) - MessageLog = new DenseLightWeightMap(); - - va_list args; - - // retrieve the variable arguments - va_start(args, fmt); - - size_t len = _vscprintf(fmt, args) + 1; // space for the terminator - - unsigned char* messageLogBuffer = new unsigned char[len]; - vsprintf_s((char*)messageLogBuffer, len, fmt, args); - messageLogBuffer[len - 1] = 0; - MessageLog->Append(MessageLog->AddBuffer(messageLogBuffer, (DWORD)len)); - delete[] messageLogBuffer; -} -void CompileResult::dmpMessageLog(DWORD key, DWORD value) -{ - printf("MessageLog NYI"); -} - -void CompileResult::recReportInliningDecision(CORINFO_METHOD_HANDLE inlinerHnd, - CORINFO_METHOD_HANDLE inlineeHnd, - CorInfoInline inlineResult, - const char* reason) -{ - if (ReportInliningDecision == nullptr) - ReportInliningDecision = new DenseLightWeightMap(); - - Agnostic_ReportInliningDecision value; - - value.inlinerHnd = CastHandle(inlinerHnd); - value.inlineeHnd = CastHandle(inlineeHnd); - value.inlineResult = (DWORD)inlineResult; - if (reason != nullptr) - value.reason_offset = - (DWORD)ReportInliningDecision->AddBuffer((unsigned char*)reason, (DWORD)strlen(reason) + 1); - else - value.reason_offset = -1; - - ReportInliningDecision->Append(value); -} -void CompileResult::dmpReportInliningDecision(DWORD key, const Agnostic_ReportInliningDecision& value) -{ - const char* reason = (const char*)ReportInliningDecision->GetBuffer(value.reason_offset); - printf("ReportInliningDecision key %u, value inliner-%016" PRIX64 " inlinee-%016" PRIX64 " res-%u reason-'%s'", key, - value.inlinerHnd, value.inlineeHnd, value.inlineResult, reason); - ReportInliningDecision->Unlock(); -} -CorInfoInline CompileResult::repReportInliningDecision(CORINFO_METHOD_HANDLE inlinerHnd, - CORINFO_METHOD_HANDLE inlineeHnd) -{ - CorInfoInline result = INLINE_FAIL; - if (ReportInliningDecision != nullptr) - { - Agnostic_ReportInliningDecision* items = ReportInliningDecision->GetRawItems(); - unsigned int cnt = ReportInliningDecision->GetCount(); - for (unsigned int i = 0; i < cnt; i++) - { - if ((items[i].inlinerHnd == CastHandle(inlinerHnd)) && (items[i].inlineeHnd == CastHandle(inlineeHnd)) && - (items[i].inlineResult == INLINE_PASS)) - result = INLINE_PASS; - } - } - return result; -} - -void CompileResult::recSetEHcount(unsigned cEH) -{ - if (SetEHcount == nullptr) - SetEHcount = new LightWeightMap(); - - SetEHcount->Add((DWORD)0, (DWORD)cEH); -} -void CompileResult::dmpSetEHcount(DWORD key, DWORD value) -{ - printf("SetEHcount key %u, value %u", key, value); -} -ULONG CompileResult::repSetEHcount() -{ - if (SetEHcount == nullptr) - SetEHcount = new LightWeightMap(); - - ULONG ehCount; - int index = SetEHcount->GetIndex(0); - if (index < 0) - ehCount = 0; - else - ehCount = (ULONG)SetEHcount->Get(index); - return ehCount; -} - -void CompileResult::recSetEHinfo(unsigned EHnumber, const CORINFO_EH_CLAUSE* clause) -{ - if (SetEHinfo == nullptr) - SetEHinfo = new LightWeightMap(); - - Agnostic_CORINFO_EH_CLAUSE value; - value.Flags = (DWORD)clause->Flags; - value.TryOffset = (DWORD)clause->TryOffset; - value.TryLength = (DWORD)clause->TryLength; - value.HandlerOffset = (DWORD)clause->HandlerOffset; - value.HandlerLength = (DWORD)clause->HandlerLength; - value.ClassToken = (DWORD)clause->ClassToken; - - SetEHinfo->Add((DWORD)EHnumber, value); -} -void CompileResult::dmpSetEHinfo(DWORD key, const Agnostic_CORINFO_EH_CLAUSE& value) -{ - printf("SetEHinfo key %u, value flg-%u to-%u tl-%u ho-%u hl-%u", key, value.Flags, value.TryOffset, value.TryLength, - value.HandlerOffset, value.HandlerLength); - if ((CORINFO_EH_CLAUSE_FLAGS)value.Flags == CORINFO_EH_CLAUSE_FILTER) - { - printf(" fo-%u", value.ClassToken); // FilterOffset - } - else if ((CORINFO_EH_CLAUSE_FLAGS)value.Flags == CORINFO_EH_CLAUSE_NONE) - { - printf(" cls-%08X", value.ClassToken); - } - // else, no need to print for finally/fault handlers -} -void CompileResult::repSetEHinfo(unsigned EHnumber, - ULONG* flags, - ULONG* tryOffset, - ULONG* tryLength, - ULONG* handlerOffset, - ULONG* handlerLength, - ULONG* classToken) -{ - Agnostic_CORINFO_EH_CLAUSE value; - value = SetEHinfo->Get(EHnumber); - - *flags = (ULONG)value.Flags; - *tryOffset = (ULONG)value.TryOffset; - *tryLength = (ULONG)value.TryLength; - *handlerOffset = (ULONG)value.HandlerOffset; - *handlerLength = (ULONG)value.HandlerLength; - *classToken = (ULONG)value.ClassToken; -} - -void CompileResult::recSetMethodAttribs(CORINFO_METHOD_HANDLE ftn, CorInfoMethodRuntimeFlags attribs) -{ - if (SetMethodAttribs == nullptr) - SetMethodAttribs = new LightWeightMap(); - - int index = SetMethodAttribs->GetIndex(CastHandle(ftn)); - if (index == -1) - { - SetMethodAttribs->Add(CastHandle(ftn), (DWORD)attribs); - } - else - { - DWORD existingAttribs = SetMethodAttribs->GetItem(index); - SetMethodAttribs->Update(index, existingAttribs | (DWORD)attribs); - } -} -void CompileResult::dmpSetMethodAttribs(DWORDLONG key, DWORD value) -{ - printf("SetMethodAttribs key ftn-%016" PRIX64 ", value attr-%08X", key, value); -} -CorInfoMethodRuntimeFlags CompileResult::repSetMethodAttribs(CORINFO_METHOD_HANDLE ftn) -{ - if (SetMethodAttribs == nullptr) - return (CorInfoMethodRuntimeFlags)0; - - int index = SetMethodAttribs->GetIndex(CastHandle(ftn)); - if (index == -1) - return (CorInfoMethodRuntimeFlags)0; - - CorInfoMethodRuntimeFlags result = (CorInfoMethodRuntimeFlags)SetMethodAttribs->GetItem(index); - return result; -} - -void CompileResult::recReportTailCallDecision(CORINFO_METHOD_HANDLE callerHnd, - CORINFO_METHOD_HANDLE calleeHnd, - bool fIsTailPrefix, - CorInfoTailCall tailCallResult, - const char* reason) -{ - if (ReportTailCallDecision == nullptr) - ReportTailCallDecision = new DenseLightWeightMap(); - - Agnostic_ReportTailCallDecision value; - - value.callerHnd = CastHandle(callerHnd); - value.calleeHnd = CastHandle(calleeHnd); - value.fIsTailPrefix = (DWORD)fIsTailPrefix; - value.tailCallResult = (DWORD)tailCallResult; - if (reason != nullptr) // protect strlen - value.reason_index = - (DWORD)ReportTailCallDecision->AddBuffer((unsigned char*)reason, (DWORD)strlen(reason) + 1); - else - value.reason_index = (DWORD)-1; - - ReportTailCallDecision->Append(value); -} -void CompileResult::dmpReportTailCallDecision(DWORD key, const Agnostic_ReportTailCallDecision& value) -{ - const char* reason = (const char*)ReportTailCallDecision->GetBuffer(value.reason_index); - printf("ReportTailCallDecision key-%u, value cr-%016" PRIX64 " ce-%016" PRIX64 " tail-%u call-%u -%s", key, value.callerHnd, - value.calleeHnd, value.tailCallResult, value.tailCallResult, reason); - ReportTailCallDecision->Unlock(); -} - -void CompileResult::recReportFatalError(CorJitResult result) -{ - if (ReportFatalError == nullptr) - ReportFatalError = new DenseLightWeightMap(); - - ReportFatalError->Append((DWORD)result); -} -void CompileResult::dmpReportFatalError(DWORD key, DWORD value) -{ - printf("ReportFatalError key Count-%u, value result-%08X", key, value); -} - -void CompileResult::recRecordRelocation(void* location, void* target, CorInfoReloc fRelocType, int32_t addlDelta) -{ - repRecordRelocation(location, target, fRelocType, addlDelta); -} - -const char* relocationTypeToString(CorInfoReloc fRelocType) -{ - switch (fRelocType) - { -#define ADD_CASE(name) case CorInfoReloc::name: return #name - ADD_CASE(NONE); - ADD_CASE(DIRECT); - ADD_CASE(RELATIVE32); - ADD_CASE(ARM64_BRANCH26); - ADD_CASE(ARM64_PAGEBASE_REL21); - ADD_CASE(ARM64_PAGEOFFSET_12A); - ADD_CASE(ARM64_PAGEOFFSET_12L); - ADD_CASE(ARM64_LIN_TLSDESC_ADR_PAGE21); - ADD_CASE(ARM64_LIN_TLSDESC_LD64_LO12); - ADD_CASE(ARM64_LIN_TLSDESC_ADD_LO12); - ADD_CASE(ARM64_LIN_TLSDESC_CALL); - ADD_CASE(ARM64_WIN_TLS_SECREL_HIGH12A); - ADD_CASE(ARM64_WIN_TLS_SECREL_LOW12A); - ADD_CASE(AMD64_WIN_SECREL); - ADD_CASE(AMD64_LIN_TLSGD); - ADD_CASE(ARM32_THUMB_BRANCH24); - ADD_CASE(ARM32_THUMB_MOV32); - ADD_CASE(ARM32_THUMB_MOV32_PCREL); - ADD_CASE(LOONGARCH64_PC); - ADD_CASE(LOONGARCH64_JIR); - ADD_CASE(RISCV64_CALL_PLT); - ADD_CASE(RISCV64_PCREL_I); - ADD_CASE(RISCV64_PCREL_S); - default: - return "UNKNOWN"; -#undef ADD_CASE - } -} -void CompileResult::dmpRecordRelocation(DWORD key, const Agnostic_RecordRelocation& value) -{ - printf("RecordRelocation key %u, value loc-%016" PRIX64 " tgt-%016" PRIX64 " fRelocType-%u(%s) addlDelta:%d", key, - value.location, value.target, value.fRelocType, relocationTypeToString((CorInfoReloc)value.fRelocType), - (int32_t)value.addlDelta); -} -void CompileResult::repRecordRelocation(void* location, void* target, CorInfoReloc fRelocType, int32_t addlDelta) -{ - if (RecordRelocation == nullptr) - RecordRelocation = new DenseLightWeightMap(); - - Agnostic_RecordRelocation value; - - value.location = CastPointer(location); - value.target = CastPointer(target); - value.fRelocType = (DWORD)fRelocType; - value.addlDelta = (DWORD)addlDelta; - - RecordRelocation->Append(value); -} - -// When we do a replay, we replace the CompileResult that was originally recorded. In most cases, -// though, as part of our collection process we do a "thinning" operation, using "mcs -removeDup -thin", -// which removes the CompileResult from the stored file. Because of this, we lose access to the original -// addresses. -// -// Unfortunately, we may have generated code based on the original relative addresses. For example, -// we might have generated a relocation based on the results of a call to GetFunctionEntryPoint, and -// the delta from the generated code to that address fit in a rel32 reloc. Or, it didn't fit, but the -// VM constructed a jump stub in the JIT code section that would fit, and returned that. -// -// Ideally, we would just keep all the original addresses and relocations, even if we delete the CompileResult. -// If a new relocation has the same target as an original relocation, then simply substitute the original -// delta and use that instead of the newly computed delta. -// -// For now, for rel32 relocations, if it doesn't fit, then simply pick an address immediately after the -// current section (using originalAddr), assuming we needed a jump stub. We'll let multiple calls to potentially -// different functions use the same address because even if they used different ones, and diffs were generated, -// no textual diffs would appear because most of the textual call names are "hackishMethodName". -// -void CompileResult::applyRelocs(RelocContext* rc, unsigned char* block1, ULONG blocksize1, void* originalAddr) -{ - if (RecordRelocation == nullptr) - return; - if (blocksize1 == 0) - return; - - // For wasm32, the JIT writes padded ULEB128/SLEB128 placeholders (PADDED_RELOC_SIZE - // bytes of `80 80 ... 80 00` that decode to zero) in place of the real handle at - // every reloc site. Both baseline and diff JITs write the same placeholder bytes, - // so byte-by-byte comparison naturally succeeds at reloc sites without any - // patching here. The near-differ validates reloc-target equivalence via - // `compareOffsetsWasm` when the surrounding immediate bytes happen to differ. - if (GetSpmiTargetArchitecture() == SPMI_TARGET_ARCHITECTURE_WASM32) - return; - - size_t section_begin = (size_t)block1; - size_t section_end = (size_t)block1 + (size_t)blocksize1; // address is exclusive - - LogDebug("applyRelocs block [%p,%p) block size %u, orig addr %p", block1, block1 + blocksize1, blocksize1, - originalAddr); - - for (unsigned int i = 0; i < RecordRelocation->GetCount(); i++) - { - Agnostic_RecordRelocation tmp = RecordRelocation->GetRawItems()[i]; - - if (Logger::IsLogLevelEnabled(LOGLEVEL_DEBUG)) - { - printf(" "); - dmpRecordRelocation(i, tmp); - printf("\n"); - } - - const SPMI_TARGET_ARCHITECTURE targetArch = GetSpmiTargetArchitecture(); - - const CorInfoReloc relocType = (CorInfoReloc)tmp.fRelocType; - bool wasRelocHandled = false; - - // Do platform specific relocations first. - - if ((targetArch == SPMI_TARGET_ARCHITECTURE_X86) || (targetArch == SPMI_TARGET_ARCHITECTURE_ARM)) - { - if (relocType == CorInfoReloc::DIRECT) - { - DWORDLONG fixupLocation = tmp.location; - - size_t address = section_begin + (size_t)fixupLocation - (size_t)originalAddr; - if ((section_begin <= address) && (address < section_end)) // A reloc for our section? - { - LogDebug(" fixupLoc-%016" PRIX64 " (@%p) : %08X => %08X", fixupLocation, address, *(DWORD*)address, - (DWORD)tmp.target); - *(DWORD*)address = (DWORD)tmp.target; - } - wasRelocHandled = true; - } - } - - if (targetArch == SPMI_TARGET_ARCHITECTURE_ARM) - { - DWORDLONG fixupLocation = tmp.location; - DWORDLONG address = section_begin + (size_t)fixupLocation - (size_t)originalAddr; - - switch (relocType) - { - case CorInfoReloc::ARM32_THUMB_MOV32: - case CorInfoReloc::ARM32_THUMB_MOV32_PCREL: - { - INT32 delta = (INT32)(tmp.target - fixupLocation); - if ((section_begin <= address) && (address < section_end)) // A reloc for our section? - { - PutThumb2Mov32((UINT16*)address, (UINT32)delta); - } - wasRelocHandled = true; - } - break; - - case CorInfoReloc::ARM32_THUMB_BRANCH24: - { - if ((section_begin <= address) && (address < section_end)) // A reloc for our section? - { - // Like the arm64 ARM64_BRANCH26 and x64 RELATIVE32 handling, hardcode the - // bottom bits of the target into the instruction so the encoding does not - // depend on where SuperPMI allocated the code buffer. Otherwise a BL whose - // target is out of the +-16MB range for one of the two compared blocks would - // get a buffer-dependent placeholder, producing spurious asm diffs. - DWORDLONG target = tmp.target + (int32_t)tmp.addlDelta; - PutThumb2BlRel24((UINT16*)address, (INT32)(target & 0x00FFFFFE)); - } - wasRelocHandled = true; - } - break; - - default: - break; - } - } - - if (targetArch == SPMI_TARGET_ARCHITECTURE_ARM64) - { - DWORDLONG fixupLocation = tmp.location; - DWORDLONG address = section_begin + (size_t)fixupLocation - (size_t)originalAddr; - - DWORDLONG target = tmp.target + (int32_t)tmp.addlDelta; - if (relocType == CorInfoReloc::ARM64_PAGEBASE_REL21 || relocType == CorInfoReloc::ARM64_LIN_TLSDESC_ADR_PAGE21 || - relocType == CorInfoReloc::ARM64_PAGEOFFSET_12A || relocType == CorInfoReloc::ARM64_PAGEOFFSET_12L) - { - if ((rc->originalRoDataAddress2 <= (size_t)target) && - ((size_t)target < rc->originalRoDataAddress2 + rc->roDataSize2)) - { - size_t ro_section_offset = (size_t)target - rc->originalRoDataAddress2; - size_t ro_section_fake_start = (size_t)-1; - - // Looks like the target is in the RO data section. - if ((rc->originalHotCodeAddress <= (size_t)fixupLocation) && - ((size_t)fixupLocation < rc->originalHotCodeAddress + rc->hotCodeSize)) - { - // Fixup location is in the hot section - ro_section_fake_start = rc->originalHotCodeAddress + rc->hotCodeSize; - target = (INT64)(ro_section_fake_start + ro_section_offset - fixupLocation); - } - else if ((rc->originalColdCodeAddress <= (size_t)fixupLocation) && - ((size_t)fixupLocation < rc->originalColdCodeAddress + rc->coldCodeSize)) - { - // Fixup location is in the cold section - ro_section_fake_start = rc->originalColdCodeAddress + rc->coldCodeSize; - target = (INT64)(ro_section_fake_start + ro_section_offset - fixupLocation); - } - } - } - - switch (relocType) - { - case CorInfoReloc::ARM64_BRANCH26: // 26 bit offset << 2 & sign ext, for B and BL - { - if ((section_begin <= address) && (address < section_end)) // A reloc for our section? - { - // Similar to x64's IMAGE_REL_BASED_REL32 handling we - // will handle this by also hardcoding the bottom bits - // of the target into the instruction. - PutArm64Rel28((UINT32*)address, (INT32)target); - } - wasRelocHandled = true; - } - break; - - case CorInfoReloc::ARM64_PAGEBASE_REL21: // ADRP 21 bit PC-relative page address - case CorInfoReloc::ARM64_LIN_TLSDESC_ADR_PAGE21: // ADRP 21 bit for TLSDesc - { - if ((section_begin <= address) && (address < section_end)) // A reloc for our section? - { - INT64 targetPage = (INT64)target & 0xFFFFFFFFFFFFF000LL; - INT64 fixupLocationPage = (INT64)fixupLocation & 0xFFFFFFFFFFFFF000LL; - INT64 pageDelta = (INT64)(targetPage - targetPage); - INT32 imm21 = (INT32)(pageDelta >> 12) & 0x1FFFFF; - PutArm64Rel21((UINT32*)address, imm21); - } - wasRelocHandled = true; - } - break; - - case CorInfoReloc::ARM64_PAGEOFFSET_12A: // ADD 12 bit page offset - { - if ((section_begin <= address) && (address < section_end)) // A reloc for our section? - { - INT32 imm12 = (INT32)(SIZE_T)target & 0xFFFLL; - PutArm64Rel12((UINT32*)address, imm12); - } - wasRelocHandled = true; - } - break; - - case CorInfoReloc::ARM64_PAGEOFFSET_12L: // LDR 12 bit page offset - { - if ((section_begin <= address) && (address < section_end)) // A reloc for our section? - { - INT32 imm12 = (INT32)(SIZE_T)target & 0xFFFLL; - PutArm64Rel12Ldr((UINT32*)address, imm12); - } - wasRelocHandled = true; - } - break; - - case CorInfoReloc::ARM64_WIN_TLS_SECREL_HIGH12A: // TLSDESC ADD for High-12 Add - case CorInfoReloc::ARM64_WIN_TLS_SECREL_LOW12A: // TLSDESC ADD for Low-12 Add - case CorInfoReloc::ARM64_LIN_TLSDESC_LD64_LO12: - case CorInfoReloc::ARM64_LIN_TLSDESC_ADD_LO12: // TLSDESC ADD for corresponding ADRP - case CorInfoReloc::ARM64_LIN_TLSDESC_CALL: - { - // These are patched later by linker during actual execution - // and do not need relocation. - wasRelocHandled = true; - } - break; - - default: - break; - } - } - - if (targetArch == SPMI_TARGET_ARCHITECTURE_RISCV64) - { - DWORDLONG fixupLocation = tmp.location; - DWORDLONG address = section_begin + (size_t)fixupLocation - (size_t)originalAddr; - - switch (relocType) - { - case CorInfoReloc::RISCV64_CALL_PLT: - case CorInfoReloc::RISCV64_PCREL_I: - case CorInfoReloc::RISCV64_PCREL_S: - { - if ((section_begin <= address) && (address < section_end)) // A reloc for our section? - { - // Similar to x64's IMAGE_REL_BASED_REL32 handling we - // will handle this by also hardcoding the bottom bits - // of the target into the instruction. - INT64 offset = (INT64)tmp.target; - INT32 lo12 = (offset << (64 - 12)) >> (64 - 12); - INT32 hi20 = INT32(offset - lo12); - bool isStype = (relocType == CorInfoReloc::RISCV64_PCREL_S); - PutRiscV64AuipcCombo((UINT32*)address, INT64(lo12) + INT64(hi20), isStype); - } - wasRelocHandled = true; - } - break; - - default: - break; - } - } - - if (IsSpmiTarget64Bit()) - { - if (!wasRelocHandled && (relocType == CorInfoReloc::DIRECT)) - { - DWORDLONG fixupLocation = tmp.location; - - // Write 64-bits into location - size_t address = section_begin + (size_t)fixupLocation - (size_t)originalAddr; - if ((section_begin <= address) && (address < section_end)) // A reloc for our section? - { - LogDebug(" fixupLoc-%016" PRIX64 " (@%p) %016" PRIX64 " => %016" PRIX64, fixupLocation, address, - *(DWORDLONG*)address, tmp.target); - *(DWORDLONG*)address = tmp.target; - } - - wasRelocHandled = true; - } - else if (relocType == CorInfoReloc::AMD64_LIN_TLSGD) - { - // These are patched later by linker during actual execution - // and do not need relocation. - wasRelocHandled = true; - } - } - - if (wasRelocHandled) - continue; - - // Now do all-platform relocations. - if ((relocType == CorInfoReloc::RELATIVE32) || (relocType == CorInfoReloc::AMD64_WIN_SECREL)) - { - DWORDLONG fixupLocation = tmp.location; - - size_t address = section_begin + (size_t)fixupLocation - (size_t)originalAddr; - if ((section_begin <= address) && (address < section_end)) // A reloc for our section? - { - DWORDLONG target = tmp.target + (int32_t)tmp.addlDelta; - DWORDLONG baseAddr = fixupLocation + sizeof(INT32); - INT64 delta = (INT64)(target - baseAddr); - bool deltaIsFinal = false; - - if (IsSpmiTarget64Bit()) - { - if (GetSpmiTargetArchitecture() == SPMI_TARGET_ARCHITECTURE_AMD64) - { - // For just AMD64: - // The VM attempts to allocate the JIT code buffer near the CLR assemblies, so 32-bit - // offsets (and RELATIVE32 relocations) can be used in the code. If this doesn't work out, - // such that a RELATIVE32 relocation doesn't fit, the VM throws away the JIT result, disables - // using RELATIVE32 relocations, and restarts compilation. SuperPMI doesn't know where the - // original compilation (during the collection) was allocated (though maybe we should - // add that to the MC, not just the CompileResult), and we don't have any control over - // where the JIT buffer is allocated. To handle this, if the getRelocTypeHint() was - // called on the target address, and the VM returned IMAGE_REL_BASED_REL32, then simply - // use the low-order 32 bits of the target address. This is unique enough for assembly - // diffs, because the delta will compare identically and won't be dependent on where - // SuperPMI allocated the JIT memory. - - if (rc->mc->GetRelocTypeHint != nullptr) - { - DWORDLONG key = tmp.target; - int index = rc->mc->GetRelocTypeHint->GetIndex(key); - if (index != -1) - { - CorInfoReloc retVal = (CorInfoReloc)rc->mc->GetRelocTypeHint->Get(key); - if (retVal == CorInfoReloc::RELATIVE32) - { - LogDebug(" RELATIVE32 target used as argument to getRelocTypeHint: setting delta=%d (0x%X)", - (int)key, (int)key); - delta = (INT64)(int)key; - deltaIsFinal = true; - } - } - } - } - - if (!deltaIsFinal) - { - // Check if tmp.target is the result of a call to getHelperFtn(). If so, the VM would create a - // jump stub if the RELATIVE32 address doesn't fit. We don't want to fail with a RELATIVE32 overflow if - // the actual target address doesn't fit, so use the low-order 32 bits of the address. - // We need to iterate the entire table since we don't know the helper function id. - - if (rc->mc->GetHelperFtn != nullptr) - { - for (unsigned int idx = 0; idx < rc->mc->GetHelperFtn->GetCount(); idx++) - { - Agnostic_GetHelperFtn value = rc->mc->GetHelperFtn->GetItem(idx); - if (value.helperLookup.handle == tmp.target) - { - LogDebug(" RELATIVE32 target is result of getHelperFtn(): setting delta=%d (0x%X)", - (int)tmp.target, (int)tmp.target); - delta = (INT64)(int)tmp.target; - deltaIsFinal = true; - break; // No need to consider the remaining GetHelperFtn entries - } - } - } - } - - if (!deltaIsFinal) - { - // Check if tmp.target is the result of a call to GetFunctionEntryPoint(). As for helper - // functions, above, the VM would create a jump stub if the RELATIVE32 address doesn't fit. - - if (rc->mc->GetFunctionEntryPoint != nullptr) - { - for (unsigned int idx = 0; idx < rc->mc->GetFunctionEntryPoint->GetCount(); idx++) - { - DLD value = rc->mc->GetFunctionEntryPoint->GetItem(idx); - if (value.A == tmp.target) - { - LogDebug(" RELATIVE32 target is result of getFunctionEntryPoint(): setting delta=%d (0x%X)", - (int)tmp.target, (int)tmp.target); - delta = (INT64)(int)tmp.target; - deltaIsFinal = true; - break; // No need to consider the remaining GetFunctionEntryPoint entries - } - } - } - } - - if (!deltaIsFinal) - { - // If the relocation points to the RO-data section, we need to be careful that the relocation - // fits in 32-bits for both the baseline and diff compilations. To do that, we pretend the RO - // data section exists immediately after the current code section. - - if ((rc->originalRoDataAddress1 <= (size_t)target) && - ((size_t)target < rc->originalRoDataAddress1 + rc->roDataSize1)) - { - size_t ro_section_offset = (size_t)target - rc->originalRoDataAddress1; - size_t ro_section_fake_start = (size_t)-1; - - // Looks like the target is in the RO data section. - if ((rc->originalHotCodeAddress <= (size_t)fixupLocation) && - ((size_t)fixupLocation < rc->originalHotCodeAddress + rc->hotCodeSize)) - { - // Fixup location is in the hot section - ro_section_fake_start = rc->originalHotCodeAddress + rc->hotCodeSize; - delta = (INT64)(ro_section_fake_start + ro_section_offset - baseAddr); - deltaIsFinal = true; - LogDebug(" RELATIVE32 hot code target is in RO data section: setting delta=%d (0x%X)", - delta, delta); - } - else if ((rc->originalColdCodeAddress <= (size_t)fixupLocation) && - ((size_t)fixupLocation < rc->originalColdCodeAddress + rc->coldCodeSize)) - { - // Fixup location is in the cold section - ro_section_fake_start = rc->originalColdCodeAddress + rc->coldCodeSize; - delta = (INT64)(ro_section_fake_start + ro_section_offset - baseAddr); - deltaIsFinal = true; - LogDebug(" RELATIVE32 cold code target is in RO data section: setting delta=%d (0x%X)", - delta, delta); - } - } - } - - if (delta != (INT64)(int)delta) - { - // This isn't going to fit in a signed 32-bit address. Use something that will fit, - // since we assume that original compilation fit fine. - // This is only an issue for 32-bit offsets on 64-bit targets. - target = (DWORDLONG)originalAddr + (DWORDLONG)blocksize1; - INT64 newdelta = (INT64)(target - baseAddr); - - LogDebug(" RELATIVE32 overflow. Mapping target to %016" PRIX64 ". Mapping delta: %016" PRIX64 " => %016" PRIX64, - target, delta, newdelta); - - delta = newdelta; - } - } - - if (IsSpmiTarget32Bit()) - { - // Only 32 bits matters. And we don't care about sign. Note that SuperPMI will sometimes return - // arbitrary values, such as 0xCAFE0003 from MethodContext::repGetHelperFtn(). - delta &= 0xFFFFFFFF; - } - else - { - if (delta != (INT64)(int)delta) - { - LogError("RELATIVE32 relocation overflows field! delta=0x%016" PRIX64, delta); - } - } - - if ((targetArch == SPMI_TARGET_ARCHITECTURE_AMD64) && !deltaIsFinal) - { - // During an actual compile, recordRelocation() will be called before the compile - // is actually finished, and it will write the relative offset into the fixupLocation. - // Then, emitEndCodeGen() will patch forward jumps by subtracting any adjustment due - // to overestimation of instruction sizes. Because we're applying the relocs after the - // compile has finished, we need to reverse that: i.e. add in the (negative) adjustment - // that's now in the fixupLocation. - INT32 adjustment = *(INT32*)address; - delta += adjustment; - } - - // Write 32-bits into location - LogDebug(" fixupLoc-%016" PRIX64 " (@%p) : %08X => %08X", fixupLocation, address, *(DWORD*)address, delta); - *(DWORD*)address = (DWORD)delta; - } - - wasRelocHandled = true; - } - - if (!wasRelocHandled) - { - LogError("Unknown reloc type %u", tmp.fRelocType); - } - } -} - -const Agnostic_RecordRelocation* CompileResult::findRelocationInRange(size_t originalBufferStart, - size_t originalBufferOffset, - size_t windowSize) -{ - if (RecordRelocation == nullptr) - return nullptr; - - if (windowSize == 0) - return nullptr; - - const size_t rangeLo = originalBufferStart + originalBufferOffset; - const size_t rangeHi = rangeLo + windowSize; - - // Guard against size_t wraparound (rangeLo near SIZE_MAX). Bail rather than - // scan with an inverted half-open range that could match unrelated relocs. - if (rangeHi < rangeLo) - return nullptr; - - const unsigned int count = RecordRelocation->GetCount(); - const Agnostic_RecordRelocation* items = RecordRelocation->GetRawItems(); - for (unsigned int i = 0; i < count; i++) - { - const size_t loc = (size_t)items[i].location; - if ((rangeLo <= loc) && (loc < rangeHi)) - { - return &items[i]; - } - } - return nullptr; -} - -void CompileResult::recProcessName(const char* name) -{ - if (ProcessName == nullptr) - ProcessName = new DenseLightWeightMap(); - - DWORD index = (DWORD)-1; - if (name != nullptr) - index = (DWORD)ProcessName->AddBuffer((unsigned char*)name, (DWORD)strlen(name) + 1); - - ProcessName->Append(index); -} -void CompileResult::dmpProcessName(DWORD key, DWORD value) -{ - const char* procName = (const char*)ProcessName->GetBuffer(value); - printf("ProcessName key %u, value '%s'", key, procName); - ProcessName->Unlock(); -} -const char* CompileResult::repProcessName() -{ - if (ProcessName == nullptr) - return "hackishProcessName"; - - if (ProcessName->GetCount() > 0) - { - return (const char*)ProcessName->GetBuffer(ProcessName->Get((DWORD)0)); - } - return nullptr; -} - -void CompileResult::recReserveUnwindInfo(BOOL isFunclet, BOOL isColdCode, ULONG unwindSize) -{ - if (ReserveUnwindInfo == nullptr) - ReserveUnwindInfo = new DenseLightWeightMap(); - - Agnostic_ReserveUnwindInfo value; - - value.isFunclet = (DWORD)isFunclet; - value.isColdCode = (DWORD)isColdCode; - value.unwindSize = (DWORD)unwindSize; - - ReserveUnwindInfo->Append(value); -} -void CompileResult::dmpReserveUnwindInfo(DWORD key, const Agnostic_ReserveUnwindInfo& value) -{ - printf("ReserveUnwindInfo key %u, value isFun-%u isCold-%u usz-%u", key, value.isFunclet, value.isColdCode, - value.unwindSize); -} - -void CompileResult::recAllocUnwindInfo(BYTE* pHotCode, - BYTE* pColdCode, - ULONG startOffset, - ULONG endOffset, - ULONG unwindSize, - BYTE* pUnwindBlock, - CorJitFuncKind funcKind) -{ - if (AllocUnwindInfo == nullptr) - AllocUnwindInfo = new DenseLightWeightMap(); - - Agnostic_AllocUnwindInfo value; - value.pHotCode = CastPointer(pHotCode); - value.pColdCode = CastPointer(pColdCode); - value.startOffset = (DWORD)startOffset; - value.endOffset = (DWORD)endOffset; - value.unwindSize = (DWORD)unwindSize; - value.pUnwindBlock_index = AllocUnwindInfo->AddBuffer((unsigned char*)pUnwindBlock, unwindSize); - value.funcKind = funcKind; - - AllocUnwindInfo->Append(value); -} -void CompileResult::dmpAllocUnwindInfo(DWORD key, const Agnostic_AllocUnwindInfo& value) -{ - printf("AllocUnwindInfo key %u, value pHot-%016" PRIX64 " pCold-%016" PRIX64 " startOff-%u endOff-%u unwindSz-%u blki-%u " - "funcKind-%u", - key, value.pHotCode, value.pColdCode, value.startOffset, value.endOffset, value.unwindSize, - value.pUnwindBlock_index, value.funcKind); -} - -void CompileResult::recRecordCallSite(ULONG instrOffset, CORINFO_SIG_INFO* callSig, CORINFO_METHOD_HANDLE methodHandle) -{ - repRecordCallSite(instrOffset, callSig, methodHandle); -} - -void CompileResult::dmpRecordCallSiteWithSignature(DWORD key, const Agnostic_RecordCallSite& value) const -{ - printf("RecordCallSite key %u, callSig-%s ftn-%016" PRIX64, - key, - SpmiDumpHelper::DumpAgnostic_CORINFO_SIG_INFO(value.callSig, RecordCallSiteWithSignature, CrSigInstHandleMap).c_str(), - value.methodHandle); -} - -void CompileResult::dmpRecordCallSiteWithoutSignature(DWORD key, DWORDLONG methodHandle) const -{ - printf("RecordCallSite without call signature key %u, ftn-%016" PRIX64, key, methodHandle); -} - -void CompileResult::repRecordCallSite(ULONG instrOffset, CORINFO_SIG_INFO* callSig, CORINFO_METHOD_HANDLE methodHandle) -{ - - if (RecordCallSiteWithSignature == nullptr) - { - // The most call site records have only `methodHandle`, so creating two separate maps give us better performance - // and smaller memory consumption. Note: we are not reading values from these maps during a normal replay. - RecordCallSiteWithSignature = new LightWeightMap(); - if (recordCallSitesWithoutSig) - { - RecordCallSiteWithoutSignature = new LightWeightMap(); - } - } - - if (callSig != nullptr) - { - Agnostic_RecordCallSite value; - ZeroMemory(&value, sizeof(Agnostic_RecordCallSite)); - value.callSig = SpmiRecordsHelper::StoreAgnostic_CORINFO_SIG_INFO(*callSig, RecordCallSiteWithSignature, CrSigInstHandleMap); - value.methodHandle = CastHandle(methodHandle); - RecordCallSiteWithSignature->Add(instrOffset, value); - } - else if (recordCallSitesWithoutSig) - { - RecordCallSiteWithoutSignature->Add(instrOffset, CastHandle(methodHandle)); - } -} - -bool CompileResult::fndRecordCallSiteSigInfo(ULONG instrOffset, CORINFO_SIG_INFO* pCallSig) -{ - if (RecordCallSiteWithSignature == nullptr) - return false; - - if (RecordCallSiteWithSignature->GetIndex(instrOffset) == -1) - return false; - - Agnostic_RecordCallSite value = RecordCallSiteWithSignature->Get(instrOffset); - - if (value.callSig.callConv == (DWORD)-1) - return false; - - *pCallSig = SpmiRecordsHelper::Restore_CORINFO_SIG_INFO(value.callSig, RecordCallSiteWithSignature, CrSigInstHandleMap, getOrCreateMemoryTracker()); - - return true; -} - -bool CompileResult::fndRecordCallSiteMethodHandle(ULONG instrOffset, CORINFO_METHOD_HANDLE* pMethodHandle) -{ - - if (RecordCallSiteWithSignature != nullptr && RecordCallSiteWithSignature->GetIndex(instrOffset) != -1) - { - Agnostic_RecordCallSite value = RecordCallSiteWithSignature->Get(instrOffset); - *pMethodHandle = (CORINFO_METHOD_HANDLE)value.methodHandle; - } - else if (RecordCallSiteWithoutSignature != nullptr && RecordCallSiteWithoutSignature->GetIndex(instrOffset) != -1) - { - CORINFO_METHOD_HANDLE value = (CORINFO_METHOD_HANDLE)RecordCallSiteWithoutSignature->Get(instrOffset); - *pMethodHandle = value; - } - return false; -} - -void CompileResult::dmpCrSigInstHandleMap(DWORD key, DWORDLONG value) -{ - printf("CrSigInstHandleMap key %u, value %016" PRIX64, key, value); -} diff --git a/src/coreclr/tools/superpmi/superpmi-shared/compileresult.h b/src/coreclr/tools/superpmi/superpmi-shared/compileresult.h deleted file mode 100644 index 7c4fafb1bc28f4..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/compileresult.h +++ /dev/null @@ -1,244 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// CompileResult.h - CompileResult contains the stuff generated by a compilation -//---------------------------------------------------------- -#ifndef _CompileResult -#define _CompileResult - -#include "runtimedetails.h" -#include "lightweightmap.h" -#include "agnostic.h" - -class MethodContext; - -// MemoryTracker: a very simple allocator and tracker of allocated memory, so it can be deleted when needed. -class MemoryTracker -{ -public: - MemoryTracker() : m_pHead(nullptr) {} - ~MemoryTracker() { freeAll(); } - - void* allocate(size_t sizeInBytes) - { - BYTE* pNew = new BYTE[sizeInBytes]; - m_pHead = new MemoryNode(pNew, m_pHead); // Prepend this new one to the tracked memory list. - return pNew; - } - -private: - - MemoryTracker(const MemoryTracker&) = delete; // no copy ctor - - void freeAll() - { - for (MemoryNode* p = m_pHead; p != nullptr; ) - { - MemoryNode* pNext = p->m_pNext; - delete p; - p = pNext; - } - m_pHead = nullptr; - } - - struct MemoryNode - { - MemoryNode(BYTE* pMem, MemoryNode* pNext) : m_pMem(pMem), m_pNext(pNext) {} - ~MemoryNode() { delete[] m_pMem; } - - BYTE* m_pMem; - MemoryNode* m_pNext; - }; - - MemoryNode* m_pHead; -}; - -// Data we need to process relocations properly. -struct RelocContext -{ - MethodContext* mc; - size_t hotCodeAddress; - size_t hotCodeSize; - size_t coldCodeAddress; - size_t coldCodeSize; - size_t roDataAddress; - size_t roDataSize1; - size_t roDataSize2; - size_t originalHotCodeAddress; - size_t originalColdCodeAddress; - size_t originalRoDataAddress1; - size_t originalRoDataAddress2; -}; - -class CompileResult -{ -public: - - CompileResult(); - ~CompileResult(); - - bool IsEmpty(); - - void AddCall(const char* name); - unsigned int CallLog_GetCount(); - bool CallLog_Contains(const char* str); - void dmpCallLog(DWORD key, DWORD value); - - void dumpToConsole(); - - void* allocateMemory(size_t sizeInBytes); - - void recAssert(const char* buff); - void dmpAssertLog(DWORD key, DWORD value); - const char* repAssert(); - - void recAllocMem(ULONG hotCodeSize, - ULONG coldCodeSize, - ULONG roDataSize, - ULONG xcptnsCount, - void* hotCodeBlock, - void* coldCodeBlock, - void* roDataBlock); - void recAllocMemCapture(); - void dmpAllocMem(DWORD key, const Agnostic_AllocMemDetails& value); - void repAllocMem(ULONG* hotCodeSize, - ULONG* coldCodeSize, - ULONG* roDataSize, - ULONG* xcptnsCount, - unsigned char** hotCodeBlock, - unsigned char** coldCodeBlock, - unsigned char** roDataBlock, - void** orig_hotCodeBlock, - void** orig_coldCodeBlock, - void** orig_roDataBlock); - - void recSetBoundaries(CORINFO_METHOD_HANDLE ftn, ULONG32 cMap, ICorDebugInfo::OffsetMapping* pMap); - void dmpSetBoundaries(DWORD key, const Agnostic_SetBoundaries& value); - bool repSetBoundaries(CORINFO_METHOD_HANDLE* ftn, ULONG32* cMap, ICorDebugInfo::OffsetMapping** pMap); - - void recSetVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo* vars); - void dmpSetVars(DWORD key, const Agnostic_SetVars& value); - bool repSetVars(CORINFO_METHOD_HANDLE* ftn, ULONG32* cVars, ICorDebugInfo::NativeVarInfo** vars); - - void recMetadata(const char* key, const void* value); - - void recSetPatchpointInfo(PatchpointInfo* patchpointInfo); - void dmpSetPatchpointInfo(DWORD key, const Agnostic_SetPatchpointInfo& value); - bool repSetPatchpointInfo(PatchpointInfo** patchpointInfo); - - void recAllocGCInfo(size_t size, void* retval); - void recAllocGCInfoCapture(); - void dmpAllocGCInfo(DWORD key, const Agnostic_AllocGCInfo& value); - void repAllocGCInfo(size_t* size, void** retval); - - void recCompileMethod(uint8_t** nativeEntry, uint32_t* nativeSizeOfCode, CorJitResult result); - void dmpCompileMethod(DWORD key, const Agnostic_CompileMethodResults& value); - void repCompileMethod(BYTE** nativeEntry, ULONG* nativeSizeOfCode, CorJitResult* result); - - void recMessageLog(const char* fmt, ...); - void dmpMessageLog(DWORD key, DWORD value); - - void recReportInliningDecision(CORINFO_METHOD_HANDLE inlinerHnd, - CORINFO_METHOD_HANDLE inlineeHnd, - CorInfoInline inlineResult, - const char* reason); - void dmpReportInliningDecision(DWORD key, const Agnostic_ReportInliningDecision& value); - CorInfoInline repReportInliningDecision(CORINFO_METHOD_HANDLE inlinerHnd, CORINFO_METHOD_HANDLE inlineeHnd); - - void recSetEHcount(unsigned cEH); - void dmpSetEHcount(DWORD key, DWORD value); - ULONG repSetEHcount(); - - void recSetEHinfo(unsigned EHnumber, const CORINFO_EH_CLAUSE* clause); - void dmpSetEHinfo(DWORD key, const Agnostic_CORINFO_EH_CLAUSE& value); - void repSetEHinfo(unsigned EHnumber, - ULONG* flags, - ULONG* tryOffset, - ULONG* tryLength, - ULONG* handlerOffset, - ULONG* handlerLength, - ULONG* classToken); - - void recSetMethodAttribs(CORINFO_METHOD_HANDLE ftn, CorInfoMethodRuntimeFlags attribs); - void dmpSetMethodAttribs(DWORDLONG key, DWORD value); - CorInfoMethodRuntimeFlags repSetMethodAttribs(CORINFO_METHOD_HANDLE ftn); - - void recReportTailCallDecision(CORINFO_METHOD_HANDLE callerHnd, - CORINFO_METHOD_HANDLE calleeHnd, - bool fIsTailPrefix, - CorInfoTailCall tailCallResult, - const char* reason); - void dmpReportTailCallDecision(DWORD key, const Agnostic_ReportTailCallDecision& value); - - void recReportFatalError(CorJitResult result); - void dmpReportFatalError(DWORD key, DWORD value); - - void recRecordRelocation(void* location, void* target, CorInfoReloc fRelocType, int32_t addlDelta); - void dmpRecordRelocation(DWORD key, const Agnostic_RecordRelocation& value); - void repRecordRelocation(void* location, void* target, CorInfoReloc fRelocType, int32_t addlDelta); - void applyRelocs(RelocContext* rc, unsigned char* block1, ULONG blocksize1, void* originalAddr); - - // Find the recorded relocation (if any) whose location falls in the half-open - // buffer range [originalBufferOffset, originalBufferOffset + windowSize) relative - // to `originalBufferStart`. Used by the wasm32 near-differ to map a coredistools - // opcode-byte block offset to a JIT-recorded reloc on the immediate-payload byte. - // Returns nullptr if no reloc is recorded in the range. - const Agnostic_RecordRelocation* findRelocationInRange(size_t originalBufferStart, - size_t originalBufferOffset, - size_t windowSize); - - void recProcessName(const char* name); - void dmpProcessName(DWORD key, DWORD value); - const char* repProcessName(); - - void recReserveUnwindInfo(BOOL isFunclet, BOOL isColdCode, ULONG unwindSize); - void dmpReserveUnwindInfo(DWORD key, const Agnostic_ReserveUnwindInfo& value); - - void recAllocUnwindInfo(BYTE* pHotCode, - BYTE* pColdCode, - ULONG startOffset, - ULONG endOffset, - ULONG unwindSize, - BYTE* pUnwindBlock, - CorJitFuncKind funcKind); - void dmpAllocUnwindInfo(DWORD key, const Agnostic_AllocUnwindInfo& value); - - void recRecordCallSite(ULONG instrOffset, CORINFO_SIG_INFO* callSig, CORINFO_METHOD_HANDLE methodHandle); - void dmpRecordCallSiteWithSignature(DWORD key, const Agnostic_RecordCallSite& value) const; - void dmpRecordCallSiteWithoutSignature(DWORD key, DWORDLONG methodHandle) const; - void repRecordCallSite(ULONG instrOffset, CORINFO_SIG_INFO* callSig, CORINFO_METHOD_HANDLE methodHandle); - bool fndRecordCallSiteSigInfo(ULONG instrOffset, CORINFO_SIG_INFO* pCallSig); - bool fndRecordCallSiteMethodHandle(ULONG instrOffset, CORINFO_METHOD_HANDLE* pMethodHandle); - - void dmpCrSigInstHandleMap(DWORD key, DWORDLONG value); - - DOUBLE secondsToCompile; - ULONGLONG clockCyclesToCompile; - -#define LWM(map, key, value) LightWeightMap* map; -#define DENSELWM(map, value) DenseLightWeightMap* map; -#include "crlwmlist.h" - -#define JITMETADATAINFO(name, type, flags) -#define JITMETADATAMETRIC(name, type, flags) type name; -#include "jitmetadatalist.h" - - // Reported method full name from JIT (not available with release JIT) - const char* MethodFullName; - // Reported compilation tier from JIT - const char* TieringName; - - // not persisted to disk. -public: - LightWeightMap* CallTargetTypes; - MemoryTracker* getOrCreateMemoryTracker(); - -private: - MemoryTracker* memoryTracker; - Capture_AllocMemDetails allocMemDets; - allocGCInfoDetails allocGCInfoDets; - - const bool recordCallSitesWithoutSig = false; // Set it to true if you want to use CallUtils::GetRecordedCallSiteInfo. -}; -#endif diff --git a/src/coreclr/tools/superpmi/superpmi-shared/crlwmlist.h b/src/coreclr/tools/superpmi/superpmi-shared/crlwmlist.h deleted file mode 100644 index 4cb03d45cc239a..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/crlwmlist.h +++ /dev/null @@ -1,43 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// crlwmlist.h - List of all LightWeightMap in CompileResult. -// To use, #define LWM(map, key, value) to something. -// If you need to distinguish DenseLightWeightMap, #define DENSELWM(map, value) as well. -//---------------------------------------------------------- - -#ifndef LWM -#error Define LWM before including this file. -#endif - -// If the key is needed, then DENSELWM must be defined. -#ifndef DENSELWM -#define DENSELWM(map, value) LWM(map, this_is_an_error, value) -#endif - -LWM(AllocGCInfo, DWORD, Agnostic_AllocGCInfo) -LWM(AllocMem, DWORD, Agnostic_AllocMemDetails) -DENSELWM(AllocUnwindInfo, Agnostic_AllocUnwindInfo) -DENSELWM(AssertLog, DWORD) -DENSELWM(CallLog, DWORD) -LWM(CompileMethod, DWORD, Agnostic_CompileMethodResults) -DENSELWM(MessageLog, DWORD) -DENSELWM(ProcessName, DWORD) -LWM(RecordCallSiteWithSignature, DWORD, Agnostic_RecordCallSite) -LWM(RecordCallSiteWithoutSignature, DWORD, DWORDLONG) -DENSELWM(RecordRelocation, Agnostic_RecordRelocation) -DENSELWM(ReportFatalError, DWORD) -DENSELWM(ReportInliningDecision, Agnostic_ReportInliningDecision) -DENSELWM(ReportTailCallDecision, Agnostic_ReportTailCallDecision) -DENSELWM(ReserveUnwindInfo, Agnostic_ReserveUnwindInfo) -LWM(SetBoundaries, DWORD, Agnostic_SetBoundaries) -LWM(SetEHcount, DWORD, DWORD) -LWM(SetEHinfo, DWORD, Agnostic_CORINFO_EH_CLAUSE) -LWM(SetMethodAttribs, DWORDLONG, DWORD) -LWM(SetVars, DWORD, Agnostic_SetVars) -LWM(SetPatchpointInfo, DWORD, Agnostic_SetPatchpointInfo) -DENSELWM(CrSigInstHandleMap, DWORDLONG) - -#undef LWM -#undef DENSELWM diff --git a/src/coreclr/tools/superpmi/superpmi-shared/errorhandling.cpp b/src/coreclr/tools/superpmi/superpmi-shared/errorhandling.cpp deleted file mode 100644 index 69ce2106cf7adb..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/errorhandling.cpp +++ /dev/null @@ -1,248 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "standardpch.h" -#include "errorhandling.h" -#include "logging.h" -#include "runtimedetails.h" -#include "spmiutil.h" - -// Allocating memory here seems moderately dangerous: we'll probably leak like a sieve... -void MSC_ONLY(__declspec(noreturn)) ThrowSpmiException(DWORD exceptionCode, va_list args, const char* message) -{ - assert(IsSuperPMIException(exceptionCode)); - - char* buffer = new char[8192]; - _vsnprintf_s(buffer, 8192, 8191, message, args); - - if (BreakOnException()) - DEBUG_BREAK; - - ULONG_PTR exArgs[1]; - exArgs[0] = (ULONG_PTR)buffer; - RaiseException(exceptionCode, 0, ArrLen(exArgs), exArgs); -} - -void MSC_ONLY(__declspec(noreturn)) ThrowSpmiException(DWORD exceptionCode, const char* msg, ...) -{ - va_list ap; - va_start(ap, msg); - ThrowSpmiException(exceptionCode, ap, msg); -} - -// Throw an exception that indicates that the EE side threw an exception during recording. -// These exceptions do not result in replay errors; see JitInstance::CompileMethod. -// Note that we rely on the fact that the JIT do not look closely at exceptions thrown by the EE; -// otherwise this could cause issues since it changes the exception code from what was actually -// thrown. -// -// However, do note that crossgen2/ilc and the VM already do not use the same exception code when -// throwing exceptions. -// -void MSC_ONLY(__declspec(noreturn)) ThrowRecordedException(DWORD innerExceptionCode) -{ - if (BreakOnException()) - DEBUG_BREAK; - - ULONG_PTR args[1]; - args[0] = (ULONG_PTR)innerExceptionCode; - RaiseException(EXCEPTIONCODE_RECORDED_EXCEPTION, 0, ArrLen(args), args); -} - -SpmiException::SpmiException(FilterSuperPMIExceptionsParam_CaptureException* e) - : exCode(e->exceptionCode), exMessage(e->exceptionMessage) -{ -} - -#if 0 -SpmiException::~SpmiException() -{ - delete[] exMessage; - exMessage = nullptr; -} -#endif - -char* SpmiException::GetExceptionMessage() -{ - return exMessage; -} - -void SpmiException::ShowAndDeleteMessage() -{ - if (exMessage != nullptr) - { - LogError("Exception thrown: %s", exMessage); - } - else - { - LogError("Unexpected exception %x was thrown.", exCode); - } - - DeleteMessage(); -} - -void SpmiException::DeleteMessage() -{ - delete[] exMessage; - exMessage = nullptr; -} - -DWORD SpmiException::GetCode() -{ - return exCode; -} - -// This filter function executes the handler only for EXCEPTIONCODE_MC, otherwise it continues the handler search. -LONG FilterSuperPMIExceptions_CatchMC(PEXCEPTION_POINTERS pExceptionPointers, LPVOID lpvParam) -{ - return (pExceptionPointers->ExceptionRecord->ExceptionCode == EXCEPTIONCODE_MC) ? EXCEPTION_EXECUTE_HANDLER - : EXCEPTION_CONTINUE_SEARCH; -} - -// This filter function captures the exception pointers and continues searching. -LONG FilterSuperPMIExceptions_CaptureExceptionAndContinue(PEXCEPTION_POINTERS pExceptionPointers, LPVOID lpvParam) -{ - FilterSuperPMIExceptionsParam_CaptureException* pSPMIEParam = (FilterSuperPMIExceptionsParam_CaptureException*)lpvParam; - pSPMIEParam->Initialize(pExceptionPointers); - return EXCEPTION_CONTINUE_SEARCH; -} - -LONG FilterSuperPMIExceptions_CaptureExceptionAndStop(PEXCEPTION_POINTERS pExceptionPointers, LPVOID lpvParam) -{ - FilterSuperPMIExceptionsParam_CaptureException* pSPMIEParam = (FilterSuperPMIExceptionsParam_CaptureException*)lpvParam; - pSPMIEParam->Initialize(pExceptionPointers); - return EXCEPTION_EXECUTE_HANDLER; -} - -bool IsSuperPMIException(unsigned code) -{ - switch (code) - { - case EXCEPTIONCODE_MC: - case EXCEPTIONCODE_LWM: - case EXCEPTIONCODE_CALLUTILS: - case EXCEPTIONCODE_TYPEUTILS: - case EXCEPTIONCODE_ASSERT: - return true; - default: - if ((EXCEPTIONCODE_DebugBreakorAV <= code) && (code < EXCEPTIONCODE_DebugBreakorAV_MAX)) - { - return true; - } - return false; - } -} - -// This filter function executes the handler only for non-SuperPMI generated exceptions, otherwise it continues the -// handler search. This allows for SuperPMI-thrown exceptions to pass through the JIT and be caught by the outer -// SuperPMI handler. -LONG FilterSuperPMIExceptions_CatchNonSuperPMIException(PEXCEPTION_POINTERS pExceptionPointers, LPVOID lpvParam) -{ - return !IsSuperPMIException(pExceptionPointers->ExceptionRecord->ExceptionCode); -} - - -// This filter function executes the handler only for SuperPMI generated exceptions, otherwise it continues the -// handler search. This allows for SuperPMI-thrown exceptions to be caught by the JIT and not be caught by the outer -// SuperPMI handler. -LONG FilterSuperPMIExceptions_CatchSuperPMIException(PEXCEPTION_POINTERS pExceptionPointers, LPVOID lpvParam) -{ - return IsSuperPMIException(pExceptionPointers->ExceptionRecord->ExceptionCode); -} - - -bool RunWithErrorTrap(void (*function)(void*), void* param) -{ - bool success = true; - - struct TrapParam - { - void (*function)(void*); - void* param; - } trapParam; - trapParam.function = function; - trapParam.param = param; - - PAL_TRY(TrapParam*, pTrapParam, &trapParam) - { - pTrapParam->function(pTrapParam->param); - } - PAL_EXCEPT_FILTER(FilterSuperPMIExceptions_CatchNonSuperPMIException) - { - success = false; - } - PAL_ENDTRY - - return success; -} - -bool RunWithSPMIErrorTrap(void (*function)(void*), void* param) -{ - bool success = true; - - struct TrapParam - { - void (*function)(void*); - void* param; - } trapParam; - trapParam.function = function; - trapParam.param = param; - - PAL_TRY(TrapParam*, pTrapParam, &trapParam) - { - pTrapParam->function(pTrapParam->param); - } - PAL_EXCEPT_FILTER(FilterSuperPMIExceptions_CatchSuperPMIException) - { - success = false; - } - PAL_ENDTRY - - return success; -} - -void RunWithErrorExceptionCodeCaptureAndContinueImp(void* param, void (*function)(void*), void (*finallyFunction)(void*, DWORD)) -{ - struct Param : FilterSuperPMIExceptionsParam_CaptureException - { - void (*function)(void*); - void (*finallyFunction)(void*, DWORD); - void* pParamActual; - } paramStruct; - - paramStruct.pParamActual = param; - paramStruct.function = function; - paramStruct.finallyFunction = finallyFunction; - -#ifdef HOST_UNIX - // We can't capture the exception code as a PAL exceptions when the exception is - // thrown from crossgen2 on Linux as the jitinterface dll does not use the PAL. So - // assume there will be some error, then set it to zero (no error) - // if the called function doesn't throw. - // - // While not quite matching the behavior on Windows, for C++ exceptions this will - // be equivalent. (All C++ exceptions on Windows have the same exception code.) - paramStruct.exceptionCode = 1; -#endif // HOST_UNIX - - PAL_TRY(Param*, pOuterParam, ¶mStruct) - { - PAL_TRY(Param*, pParam, pOuterParam) - { - pParam->function(pParam->pParamActual); -#ifdef HOST_UNIX - pParam->exceptionCode = 0; -#endif // HOST_UNIX - } - PAL_EXCEPT_FILTER(FilterSuperPMIExceptions_CaptureExceptionAndContinue) - { - } - PAL_ENDTRY - } - PAL_FINALLY - { - paramStruct.finallyFunction(paramStruct.pParamActual, paramStruct.exceptionCode); - } - PAL_ENDTRY - -} diff --git a/src/coreclr/tools/superpmi/superpmi-shared/errorhandling.h b/src/coreclr/tools/superpmi/superpmi-shared/errorhandling.h deleted file mode 100644 index 484106fd3878d6..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/errorhandling.h +++ /dev/null @@ -1,178 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// ErrorHandling.h - Helpers & whatnot for using SEH for errors -//---------------------------------------------------------- -#ifndef _ErrorHandling -#define _ErrorHandling - -#include "logging.h" - -// EXCEPTIONCODE_DebugBreakorAV is just the base exception number; calls to DebugBreakorAV() -// pass a unique number to add to this. EXCEPTIONCODE_DebugBreakorAV_MAX is the maximum number -// of this exception range. -#define EXCEPTIONCODE_DebugBreakorAV 0xe0421000 -#define EXCEPTIONCODE_DebugBreakorAV_MAX 0xe0422000 - -#define EXCEPTIONCODE_MC 0xe0422000 -#define EXCEPTIONCODE_LWM 0xe0423000 -#define EXCEPTIONCODE_CALLUTILS 0xe0426000 -#define EXCEPTIONCODE_TYPEUTILS 0xe0427000 -// Special exception code for rethrowing a recorded exception. This is NOT -// considered an SPMI exception (see IsSuperPMIException), but it also does not -// result in a replay failure (see JitInstance::CompileMethod). -#define EXCEPTIONCODE_RECORDED_EXCEPTION 0xe0428000 -#define EXCEPTIONCODE_ASSERT 0xe0440000 - -// RaiseException wrappers -void MSC_ONLY(__declspec(noreturn)) ThrowSpmiException(DWORD exceptionCode, const char* message, ...); -void MSC_ONLY(__declspec(noreturn)) ThrowRecordedException(DWORD innerExceptionCode); - -// Assert stuff -#define AssertCodeMsg(expr, exCode, msg, ...) \ - do \ - { \ - if (!(expr)) \ - LogException(exCode, "SuperPMI assertion '%s' failed (" msg ")", #expr, ##__VA_ARGS__); \ - } while (0) - -#define AssertCode(expr, exCode) \ - do \ - { \ - if (!(expr)) \ - LogException(exCode, "SuperPMI assertion '%s' failed", #expr); \ - } while (0) - -#define AssertMapExists(map, keymsg, ...) \ - do \ - { \ - if (map == nullptr) \ - LogException(EXCEPTIONCODE_MC, "SuperPMI assertion failed (missing map " #map ")" keymsg, ##__VA_ARGS__); \ - } while (0) - -#define LookupByKeyOrMiss(map, key, keymsg, ...) \ - [&]() { \ - if (map == nullptr) \ - LogException(EXCEPTIONCODE_MC, "SuperPMI assertion failed (missing map " #map ")" keymsg, ##__VA_ARGS__); \ - int index = map->GetIndex(key); \ - if (index == -1) \ - LogException(EXCEPTIONCODE_MC, "SuperPMI assertion failed (missing key \"" #key "\" in map " #map ")" keymsg, ##__VA_ARGS__); \ - return map->GetItem(index); \ - }() - -// clang doesn't allow for an empty __VA_ARGS__, so we need to pass something non-empty to `LogException`, below. - -#define AssertMapExistsNoMessage(map) \ - do \ - { \ - if (map == nullptr) \ - LogException(EXCEPTIONCODE_MC, "SuperPMI assertion failed (missing map " #map ")", ""); \ - } while (0) - -#define LookupByKeyOrMissNoMessage(map, key) \ - [&]() { \ - if (map == nullptr) \ - LogException(EXCEPTIONCODE_MC, "SuperPMI assertion failed (missing map " #map ")", ""); \ - int index = map->GetIndex(key); \ - if (index == -1) \ - LogException(EXCEPTIONCODE_MC, "SuperPMI assertion failed (missing key \"" #key "\" in map " #map ")", ""); \ - return map->GetItem(index); \ - }() - -#define AssertMsg(expr, msg, ...) AssertCodeMsg(expr, EXCEPTIONCODE_ASSERT, msg, ##__VA_ARGS__) -#define Assert(expr) AssertCode(expr, EXCEPTIONCODE_ASSERT) - -// -// Functions and types used by PAL_TRY-related macros. -// - -extern bool IsSuperPMIException(unsigned code); - -extern LONG FilterSuperPMIExceptions_CatchMC(PEXCEPTION_POINTERS pExceptionPointers, LPVOID lpvParam); - -struct FilterSuperPMIExceptionsParam_CaptureException -{ - DWORD exceptionCode; - char* exceptionMessage; // 'new' memory passed from ThrowException() - - FilterSuperPMIExceptionsParam_CaptureException() - : exceptionCode(0) - , exceptionMessage(nullptr) - { - } - - // Note: this is called during an SEH filter; the data pointed to by PEXCEPTION_POINTERS is not valid after - // calling this function, so anything we want to safe must be copied. - // The exception message string is 'new' memory, allocated in the ThrowException() function. - void Initialize(PEXCEPTION_POINTERS pExceptionPointers) - { - exceptionCode = pExceptionPointers->ExceptionRecord->ExceptionCode; - exceptionMessage = nullptr; - if (IsSuperPMIException(exceptionCode) && (pExceptionPointers->ExceptionRecord->NumberParameters >= 1)) - { - exceptionMessage = (char*)pExceptionPointers->ExceptionRecord->ExceptionInformation[0]; - } - } -}; - -extern LONG FilterSuperPMIExceptions_CaptureExceptionAndStop(PEXCEPTION_POINTERS pExceptionPointers, LPVOID lpvParam); -extern bool RunWithErrorTrap(void (*function)(void*), void* param); -extern bool RunWithSPMIErrorTrap(void (*function)(void*), void* param); -extern void RunWithErrorExceptionCodeCaptureAndContinueImp(void* param, void (*function)(void*), void (*finallyFunction)(void*, DWORD)); - -template -class LambdaExecutor -{ -public: - LambdaType& _lambda; - - LambdaExecutor(LambdaType& lambda) : _lambda(lambda) {} -}; - -template -void RunWithErrorExceptionCodeCaptureAndContinue(LambdaTry function, LambdaFinally finally) -{ - struct LambdaArguments - { - LambdaExecutor *pTryLambda; - LambdaExecutor *pFinallyLambda; - } lambdaArgs; - - LambdaExecutor tryStorage(function); - LambdaExecutor finallyStorage(finally); - - lambdaArgs.pTryLambda = &tryStorage; - lambdaArgs.pFinallyLambda = &finallyStorage; - - RunWithErrorExceptionCodeCaptureAndContinueImp(&lambdaArgs, - [](void* pParam) - { - ((LambdaArguments*)pParam)->pTryLambda->_lambda(); - }, - [](void* pParam, DWORD exceptionCode) - { - ((LambdaArguments*)pParam)->pFinallyLambda->_lambda(exceptionCode); - }); -} - -class SpmiException -{ -private: - DWORD exCode; - char* exMessage; - -public: - SpmiException(FilterSuperPMIExceptionsParam_CaptureException* e); -#if 0 - ~SpmiException(); -#endif - - char* GetExceptionMessage(); - DWORD GetCode(); - - void ShowAndDeleteMessage(); - void DeleteMessage(); -}; - -#endif diff --git a/src/coreclr/tools/superpmi/superpmi-shared/hash.cpp b/src/coreclr/tools/superpmi/superpmi-shared/hash.cpp deleted file mode 100644 index b8cba70815a805..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/hash.cpp +++ /dev/null @@ -1,161 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// hash.cpp - Class for hashing a text stream using MurMurHash3 hashing -//---------------------------------------------------------- - -#include "standardpch.h" -#include "runtimedetails.h" -#include "errorhandling.h" -#include "hash.h" - -// MurmurHash3 was written by Austin Appleby, and is placed in the public -// domain. The author hereby disclaims copyright to this source code. -// -// Implementation was copied from https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp -// with changes around strict-aliasing/unaligned reads - -inline uint64_t ROTL64(uint64_t x, int8_t r) -{ - return (x << r) | (x >> (64 - r)); -} - -inline uint64_t getblock64(const uint8_t* ptr) -{ - uint64_t val = 0; - memcpy(&val, ptr, sizeof(uint64_t)); - return val; -} - -inline void setblock64(uint8_t* ptr, uint64_t val) -{ - memcpy(ptr, &val, sizeof(uint64_t)); -} - -// Finalization mix - force all bits of a hash block to avalanche -inline uint64_t fmix64(uint64_t k) -{ - k ^= k >> 33; - k *= 0xff51afd7ed558ccdLLU; - k ^= k >> 33; - k *= 0xc4ceb9fe1a85ec53LLU; - k ^= k >> 33; - return k; -} - -static void MurmurHash3_128(const void* key, const size_t len, const uint32_t seed, void* out) -{ - const uint8_t* data = static_cast(key); - const size_t nblocks = len / MM3_HASH_BYTE_SIZE; - uint64_t h1 = seed; - uint64_t h2 = seed; - const uint64_t c1 = 0x87c37b91114253d5LLU; - const uint64_t c2 = 0x4cf5ad432745937fLLU; - - // body - for (size_t i = 0; i < nblocks; i++) - { - uint64_t k1 = getblock64(data + (i * 2 + 0) * sizeof(uint64_t)); - uint64_t k2 = getblock64(data + (i * 2 + 1) * sizeof(uint64_t)); - - k1 *= c1; k1 = ROTL64(k1, 31); k1 *= c2; h1 ^= k1; - h1 = ROTL64(h1, 27); h1 += h2; h1 = h1 * 5 + 0x52dce729; - k2 *= c2; k2 = ROTL64(k2, 33); k2 *= c1; h2 ^= k2; - h2 = ROTL64(h2, 31); h2 += h1; h2 = h2 * 5 + 0x38495ab5; - } - - // tail - const uint8_t* tail = data + nblocks * MM3_HASH_BYTE_SIZE; - uint64_t k1 = 0; - uint64_t k2 = 0; - - switch (len & 15) - { - case 15: k2 ^= static_cast(tail[14]) << 48; FALLTHROUGH; - case 14: k2 ^= static_cast(tail[13]) << 40; FALLTHROUGH; - case 13: k2 ^= static_cast(tail[12]) << 32; FALLTHROUGH; - case 12: k2 ^= static_cast(tail[11]) << 24; FALLTHROUGH; - case 11: k2 ^= static_cast(tail[10]) << 16; FALLTHROUGH; - case 10: k2 ^= static_cast(tail[9]) << 8; FALLTHROUGH; - case 9: k2 ^= static_cast(tail[8]) << 0; - k2 *= c2; k2 = ROTL64(k2, 33); k2 *= c1; h2 ^= k2; - FALLTHROUGH; - - case 8: k1 ^= static_cast(tail[7]) << 56; FALLTHROUGH; - case 7: k1 ^= static_cast(tail[6]) << 48; FALLTHROUGH; - case 6: k1 ^= static_cast(tail[5]) << 40; FALLTHROUGH; - case 5: k1 ^= static_cast(tail[4]) << 32; FALLTHROUGH; - case 4: k1 ^= static_cast(tail[3]) << 24; FALLTHROUGH; - case 3: k1 ^= static_cast(tail[2]) << 16; FALLTHROUGH; - case 2: k1 ^= static_cast(tail[1]) << 8; FALLTHROUGH; - case 1: k1 ^= static_cast(tail[0]) << 0; - k1 *= c1; k1 = ROTL64(k1, 31); k1 *= c2; h1 ^= k1; - break; - } - - // finalization - h1 ^= len; - h2 ^= len; - h1 += h2; - h2 += h1; - h1 = fmix64(h1); - h2 = fmix64(h2); - h1 += h2; - h2 += h1; - - setblock64(static_cast(out), h1); - setblock64(static_cast(out) + sizeof(uint64_t), h2); -} - -// Hash::WriteHashValueAsText - Take a binary hash value in the array of bytes pointed to by -// 'pHash' (size in bytes 'cbHash'), and write an ASCII hexadecimal representation of it in the buffer -// 'hashTextBuffer' (size in bytes 'hashTextBufferLen'). -// -// Returns true on success, false on failure (only if the arguments are bad). -bool Hash::WriteHashValueAsText(const BYTE* pHash, size_t cbHash, char* hashTextBuffer, size_t hashTextBufferLen) -{ - // This could be: - // - // for (DWORD i = 0; i < MM3_HASH_BYTE_SIZE; i++) - // { - // sprintf_s(hash + i * 2, hashLen - i * 2, "%02X", bHash[i]); - // } - // - // But this function is hot, and sprintf_s is too slow. This is a specialized function to speed it up. - - if (hashTextBufferLen < 2 * cbHash + 1) // 2 characters for each byte, plus null terminator - { - LogError("WriteHashValueAsText doesn't have enough space to write the output"); - return false; - } - - static const char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; - char* pCur = hashTextBuffer; - for (size_t i = 0; i < cbHash; i++) - { - unsigned digit = pHash[i]; - unsigned lowNibble = digit & 0xF; - unsigned highNibble = digit >> 4; - *pCur++ = hexDigits[highNibble]; - *pCur++ = hexDigits[lowNibble]; - } - *pCur++ = '\0'; - return true; -} - -// Hash::HashBuffer - Compute a MurMurHash3 hash of the data pointed to by 'pBuffer', of 'bufLen' bytes, -// writing the hexadecimal ASCII text representation of the hash to the buffer pointed to by 'hash', -// of 'hashLen' bytes in size, which must be at least MM3_HASH_BUFFER_SIZE bytes. -// -// Returns the number of bytes written, or -1 on error. -int Hash::HashBuffer(BYTE* pBuffer, size_t bufLen, char* hash, size_t hashLen) -{ - uint8_t murMurHash[MM3_HASH_BYTE_SIZE]; - MurmurHash3_128(pBuffer, bufLen, 0, murMurHash); - - if (!WriteHashValueAsText(murMurHash, MM3_HASH_BYTE_SIZE, hash, hashLen)) - return -1; - - return MM3_HASH_BUFFER_SIZE; // if we had success we wrote MM3_HASH_BUFFER_SIZE bytes to the buffer -} diff --git a/src/coreclr/tools/superpmi/superpmi-shared/hash.h b/src/coreclr/tools/superpmi/superpmi-shared/hash.h deleted file mode 100644 index 67053ce932737b..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/hash.h +++ /dev/null @@ -1,22 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// hash.h - Class for hashing a text stream using MD5 hashing -//---------------------------------------------------------- -#ifndef _hash -#define _hash - -#define MM3_HASH_BYTE_SIZE 16 // MurMurHash3 is 128-bit, so we need 16 bytes to store it -#define MM3_HASH_BUFFER_SIZE 33 // MurMurHash3 is 128-bit, so we need 32 chars + 1 char to store null-terminator - -class Hash -{ -public: - static int HashBuffer(BYTE* pBuffer, size_t bufLen, char* hash, size_t hashLen); - -private: - static bool WriteHashValueAsText(const BYTE* pHash, size_t cbHash, char* hashTextBuffer, size_t hashTextBufferLen); -}; - -#endif diff --git a/src/coreclr/tools/superpmi/superpmi-shared/icorjitcompilerimpl.h b/src/coreclr/tools/superpmi/superpmi-shared/icorjitcompilerimpl.h deleted file mode 100644 index 66f7e0992a300c..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/icorjitcompilerimpl.h +++ /dev/null @@ -1,51 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#ifndef _ICorJitCompilerImpl -#define _ICorJitCompilerImpl - -// ICorJitCompilerImpl: declare for implementation all the members of the ICorJitCompiler interface (which are -// specified as pure virtual methods). This is done once, here, and all implementations share it, -// to avoid duplicated declarations. This file is #include'd within all the ICorJitCompiler implementation -// classes. -// -// NOTE: this file is in exactly the same order, with exactly the same whitespace, as the ICorJitCompiler -// interface declaration (with the "virtual" and "= 0" syntax removed). This is to make it easy to compare -// against the interface declaration. - -public: -// compileMethod is the main routine to ask the JIT Compiler to create native code for a method. The -// method to be compiled is passed in the 'info' parameter, and the code:ICorJitInfo is used to allow the -// JIT to resolve tokens, and make any other callbacks needed to create the code. nativeEntry, and -// nativeSizeOfCode are just for convenience because the JIT asks the EE for the memory to emit code into -// (see code:ICorJitInfo.allocMem), so really the EE already knows where the method starts and how big -// it is (in fact, it could be in more than one chunk). -// -// * In the 32 bit jit this is implemented by code:CILJit.compileMethod -// * For the 64 bit jit this is implemented by code:PreJit.compileMethod -// -// Note: setTargetOS must be called before this api is used. -CorJitResult compileMethod(ICorJitInfo* comp, /* IN */ - struct CORINFO_METHOD_INFO* info, /* IN */ - unsigned /* code:CorJitFlag */ flags, /* IN */ - uint8_t** nativeEntry, /* OUT */ - uint32_t* nativeSizeOfCode /* OUT */ - ); - -// Do any appropriate work at process shutdown. Default impl is to do nothing. -void ProcessShutdownWork(ICorStaticInfo* info); /* {}; */ - -// The EE asks the JIT for a "version identifier". This represents the version of the JIT/EE interface. -// If the JIT doesn't implement the same JIT/EE interface expected by the EE (because the JIT doesn't -// return the version identifier that the EE expects), then the EE fails to load the JIT. -// -void getVersionIdentifier(GUID* versionIdentifier /* OUT */ - ); - -// Some JIT's may support multiple OSs. This api provides a means to specify to the JIT what OS it should -// be trying to compile. This api does not produce any errors, any errors are to be generated by the -// the compileMethod call, which will call back into the VM to ensure bits are correctly setup. -// -// Note: this api MUST be called before the compileMethod is called for the first time in the process. -void setTargetOS(CORINFO_OS os); -#endif diff --git a/src/coreclr/tools/superpmi/superpmi-shared/icorjithostimpl.h b/src/coreclr/tools/superpmi/superpmi-shared/icorjithostimpl.h deleted file mode 100644 index 2d75683139187b..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/icorjithostimpl.h +++ /dev/null @@ -1,43 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#ifndef _ICorJitHostImpl -#define _ICorJitHostImpl - -// ICorJitHost -// -// ICorJitHost provides the interface that the JIT uses to access some functionality that -// would normally be provided by the operating system. This is intended to allow for -// host-specific policies re: memory allocation, configuration value access, etc. It is -// expected that the `ICorJitHost` value provided to `jitStartup` lives at least as -// long as the JIT itself. - -// ICorJitHostImpl: declare for implementation all the members of the ICorJitHost interface (which are -// specified as pure virtual methods). This is done once, here, and all implementations share it, -// to avoid duplicated declarations. This file is #include'd within all the ICorJitHost implementation -// classes. -// -// NOTE: this file is in exactly the same order, with exactly the same whitespace, as the ICorJitHost -// interface declaration (with the "virtual" and "= 0" syntax removed). This is to make it easy to compare -// against the interface declaration. - -public: -// Allocate memory of the given size in bytes. -void* allocateMemory(size_t size); - -// Frees memory previous obtained by a call to `ICorJitHost::allocateMemory`. -void freeMemory(void* block); - -// Return an integer config value for the given key, if any exists. -int getIntConfigValue(const char* name, int defaultValue); - -// Return a string config value for the given key, if any exists. -const char* getStringConfigValue(const char* name); - -// Free a string ConfigValue returned by the runtime. -// JITs using the getStringConfigValue query are required -// to return the string values to the runtime for deletion. -// This avoids leaking the memory in the JIT. -void freeStringConfigValue(const char* value); - -#endif diff --git a/src/coreclr/tools/superpmi/superpmi-shared/icorjitinfoimpl.h b/src/coreclr/tools/superpmi/superpmi-shared/icorjitinfoimpl.h deleted file mode 100644 index 0c0e42cfa27a4f..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/icorjitinfoimpl.h +++ /dev/null @@ -1,10 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#ifndef _ICorJitInfoImpl -#define _ICorJitInfoImpl - -// This file uses the autogenerated icorjitinfoimpl.h header to define the various methods. -#include "icorjitinfoimpl_generated.h" - -#endif // _ICorJitInfoImpl diff --git a/src/coreclr/tools/superpmi/superpmi-shared/jitmetadatalist.h b/src/coreclr/tools/superpmi/superpmi-shared/jitmetadatalist.h deleted file mode 100644 index f43f4300d73a1a..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/jitmetadatalist.h +++ /dev/null @@ -1 +0,0 @@ -#include "../../../jit/jitmetadatalist.h" diff --git a/src/coreclr/tools/superpmi/superpmi-shared/lightweightmap.h b/src/coreclr/tools/superpmi/superpmi-shared/lightweightmap.h deleted file mode 100644 index 9cad6233ea3543..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/lightweightmap.h +++ /dev/null @@ -1,759 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// LightWeightMap.h - -// Notes: -// improvements: -// 1. we could pack the size down a bit with various encoding tricks (don't use 4 bytes for the numItems etc) -// 2. Add() could find the right place to insert via binary search... though the list is normally very small -// 3. Buffer encoding could easily be more compact -//---------------------------------------------------------- -#ifndef _LightWeightMap -#define _LightWeightMap - -#include "errorhandling.h" - -//#define DEBUG_LWM - -// Common base class that implements the raw buffer functionality. -class LightWeightMapBuffer -{ -public: - LightWeightMapBuffer() - { - InitialClear(); - } - - LightWeightMapBuffer(const LightWeightMapBuffer& lwm) - { - InitialClear(); - bufferLength = lwm.bufferLength; - - if ((lwm.buffer != nullptr) && (lwm.bufferLength > 0)) - { - buffer = new unsigned char[lwm.bufferLength]; - memcpy(buffer, lwm.buffer, lwm.bufferLength); - } - } - - ~LightWeightMapBuffer() - { - delete[] buffer; - } - - unsigned int AddBuffer(const unsigned char* buff, unsigned int len) - { - return AddBuffer(buff, len, false); - } - - unsigned int AddBuffer(const unsigned char* buff, unsigned int len, bool forceUnique) - { - if (len == 0) - return -1; - if (buff == nullptr) - return -1; - int index = Contains(buff, len); // See if there is already a copy of this data in our buffer - if ((index != -1) && (!forceUnique)) - return index; - if (locked) - { - LogError("Added item that extended the buffer after it was locked by a call to GetBuffer()"); - DEBUG_BREAK; - } - - unsigned int newbuffsize = bufferLength + sizeof(unsigned int) + len; - unsigned char* newbuffer = new unsigned char[newbuffsize]; - unsigned int newOffset = bufferLength; - if (bufferLength > 0) - memcpy(newbuffer, buffer, bufferLength); - memcpy(newbuffer + bufferLength + sizeof(unsigned int), buff, len); - *((unsigned int*)(newbuffer + bufferLength)) = len; - bufferLength += sizeof(unsigned int) + len; - if (buffer != nullptr) - delete[] buffer; - buffer = newbuffer; - return newOffset + sizeof(unsigned int); - } - - const unsigned char* CreateBuffer(unsigned int len) - { - if (len == 0) - { - return nullptr; - } - - if (locked) - { - LogError("Added item that extended the buffer after it was locked by a call to GetBuffer()"); - DEBUG_BREAK; - } - - unsigned int newbuffsize = bufferLength + sizeof(unsigned int) + len; - unsigned char* newbuffer = new unsigned char[newbuffsize]; - unsigned int newOffset = bufferLength; - if (bufferLength > 0) - memcpy(newbuffer, buffer, bufferLength); - memset(newbuffer + bufferLength + sizeof(unsigned int), 0, len); - *((unsigned int*)(newbuffer + bufferLength)) = len; - bufferLength += sizeof(unsigned int) + len; - if (buffer != nullptr) - delete[] buffer; - buffer = newbuffer; - return buffer + newOffset + sizeof(unsigned int); - } - - unsigned char* GetBuffer(unsigned int offset) - { - if (offset == (unsigned int)-1) - return nullptr; - AssertCodeMsg(offset < bufferLength, EXCEPTIONCODE_LWM, "Hit offset bigger than bufferLength %u >= %u", offset, - bufferLength); - locked = true; - // LogDebug("Address given %p", &buffer[offset]); - return &buffer[offset]; - } - - int Contains(const unsigned char* buff, unsigned int len) const - { -#ifdef DEBUG_LWM - LogDebug("New call to Contains %d {", len); - for (int i = 0; i < len; i++) - LogDebug("0x%02x ", buff[len]); - LogDebug("}"); -#endif - if (len == 0) - return -1; - if (bufferLength == 0) - return -1; - unsigned int offset = 0; - while ((offset + sizeof(unsigned int) + len) <= bufferLength) - { - unsigned int buffChunkLen = *(unsigned int*)(&buffer[offset]); -#ifdef DEBUG_LWM - LogDebug("Investigating len %d @ %d", buffChunkLen, offset); -#endif - if (buffChunkLen == len) - { -#ifdef DEBUG_LWM - LogDebug("peering into {"); - for (int i = 0; i < len; i++) - LogDebug("0x%02x ", buff[len]); - LogDebug("}"); -#endif - if (memcmp(&buffer[offset + sizeof(unsigned int)], buff, len) == 0) - { -#ifdef DEBUG_LWM - LogDebug("Found!"); -#endif - return offset + sizeof(unsigned int); - } - } - offset += sizeof(unsigned int) + buffChunkLen; - } -#ifdef DEBUG_LWM - LogDebug("NOT Found!"); -#endif - return -1; - } - - void Unlock() - { - locked = false; - } - -protected: - void InitialClear() - { - buffer = nullptr; - bufferLength = 0; - locked = false; - } - - unsigned char* buffer; // TODO-Cleanup: this should really be a linked list; we reallocate it with every call to - // AddBuffer(). - unsigned int bufferLength; - bool locked; -}; - -template -class LightWeightMap : public LightWeightMapBuffer -{ -public: - LightWeightMap() - { - InitialClear(); - } - - LightWeightMap(const LightWeightMap& lwm) - { - InitialClear(); - numItems = lwm.numItems; - strideSize = lwm.strideSize; - bufferLength = lwm.bufferLength; - locked = false; - - pKeys = nullptr; - pItems = nullptr; - - if (lwm.pKeys != nullptr) - { - pKeys = new _Key[numItems]; - memcpy(pKeys, lwm.pKeys, numItems * sizeof(_Key)); - } - if (lwm.pItems != nullptr) - { - pItems = new _Item[numItems]; - memcpy(pItems, lwm.pItems, numItems * sizeof(_Item)); - } - if ((lwm.buffer != nullptr) && (lwm.bufferLength > 0)) - { - buffer = new unsigned char[lwm.bufferLength]; - memcpy(buffer, lwm.buffer, lwm.bufferLength); - } - } - - ~LightWeightMap() - { - if (pKeys != nullptr) - delete[] pKeys; - if (pItems != nullptr) - delete[] pItems; - } - - void ReadFromArray(const unsigned char* rawData, unsigned int size) - { - unsigned int sizeOfKey = sizeof(_Key); - unsigned int sizeOfItem = sizeof(_Item); - const unsigned char* ptr = rawData; - - // The tag is optional, to roll forward previous formats which don't have - // the tag, but which also have the same format. - if (0 == memcmp(ptr, "LWM1", 4)) - { - ptr += 4; - } - - memcpy(&numItems, ptr, sizeof(unsigned int)); - ptr += sizeof(unsigned int); - strideSize = numItems; - - if (numItems > 0) - { - // Read the buffersize - memcpy(&bufferLength, ptr, sizeof(unsigned int)); - ptr += sizeof(unsigned int); - - AssertCodeMsg(pKeys == nullptr, EXCEPTIONCODE_LWM, "Found existing pKeys"); - pKeys = new _Key[numItems]; - // Set the Keys - memcpy(pKeys, ptr, sizeOfKey * numItems); - ptr += sizeOfKey * numItems; - - AssertCodeMsg(pItems == nullptr, EXCEPTIONCODE_LWM, "Found existing pItems"); - pItems = new _Item[numItems]; - // Set the Items - memcpy(pItems, ptr, sizeOfItem * numItems); - ptr += sizeOfItem * numItems; - - AssertCodeMsg(buffer == nullptr, EXCEPTIONCODE_LWM, "Found existing buffer"); - buffer = new unsigned char[bufferLength]; - // Read the buffer - memcpy(buffer, ptr, bufferLength * sizeof(unsigned char)); - ptr += bufferLength * sizeof(unsigned char); - } - - // If we have RTTI, we can make this assert report the correct type. No RTTI, though, when - // built with .NET Core, especially when built against the PAL. - AssertCodeMsg((unsigned int)(ptr - rawData) == size, EXCEPTIONCODE_LWM, "%s - Ended with unexpected sizes %zx != %x", - "Unknown type" /*typeid(_Item).name()*/, ptr - rawData, size); - } - - unsigned int CalculateArraySize() const - { - int size = 4 /* tag */ + sizeof(unsigned int) /* numItems */; - if (numItems > 0) - { - size += sizeof(unsigned int); // size of bufferLength - size += sizeof(_Key) * numItems; // size of keyset - size += sizeof(_Item) * numItems; // size of itemset - size += sizeof(unsigned char) * bufferLength; // bulk size of raw buffer - } - return size; - } - - unsigned int DumpToArray(unsigned char* bytes) - { - unsigned char* ptr = bytes; - unsigned int size = CalculateArraySize(); - - // Write the tag - memcpy(ptr, "LWM1", 4); - ptr += 4; - - // Write the header - memcpy(ptr, &numItems, sizeof(unsigned int)); - ptr += sizeof(unsigned int); - - if (numItems > 0) - { - unsigned int sizeOfKey = sizeof(_Key); - unsigned int sizeOfItem = sizeof(_Item); - - // Write the buffersize - memcpy(ptr, &bufferLength, sizeof(unsigned int)); - ptr += sizeof(unsigned int); - - // Write the Keys - memcpy(ptr, pKeys, sizeOfKey * numItems); - ptr += sizeOfKey * numItems; - - // Write the Items - memcpy(ptr, pItems, sizeOfItem * numItems); - ptr += sizeOfItem * numItems; - - // Write the buffer - memcpy(ptr, buffer, bufferLength * sizeof(unsigned char)); - ptr += bufferLength * sizeof(unsigned char); - } - - // If we have RTTI, we can make this assert report the correct type. No RTTI, though, when - // built with .NET Core, especially when built against the PAL. - AssertCodeMsg(ptr == (bytes + size), EXCEPTIONCODE_LWM, "%s - Ended with unexpected sizes %p != %x", - "Unknown type" /*typeid(_Item).name()*/, (void*)(ptr - bytes), size); - return size; - } - - // It's worth noting that the actual order of insertion here doesnt meet what you might expect. It's using memcmp, so - // since we are on a little endian machine we'd use the lowest 8 bits as the first part of the key. This is - // a side effect of using the same code for large structs and DWORDS etc... - bool Add(_Key key, _Item item) - { - // Make sure we have space left, expand if needed - if (numItems == strideSize) - { - _Key* tKeys = pKeys; - _Item* tItems = pItems; - pKeys = new _Key[(strideSize * 2) + 4]; - memcpy(pKeys, tKeys, strideSize * sizeof(_Key)); - pItems = new _Item[(strideSize * 2) + 4]; - memcpy(pItems, tItems, strideSize * sizeof(_Item)); - strideSize = (strideSize * 2) + 4; - delete[] tKeys; - delete[] tItems; - } - unsigned int insert = 0; - // Find the right place to insert O(n) version - /* for(;insert < numItems; insert++) - { - int res = memcmp(&pKeys[insert], &key, sizeof(_Key)); - if(res == 0) - return false; - if(res>0) - break; - } - */ - // O(log n) version - int first = 0; - int mid = 0; - int last = numItems - 1; - while (first <= last) - { - mid = (first + last) / 2; // compute mid point. - int res = memcmp(&pKeys[mid], &key, sizeof(_Key)); - - if (res < 0) - first = mid + 1; // repeat search in top half. - else if (res > 0) - last = mid - 1; // repeat search in bottom half. - else - { - int resItem = memcmp(&pItems[mid], &item, sizeof(_Item)); - if (resItem != 0) - { - LogDebug("Tried to add a new value for an existing key, the new value was ignored"); - } - return false; // found it. return position ///// - } - } - insert = first; - if (insert != (unsigned int)first) - { - LogDebug("index = %u f %u mid = %u l %u***************************", insert, first, mid, last); - DEBUG_BREAK; - } - - if (numItems > 0) - { - int countToMove = (numItems - insert); - memmove(&pKeys[insert+1], &pKeys[insert], countToMove * sizeof(pKeys[insert])); - memmove(&pItems[insert+1], &pItems[insert], countToMove * sizeof(pItems[insert])); - } - - pKeys[insert] = key; - pItems[insert] = item; - numItems++; - return true; - } - - void Update(int index, _Item item) - { - pItems[index] = item; - } - - int GetIndex(_Key key) const - { - if (numItems == 0) - return -1; - - // O(log n) version - int first = 0; - int mid = 0; - int last = numItems - 1; - while (first <= last) - { - mid = (first + last) / 2; // compute mid point. - int res = memcmp(&pKeys[mid], &key, sizeof(_Key)); - - if (res < 0) - first = mid + 1; // repeat search in top half. - else if (res > 0) - last = mid - 1; // repeat search in bottom half. - else - return mid; // found it. return position ///// - } - return -1; // Didn't find key - } - - _Item GetItem(int index) const - { - AssertCodeMsg(index != -1, EXCEPTIONCODE_LWM, "Didn't find Key"); - return pItems[index]; // found it. return position ///// - } - - _Key GetKey(int index) const - { - AssertCodeMsg(index != -1, EXCEPTIONCODE_LWM, "Didn't find Key (in GetKey)"); - return pKeys[index]; - } - - _Item Get(_Key key) const - { - int index = GetIndex(key); - AssertCodeMsg(index != -1, EXCEPTIONCODE_MC, "Didn't find Item (in Get)"); - return GetItem(index); - } - - _Item* GetRawItems() - { - return pItems; - } - - _Key* GetRawKeys() - { - return pKeys; - } - - unsigned int GetCount() const - { - return numItems; - } - -private: - void InitialClear() - { - numItems = 0; - strideSize = 0; - pKeys = nullptr; - pItems = nullptr; - } - - unsigned int numItems; // Number of active items in the pKeys and pItems arrays. - unsigned int strideSize; // Allocated count of items in the pKeys and pItems arrays. - _Key* pKeys; - _Item* pItems; -}; - -// Second implementation of LightWeightMap where the Key type is an unsigned int in the range [0 .. numItems - 1] (where -// numItems is the number of items stored in the map). Keys are not stored, since the index into the pItems array is -// the key. Appending to the end of the map is O(1), since we don't have to search for it, and we don't have to move -// anything down. - -template -class DenseLightWeightMap : public LightWeightMapBuffer -{ -public: - DenseLightWeightMap() - { - InitialClear(); - } - - DenseLightWeightMap(const DenseLightWeightMap& lwm) - { - InitialClear(); - numItems = lwm.numItems; - strideSize = lwm.strideSize; - bufferLength = lwm.bufferLength; - - if (lwm.pItems != nullptr) - { - pItems = new _Item[numItems]; - memcpy(pItems, lwm.pItems, numItems * sizeof(_Item)); - } - if ((lwm.buffer != nullptr) && (lwm.bufferLength > 0)) - { - buffer = new unsigned char[lwm.bufferLength]; - memcpy(buffer, lwm.buffer, lwm.bufferLength); - } - } - - ~DenseLightWeightMap() - { - if (pItems != nullptr) - delete[] pItems; - } - - void ReadFromArray(const unsigned char* rawData, unsigned int size) - { - unsigned int sizeOfItem = sizeof(_Item); - const unsigned char* ptr = rawData; - - // Check tag; if this is a v1 LWM, convert it to a DenseLightWeightMap in memory - if (0 != memcmp(ptr, "DWM1", 4)) - { - ReadFromArrayAndConvertLWM1(rawData, size); - return; - } - ptr += 4; - - memcpy(&numItems, ptr, sizeof(unsigned int)); - ptr += sizeof(unsigned int); - strideSize = numItems; - - if (numItems > 0) - { - // Read the buffersize - memcpy(&bufferLength, ptr, sizeof(unsigned int)); - ptr += sizeof(unsigned int); - - AssertCodeMsg(pItems == nullptr, EXCEPTIONCODE_LWM, "Found existing pItems"); - pItems = new _Item[numItems]; - // Set the Items - memcpy(pItems, ptr, sizeOfItem * numItems); - ptr += sizeOfItem * numItems; - - AssertCodeMsg(buffer == nullptr, EXCEPTIONCODE_LWM, "Found existing buffer"); - buffer = new unsigned char[bufferLength]; - // Read the buffer - memcpy(buffer, ptr, bufferLength * sizeof(unsigned char)); - ptr += bufferLength * sizeof(unsigned char); - } - - AssertCodeMsg((unsigned int)(ptr - rawData) == size, EXCEPTIONCODE_LWM, "Ended with unexpected sizes %zx != %x", - ptr - rawData, size); - } - -private: - void ReadFromArrayAndConvertLWM1(const unsigned char* rawData, unsigned int size) - { - unsigned int sizeOfKey = sizeof(DWORD); - unsigned int sizeOfItem = sizeof(_Item); - const unsigned char* ptr = rawData; - - memcpy(&numItems, ptr, sizeof(unsigned int)); - ptr += sizeof(unsigned int); - strideSize = numItems; - - if (numItems > 0) - { - // Read the buffersize - memcpy(&bufferLength, ptr, sizeof(unsigned int)); - ptr += sizeof(unsigned int); - - DWORD* tKeys = new DWORD[numItems]; - // Set the Keys - memcpy(tKeys, ptr, sizeOfKey * numItems); - ptr += sizeOfKey * numItems; - - _Item* tItems = new _Item[numItems]; - // Set the Items - memcpy(tItems, ptr, sizeOfItem * numItems); - ptr += sizeOfItem * numItems; - - AssertCodeMsg(buffer == nullptr, EXCEPTIONCODE_LWM, "Found existing buffer"); - buffer = new unsigned char[bufferLength]; - // Read the buffer - memcpy(buffer, ptr, bufferLength * sizeof(unsigned char)); - ptr += bufferLength * sizeof(unsigned char); - - // Convert to new format - AssertCodeMsg(pItems == nullptr, EXCEPTIONCODE_LWM, "Found existing pItems"); - bool* tKeySeen = new bool[numItems]; // Used for assert, below: keys must be unique. - for (unsigned int i = 0; i < numItems; i++) - { - tKeySeen[i] = false; - } - pItems = new _Item[numItems]; - for (unsigned int index = 0; index < numItems; index++) - { - unsigned int key = tKeys[index]; - AssertCodeMsg(key < numItems, EXCEPTIONCODE_LWM, "Illegal key %d, numItems == %d", key, numItems); - AssertCodeMsg(!tKeySeen[key], EXCEPTIONCODE_LWM, "Duplicate key %d", key); - tKeySeen[key] = true; - pItems[key] = tItems[index]; - } - - // Note that if we get here, we've seen every key [0 .. numItems - 1]. - delete[] tKeySeen; - delete[] tKeys; - delete[] tItems; - } - - AssertCodeMsg((unsigned int)(ptr - rawData) == size, EXCEPTIONCODE_LWM, "Ended with unexpected sizes %zx != %x", - ptr - rawData, size); - } - -public: - unsigned int CalculateArraySize() const - { - int size = 4 /* tag */ + sizeof(unsigned int) /* numItems */; - if (numItems > 0) - { - size += sizeof(unsigned int); // size of bufferLength - size += sizeof(_Item) * numItems; // size of itemset - size += sizeof(unsigned char) * bufferLength; // bulk size of raw buffer - } - return size; - } - - unsigned int DumpToArray(unsigned char* bytes) const - { - unsigned char* ptr = bytes; - unsigned int size = CalculateArraySize(); - - // Write the tag - memcpy(ptr, "DWM1", 4); - ptr += 4; - - // Write the header - memcpy(ptr, &numItems, sizeof(unsigned int)); - ptr += sizeof(unsigned int); - - if (numItems > 0) - { - unsigned int sizeOfItem = sizeof(_Item); - - // Write the buffersize - memcpy(ptr, &bufferLength, sizeof(unsigned int)); - ptr += sizeof(unsigned int); - - // Write the Items - memcpy(ptr, pItems, sizeOfItem * numItems); - ptr += sizeOfItem * numItems; - - // Write the buffer - memcpy(ptr, buffer, bufferLength * sizeof(unsigned char)); - ptr += bufferLength * sizeof(unsigned char); - } - - AssertCodeMsg(ptr == (bytes + size), EXCEPTIONCODE_LWM, "Ended with unexpected sizes %zx != %x", ptr - bytes, - size); - return size; - } - - bool Append(_Item item) - { - // Make sure we have space left, expand if needed - if (numItems == strideSize) - { - // NOTE: if this is the first allocation, we'll just allocate 4 items. ok? - _Item* tItems = pItems; - pItems = new _Item[(strideSize * 2) + 4]; - memcpy(pItems, tItems, strideSize * sizeof(_Item)); - strideSize = (strideSize * 2) + 4; - delete[] tItems; - } - - pItems[numItems] = item; - numItems++; - return true; - } - - int GetIndex(unsigned int key) const - { - if (key >= numItems) - return -1; - - return (int)key; - } - - _Item GetItem(int index) const - { - AssertCodeMsg(index != -1, EXCEPTIONCODE_LWM, "Didn't find Key"); - return pItems[index]; // found it. return position ///// - } - - _Item Get(unsigned int key) const - { - int index = GetIndex(key); - return GetItem(index); - } - - _Item* GetRawItems() - { - return pItems; - } - - unsigned int GetCount() const - { - return numItems; - } - -private: - void InitialClear() - { - numItems = 0; - strideSize = 0; - pItems = nullptr; - } - - static int CompareKeys(unsigned int key1, unsigned int key2) - { - if (key1 < key2) - return -1; - else if (key1 > key2) - return 1; - else - return 0; // equal - } - - unsigned int numItems; // Number of active items in the pKeys and pItems arrays. - unsigned int strideSize; // Allocated count of items in the pKeys and pItems arrays. - _Item* pItems; -}; - -#define dumpLWM(ptr, mapName) \ - if (ptr->mapName != nullptr) \ - { \ - printf("%s - %u\n", #mapName, ptr->mapName->GetCount()); \ - for (unsigned int i = 0; i < ptr->mapName->GetCount(); i++) \ - { \ - printf("%u-", i); \ - ptr->dmp##mapName(ptr->mapName->GetRawKeys()[i], ptr->mapName->GetRawItems()[i]); \ - printf("\n"); \ - } \ - } - -#define dumpLWMDense(ptr, mapName) \ - if (ptr->mapName != nullptr) \ - { \ - printf("%s - %u\n", #mapName, ptr->mapName->GetCount()); \ - for (unsigned int i = 0; i < ptr->mapName->GetCount(); i++) \ - { \ - printf("%u-", i); \ - ptr->dmp##mapName(i, ptr->mapName->GetRawItems()[i]); \ - printf("\n"); \ - } \ - } - -#endif // _LightWeightMap diff --git a/src/coreclr/tools/superpmi/superpmi-shared/logging.cpp b/src/coreclr/tools/superpmi/superpmi-shared/logging.cpp deleted file mode 100644 index a0de0cda60d122..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/logging.cpp +++ /dev/null @@ -1,357 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// Logging.cpp - Common logging and console output infrastructure -//---------------------------------------------------------- - -#include "standardpch.h" -#include "logging.h" -#include "errorhandling.h" -#include -#include - -// -// NOTE: Since the logging system is at the core of the error handling infrastructure, any errors -// that occur while logging will print a message to the console. Fatal errors trigger a debugbreak. -// - -bool Logger::s_initialized = false; -UINT32 Logger::s_logLevel = LOGMASK_DEFAULT; -HANDLE Logger::s_logFile = INVALID_HANDLE_VALUE; -char* Logger::s_logFilePath = nullptr; -minipal_mutex Logger::s_critSec; - -// -// Initializes the logging subsystem. This must be called before invoking any of the logging functionality. -// -/* static */ -void Logger::Initialize() -{ - if (!s_initialized) - { - minipal_mutex_init(&s_critSec); - s_initialized = true; - } -} - -// -// Shuts down the logging subsystem, freeing resources, closing handles, and such. -// -/* static */ -void Logger::Shutdown() -{ - if (s_initialized) - { - minipal_mutex_destroy(&s_critSec); - CloseLogFile(); - s_initialized = false; - } -} - -// -// Opens a log file at the given path and enables file-based logging, if the given path is valid. -// -/* static */ -void Logger::OpenLogFile(const char* logFilePath) -{ - if (s_logFile == INVALID_HANDLE_VALUE && logFilePath != nullptr) - { - s_logFile = CreateFileA(logFilePath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); - - if (s_logFile != INVALID_HANDLE_VALUE) - { - // We may need the file path later in order to delete the log file - s_logFilePath = _strdup(logFilePath); - } - else - { - fprintf(stderr, "WARNING: [Logger::OpenLogFile] Failed to open log file '%s'. GetLastError()=%u\n", - logFilePath, GetLastError()); - } - } -} - -// -// Closes the currently open log file, if one is open. -// -/* static */ -void Logger::CloseLogFile() -{ - if (s_logFile != INVALID_HANDLE_VALUE) - { - // Avoid polluting the file system with empty log files - if (GetFileSize(s_logFile, nullptr) == 0 && s_logFilePath != nullptr) - { - // We can call this before closing the handle because remove just marks the file - // for deletion, i.e. it does not actually get deleted until its last handle is closed. - if (remove(s_logFilePath) == -1) - fprintf(stderr, "WARNING: [Logger::CloseLogFile] remove failed. GetLastError()=%u\n", - GetLastError()); - } - - if (!CloseHandle(s_logFile)) - fprintf(stderr, "WARNING: [Logger::CloseLogFile] CloseHandle failed. GetLastError()=%u\n", GetLastError()); - - s_logFile = INVALID_HANDLE_VALUE; - - free(s_logFilePath); - s_logFilePath = nullptr; - } -} - -// -// Returns a bitmask representing the logging levels that are specified by the given string. The string -// format is described explicitly in the command-line usage documentation for SuperPMI and MCS. -// -// In essence, each log level has a corresponding character representing it, and the presence of that -// character in the specifier string indicates that the log mask should include that log level. The -// "quiet" level will override any other level specified: that is, if a "q" is present in the string, -// all other levels specified will be disregarded. -// -// If "q" is not specified, and "a" is specified, then all log levels are enabled. This is a shorthand -// to avoid looking up all the log levels and enabling them all by specifying all the individual characters. -// -/* static */ -UINT32 Logger::ParseLogLevelString(const char* specifierStr) -{ - UINT32 logLevelMask = LOGMASK_NONE; - - if (strchr(specifierStr, 'q') == nullptr) // "Quiet" overrides all other specifiers - { - if (strchr(specifierStr, 'a') != nullptr) // "All" overrides the other specifiers - { - logLevelMask |= LOGMASK_ALL; - } - else - { - if (strchr(specifierStr, 'e') != nullptr) - logLevelMask |= LOGLEVEL_ERROR; - - if (strchr(specifierStr, 'w') != nullptr) - logLevelMask |= LOGLEVEL_WARNING; - - if (strchr(specifierStr, 'm') != nullptr) - logLevelMask |= LOGLEVEL_MISSING; - - if (strchr(specifierStr, 'i') != nullptr) - logLevelMask |= LOGLEVEL_ISSUE; - - if (strchr(specifierStr, 'n') != nullptr) - logLevelMask |= LOGLEVEL_INFO; - - if (strchr(specifierStr, 'v') != nullptr) - logLevelMask |= LOGLEVEL_VERBOSE; - - if (strchr(specifierStr, 'd') != nullptr) - logLevelMask |= LOGLEVEL_DEBUG; - } - } - - return logLevelMask; -} - -/* static */ -void Logger::LogPrintf(const char* function, const char* file, int line, LogLevel level, const char* msg, ...) -{ - va_list argList; - va_start(argList, msg); - LogVprintf(function, file, line, level, argList, msg); -} - -// -// Logs a message, if the given log level is enabled, to both the console and the log file. This is the -// main logging function that all other logging functions eventually funnel into. -// -/* static */ -void Logger::LogVprintf( - const char* function, const char* file, int line, LogLevel level, va_list argList, const char* msg) -{ - if (!s_initialized) - { - fprintf(stderr, "ERROR: [Logger::LogVprintf] Invoked the logging system before initializing it.\n"); - DEBUG_BREAK; - } - - // Early out if we're not logging at this level. - if (!IsPassThrough(level) && ((level & GetLogLevel()) == 0)) - { - return; - } - - // Capture this first to make the timestamp more accurately reflect the actual time of logging - time_t timestamp = time(nullptr); - - int fullMsgLen = _vscprintf(msg, argList) + 1; // This doesn't count the null terminator - char* fullMsg = new char[fullMsgLen]; - - _vsnprintf_s(fullMsg, fullMsgLen, fullMsgLen, msg, argList); - va_end(argList); - - // Where to write messages? Default to stdout. - FILE* dest = stdout; - - const char* logLevelStr = ""; - switch (level) - { - case LOGLEVEL_ERROR: - logLevelStr = "ERROR"; - dest = stderr; - break; - - case LOGLEVEL_WARNING: - logLevelStr = "WARNING"; - dest = stderr; - break; - - case LOGLEVEL_MISSING: - logLevelStr = "MISSING"; - break; - - case LOGLEVEL_ISSUE: - logLevelStr = "ISSUE"; - break; - - case LOGLEVEL_INFO: - logLevelStr = "INFO"; - break; - - case LOGLEVEL_VERBOSE: - logLevelStr = "VERBOSE"; - break; - - case LOGLEVEL_DEBUG: - logLevelStr = "DEBUG"; - break; - - case LOGLEVEL_PASSTHROUGH_STDOUT: - logLevelStr = "STDOUT"; - break; - - case LOGLEVEL_PASSTHROUGH_STDERR: - logLevelStr = "STDERR"; - dest = stderr; - break; - - default: - logLevelStr = "INVALID_LOGLEVEL"; - break; - } - - // NOTE: This implementation doesn't guarantee that log messages will be written in chronological - // order, since Windows doesn't guarantee FIFO behavior when a thread relinquishes a lock. If - // maintaining chronological order is crucial, then we can implement a priority queueing system - // for log messages. - - minipal_mutex_enter(&s_critSec); - - if (level < LOGLEVEL_INFO) - fprintf(dest, "%s: ", logLevelStr); - - fprintf(dest, "%s\n", fullMsg); - - if (s_logFile != INVALID_HANDLE_VALUE) - { -#ifndef TARGET_UNIX // TODO: no localtime_s() or strftime() in PAL - tm timeInfo; - errno_t err = localtime_s(&timeInfo, ×tamp); - if (err != 0) - { - fprintf(stderr, "WARNING: [Logger::LogVprintf] localtime failed with error %d.\n", err); - goto CleanUp; - } - - size_t timeStrBuffSize = 20 * sizeof(char); - char* timeStr = (char*)malloc(timeStrBuffSize); // Use malloc so we can realloc if necessary - - // This particular format string should always generate strings of the same size, but - // for the sake of robustness, we shouldn't rely on that assumption. - while (strftime(timeStr, timeStrBuffSize, "%Y-%m-%d %H:%M:%S", &timeInfo) == 0) - { - timeStrBuffSize *= 2; - timeStr = (char*)realloc(timeStr, timeStrBuffSize); - } -#else // TARGET_UNIX - const char* timeStr = ""; -#endif // TARGET_UNIX - - const char logEntryFmtStr[] = "%s - %s [%s:%d] - %s - %s\r\n"; - size_t logEntryBuffSize = sizeof(logEntryFmtStr) + strlen(timeStr) + strlen(function) + strlen(file) + /* line number */ 10 + - strlen(logLevelStr) + strlen(fullMsg); - - char* logEntry = new char[logEntryBuffSize]; - sprintf_s(logEntry, logEntryBuffSize, logEntryFmtStr, timeStr, function, file, line, logLevelStr, fullMsg); - size_t logEntryLen = strlen(logEntry); - - DWORD bytesWritten; - - if (!WriteFile(s_logFile, logEntry, (DWORD)logEntryLen, &bytesWritten, nullptr)) - fprintf(stderr, "WARNING: [Logger::LogVprintf] Failed to write to log file. GetLastError()=%u\n", - GetLastError()); - - if (!FlushFileBuffers(s_logFile)) - fprintf(stderr, "WARNING: [Logger::LogVprintf] Failed to flush log file. GetLastError()=%u\n", - GetLastError()); - - delete[] logEntry; - -#ifndef TARGET_UNIX - free((void*)timeStr); -#endif // !TARGET_UNIX - } - -#ifndef TARGET_UNIX -CleanUp: -#endif // !TARGET_UNIX - - minipal_mutex_leave(&s_critSec); - delete[] fullMsg; -} - -// -// Special helper for logging exceptions. This logs the exception message given as a debug message. -// -/* static */ -void Logger::LogExceptionMessage( - const char* function, const char* file, int line, DWORD exceptionCode, const char* msg, ...) -{ - std::string fullMsg = "Exception thrown: "; - fullMsg += msg; - - va_list argList; - va_start(argList, msg); - LogVprintf(function, file, line, LOGLEVEL_DEBUG, argList, fullMsg.c_str()); -} - -// -// Logger for JIT issues. Identifies the issue type and logs the given message normally. -// -/* static */ -void IssueLogger::LogIssueHelper( - const char* function, const char* file, int line, IssueType issue, const char* msg, ...) -{ - std::string fullMsg; - - switch (issue) - { - case ISSUE_ASSERT: - fullMsg += ""; - break; - - case ISSUE_ASM_DIFF: - fullMsg += ""; - break; - - default: - fullMsg += ""; - break; - } - - fullMsg += " "; - fullMsg += msg; - - va_list argList; - va_start(argList, msg); - Logger::LogVprintf(function, file, line, LOGLEVEL_ISSUE, argList, fullMsg.c_str()); -} diff --git a/src/coreclr/tools/superpmi/superpmi-shared/logging.h b/src/coreclr/tools/superpmi/superpmi-shared/logging.h deleted file mode 100644 index 83559df9befdbf..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/logging.h +++ /dev/null @@ -1,123 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// Logging.h - Common logging and console output infrastructure -//---------------------------------------------------------- -#ifndef _Logging -#define _Logging - -#include - -// -// General purpose logging macros -// - -#define LogMessage(level, ...) Logger::LogPrintf(__func__, __FILE__, __LINE__, level, __VA_ARGS__) - -#define LogError(...) LogMessage(LOGLEVEL_ERROR, __VA_ARGS__) -#define LogWarning(...) LogMessage(LOGLEVEL_WARNING, __VA_ARGS__) -#define LogMissing(...) LogMessage(LOGLEVEL_MISSING, __VA_ARGS__) -#define LogInfo(...) LogMessage(LOGLEVEL_INFO, __VA_ARGS__) -#define LogVerbose(...) LogMessage(LOGLEVEL_VERBOSE, __VA_ARGS__) -#define LogDebug(...) LogMessage(LOGLEVEL_DEBUG, __VA_ARGS__) - -#define LogPassThroughStdout(...) LogMessage(LOGLEVEL_PASSTHROUGH_STDOUT, __VA_ARGS__) -#define LogPassThroughStderr(...) LogMessage(LOGLEVEL_PASSTHROUGH_STDERR, __VA_ARGS__) - -#define LogIssue(issue, msg, ...) IssueLogger::LogIssueHelper(__FUNCTION__, __FILE__, __LINE__, issue, msg, __VA_ARGS__) - -// Captures the exception message before throwing so we can log it at the point of occurrence -#define LogException(exCode, msg, ...) \ - do \ - { \ - Logger::LogExceptionMessage(__FUNCTION__, __FILE__, __LINE__, exCode, msg, __VA_ARGS__); \ - ThrowSpmiException(exCode, msg, __VA_ARGS__); \ - } while (0) - -// These are specified as flags so subsets of the logging functionality can be enabled/disabled at once -enum LogLevel : UINT32 -{ - LOGLEVEL_ERROR = 0x00000001, // Internal fatal errors that are non-recoverable - LOGLEVEL_WARNING = 0x00000002, // Internal conditions that are unusual, but not serious - LOGLEVEL_MISSING = 0x00000004, // Failures to due to missing JIT-EE details - LOGLEVEL_ISSUE = 0x00000008, // Issues found with the JIT, e.g. asm diffs, asserts - LOGLEVEL_INFO = 0x00000010, // Notifications/summaries, e.g. 'Loaded 5 Jitted 4 FailedCompile 1' - LOGLEVEL_VERBOSE = 0x00000020, // Status messages, e.g. 'Jit startup took 151.12ms' - LOGLEVEL_DEBUG = 0x00000040, // Detailed output that's only useful for SuperPMI debugging - LOGLEVEL_PASSTHROUGH_STDOUT = 0x00000080, // Special: pass through parallel SuperPMI stdout - LOGLEVEL_PASSTHROUGH_STDERR = 0x00000100 // Special: pass through parallel SuperPMI stderr -}; - -// Preset log level combinations -enum LogLevelMask : UINT32 -{ - LOGMASK_NONE = 0x00000000, - LOGMASK_DEFAULT = (LOGLEVEL_DEBUG - 1), // Default is essentially "enable everything except debug" - LOGMASK_ALL = 0xffffffff -}; - -// -// Manages the SuperPMI logging subsystem, including both file-based logging and logging to the console. -// -class Logger -{ -private: - static bool s_initialized; - static UINT32 s_logLevel; - static HANDLE s_logFile; - static char* s_logFilePath; - static minipal_mutex s_critSec; - -public: - static void Initialize(); - static void Shutdown(); - - static void OpenLogFile(const char* logFilePath); - static void CloseLogFile(); - - static UINT32 ParseLogLevelString(const char* specifierStr); - static void SetLogLevel(UINT32 logLevelMask) - { - s_logLevel = logLevelMask; - } - static UINT32 GetLogLevel() - { - return s_logLevel; - } - static bool IsPassThrough(LogLevel level) - { - return (level == LOGLEVEL_PASSTHROUGH_STDOUT) || (level == LOGLEVEL_PASSTHROUGH_STDERR); - } - - // Return true if all specified log levels are enabled. - static bool IsLogLevelEnabled(UINT32 logLevelMask) - { - return (logLevelMask & GetLogLevel()) == logLevelMask; - } - - static void LogPrintf(const char* function, const char* file, int line, LogLevel level, const char* msg, ...); - static void LogVprintf( - const char* function, const char* file, int line, LogLevel level, va_list argList, const char* msg); - static void LogExceptionMessage( - const char* function, const char* file, int line, DWORD exceptionCode, const char* msg, ...); -}; - -enum IssueType -{ - ISSUE_ASSERT, - ISSUE_ASM_DIFF -}; - -// -// JIT issues have more granularity than other types of log messages. The logging of issues is abstracted -// from the normal logger to reflect this. It also will enable us to track things specific to JIT issues, -// like statistics on issues that were found during a run. -// -class IssueLogger -{ -public: - static void LogIssueHelper(const char* function, const char* file, int line, IssueType issue, const char* msg, ...); -}; - -#endif diff --git a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h deleted file mode 100644 index f870fb7f648e0d..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h +++ /dev/null @@ -1,183 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// lwmlist.h - List of all LightWeightMap in MethodContext. -// To use, #define LWM(map, key, value) to something. -// If you need to distinguish DenseLightWeightMap, #define DENSELWM(map, value) as well. -//---------------------------------------------------------- - -#ifndef LWM -#error Define LWM before including this file. -#endif - -// If the key is needed, then DENSELWM must be defined. -#ifndef DENSELWM -#define DENSELWM(map, value) LWM(map, this_is_an_error, value) -#endif - -LWM(AllocPgoInstrumentationBySchema, DWORDLONG, Agnostic_AllocPgoInstrumentationBySchema) -LWM(GetPgoInstrumentationResults, DWORDLONG, Agnostic_GetPgoInstrumentationResults) -LWM(AsCorInfoType, DWORDLONG, DWORD) -LWM(CanAccessClass, Agnostic_CanAccessClassIn, Agnostic_CanAccessClassOut) -LWM(CanCast, DLDL, DWORD) -LWM(CanInline, DLDL, Agnostic_CanInline) -LWM(CanTailCall, Agnostic_CanTailCall, DWORD) -LWM(CheckMethodModifier, Agnostic_CheckMethodModifier, DWORD) -LWM(CompareTypesForCast, DLDL, DWORD) -LWM(CompareTypesForEquality, DLDL, DWORD) -LWM(CompileMethod, DWORD, Agnostic_CompileMethod) -LWM(ConstructStringLiteral, DLD, DLD) -LWM(ConvertPInvokeCalliToCall, DLD, DLDL) -LWM(EmbedClassHandle, DWORDLONG, DLDL) -LWM(EmbedFieldHandle, DWORDLONG, DLDL) -LWM(EmbedGenericHandle, Agnostic_EmbedGenericHandle, Agnostic_CORINFO_GENERICHANDLE_RESULT) -LWM(EmbedMethodHandle, DWORDLONG, DLDL) -LWM(EmbedModuleHandle, DWORDLONG, DLDL) -LWM(GetThreadLocalFieldInfo, DLD, DWORD) -LWM(GetThreadLocalStaticBlocksInfo, DWORD, Agnostic_GetThreadLocalStaticBlocksInfo) -LWM(GetThreadLocalStaticInfo_NativeAOT, DWORDLONG, Agnostic_GetThreadStaticInfo_NativeAOT) -DENSELWM(EmptyStringLiteral, DLD) -DENSELWM(ErrorList, DWORD) -LWM(FindCallSiteSig, Agnostic_FindCallSiteSig, Agnostic_CORINFO_SIG_INFO) -LWM(FindSig, Agnostic_FindSig, Agnostic_CORINFO_SIG_INFO) -LWM(GetAddressOfPInvokeTarget, DWORDLONG, DLD) -LWM(GetAddrOfCaptureThreadGlobal, DWORD, DLDL) -LWM(GetArgClass, Agnostic_GetArgClass_Key, Agnostic_GetArgClass_Value) -LWM(GetArgNext, DWORDLONG, DWORDLONG) -LWM(GetArgType, Agnostic_GetArgType_Key, Agnostic_GetArgType_Value) -LWM(GetExactClasses, DLD, Agnostic_GetExactClassesResult) -LWM(GetArrayInitializationData, DLD, DWORDLONG) -LWM(GetArrayRank, DWORDLONG, DWORD) -LWM(GetArrayIntrinsicID, DWORDLONG, DWORD) -LWM(GetBoundaries, DWORDLONG, Agnostic_GetBoundaries) -LWM(GetBoxHelper, DWORDLONG, DWORD) -LWM(GetBuiltinClass, DWORD, DWORDLONG) -LWM(GetCallInfo, Agnostic_GetCallInfo, Agnostic_CORINFO_CALL_INFO) -LWM(GetCastingHelper, Agnostic_GetCastingHelper, DWORD) -LWM(GetChildType, DWORDLONG, DLD) -LWM(GetClassAlignmentRequirement, DLD, DWORD) -LWM(GetClassAttribs, DWORDLONG, DWORD) -LWM(GetClassStaticDynamicInfo, DWORDLONG, DLD) -LWM(GetClassThreadStaticDynamicInfo, DWORDLONG, DLD) -LWM(GetClassGClayout, DWORDLONG, Agnostic_GetClassGClayout) -LWM(GetClassModuleIdForStatics, DWORDLONG, Agnostic_GetClassModuleIdForStatics) -LWM(GetIsClassInitedFlagAddress, DWORDLONG, Agnostic_GetIsClassInitedFlagAddress) -LWM(GetStaticBaseAddress, DLD, Agnostic_GetStaticBaseAddress) -LWM(GetClassNameFromMetadata, DLD, DD) -LWM(GetTypeInstantiationArgument, DLD, DWORDLONG) -LWM(GetMethodInstantiationArgument, DLD, DWORDLONG) -LWM(GetClassNumInstanceFields, DWORDLONG, DWORD) -LWM(GetClassSize, DWORDLONG, DWORD) -LWM(GetHeapClassSize, DWORDLONG, DWORD) -LWM(CanAllocateOnStack, DWORDLONG, DWORD) -LWM(GetCookieForInterpreterCalliSig, GetCookieForInterpreterCalliSigValue, DLDL) -LWM(GetDefaultComparerClass, DWORDLONG, DWORDLONG) -LWM(GetDefaultEqualityComparerClass, DWORDLONG, DWORDLONG) -LWM(GetSZArrayHelperEnumeratorClass, DWORDLONG, DWORDLONG) -LWM(GetDelegateCtor, Agnostic_GetDelegateCtorIn, Agnostic_GetDelegateCtorOut) -LWM(GetEEInfo, DWORD, Agnostic_CORINFO_EE_INFO) -LWM(GetAsyncInfo, DWORD, Agnostic_CORINFO_ASYNC_INFO) -LWM(GetAwaitReturnCall, DWORDLONG, Agnostic_GetAwaitReturnCallResult) -LWM(GetAwaitAwaiterInContinuationCall, Agnostic_GetAwaitAwaiterInContinuationCall, Agnostic_GetAwaitReturnCallResult) -LWM(GetEHinfo, DLD, Agnostic_CORINFO_EH_CLAUSE) -LWM(GetStaticFieldContent, DLDDD, DD) -LWM(GetObjectContent, DLDD, DD) -LWM(GetStaticFieldCurrentClass, DLD, Agnostic_GetStaticFieldCurrentClass) -LWM(GetFieldClass, DWORDLONG, DWORDLONG) -LWM(GetFieldInClass, DLD, DWORDLONG) -LWM(GetTypeLayout, DWORDLONG, Agnostic_GetTypeLayoutResult) -LWM(GetFieldInfo, Agnostic_GetFieldInfo, Agnostic_CORINFO_FIELD_INFO) -LWM(GetFieldOffset, DWORDLONG, DWORD) -LWM(GetFieldThreadLocalStoreID, DWORDLONG, DLD) -LWM(GetFieldType, DLDL, DLD) -LWM(GetFunctionEntryPoint, DLD, DLD) -LWM(GetFunctionFixedEntryPoint, DWORDLONG, Agnostic_CORINFO_CONST_LOOKUP) -LWM(GetGSCookie, DWORD, DLDL) -LWM(GetHelperFtn, DWORD, Agnostic_GetHelperFtn) -LWM(GetHFAType, DWORDLONG, DWORD) -LWM(GetIntConfigValue, Agnostic_ConfigIntInfo, DWORD) -LWM(GetJitFlags, DWORD, DD) -LWM(GetJustMyCodeHandle, DWORDLONG, DLDL) -LWM(GetLocationOfThisType, DWORDLONG, Agnostic_CORINFO_LOOKUP_KIND) -LWM(IsIntrinsic, DWORDLONG, DWORD) -LWM(NotifyMethodInfoUsage, DWORDLONG, DWORD) -LWM(NotifyInstructionSetUsage, DD, DWORD) -LWM(GetMethodAttribs, DWORDLONG, DWORD) -LWM(GetClassAssemblyName, DWORDLONG, DWORD) -LWM(GetMethodClass, DWORDLONG, DWORDLONG) -LWM(GetMethodDefFromMethod, DWORDLONG, DWORD) -LWM(GetMethodHash, DWORDLONG, DWORD) -LWM(GetMethodInfo, DLDL, Agnostic_GetMethodInfo) -LWM(HaveSameMethodDefinition, DLDL, DWORD) -LWM(GetTypeDefinition, DWORDLONG, DWORDLONG) -LWM(GetMethodNameFromMetadata, Agnostic_CORINFO_METHODNAME_TOKENin, Agnostic_CORINFO_METHODNAME_TOKENout) -LWM(GetMethodSig, DLDL, Agnostic_CORINFO_SIG_INFO) -LWM(GetMethodVTableOffset, DWORDLONG, DDD) -LWM(GetNewArrHelper, DWORDLONG, DWORD) -LWM(GetNewHelper, DWORDLONG, DDD) -LWM(GetOSRInfo, DWORD, Agnostic_GetOSRInfo) -LWM(GetParentType, DWORDLONG, DWORDLONG) -LWM(GetProfilingHandle, DWORD, Agnostic_GetProfilingHandle) -LWM(GetReadyToRunHelper, GetReadyToRunHelper_TOKENin, GetReadyToRunHelper_TOKENout) -LWM(GetReadyToRunDelegateCtorHelper, GetReadyToRunDelegateCtorHelper_TOKENIn, Agnostic_CORINFO_LOOKUP) -LWM(GetRelocTypeHint, DWORDLONG, DWORD) -LWM(GetExpectedTargetArchitecture, DWORD, DWORD) -LWM(GetSharedCCtorHelper, DWORDLONG, DWORD) -LWM(GetStringConfigValue, DWORD, DWORD) -LWM(GetSystemVAmd64PassStructInRegisterDescriptor, DWORDLONG, Agnostic_GetSystemVAmd64PassStructInRegisterDescriptor) -LWM(GetSwiftLowering, DWORDLONG, Agnostic_GetSwiftLowering) -LWM(GetFpStructLowering, DWORDLONG, Agnostic_GetFpStructLowering) -LWM(GetWasmLowering, DWORDLONG, DWORD) -LWM(GetTailCallHelpers, Agnostic_GetTailCallHelpers, Agnostic_CORINFO_TAILCALL_HELPERS) -LWM(GetAsyncResumptionStub, DWORD, DLDL) -LWM(GetContinuationType, Agnostic_GetContinuationTypeIn, DWORDLONG) -LWM(UpdateEntryPointForTailCall, Agnostic_CORINFO_CONST_LOOKUP, Agnostic_CORINFO_CONST_LOOKUP) -LWM(GetSpecialCopyHelper, DWORDLONG, DWORDLONG) -LWM(GetThreadTLSIndex, DWORD, DLD) -LWM(GetTokenTypeAsHandle, GetTokenTypeAsHandleValue, DWORDLONG) -LWM(GetTypeForBox, DWORDLONG, DWORDLONG) -LWM(GetTypeForPrimitiveValueClass, DWORDLONG, DWORD) -LWM(GetTypeForPrimitiveNumericClass, DWORDLONG, DWORD) -LWM(GetAsyncOtherVariant, DWORDLONG, DLD); -LWM(GetUnBoxHelper, DWORDLONG, DWORD) -LWM(GetRuntimeTypePointer, DWORDLONG, DWORDLONG) -LWM(IsObjectImmutable, DWORDLONG, DWORD) -LWM(GetStringChar, DLD, DD) -LWM(GetObjectType, DWORDLONG, DWORDLONG) -LWM(GetVarArgsHandle, GetVarArgsHandleValue, DLDL) -LWM(GetVars, DWORDLONG, Agnostic_GetVars) -LWM(InitClass, Agnostic_InitClass, DWORD) -LWM(IsDelegateCreationAllowed, DLDL, DWORD) -LWM(IsFieldStatic, DWORDLONG, DWORD) -LWM(GetArrayOrStringLength, DWORDLONG, DWORD) -LWM(ExpandRawHandleIntrinsic, Agnostic_ExpandRawHandleIntrinsic, Agnostic_CORINFO_GENERICHANDLE_RESULT) -LWM(IsIntrinsicType, DWORDLONG, DWORD) -LWM(IsSDArray, DWORDLONG, DWORD) -LWM(GetStringLiteral, DLDDD, DD) -LWM(PrintObjectDescription, DWORDLONG, Agnostic_PrintResult) -LWM(PrintClassName, DWORDLONG, Agnostic_PrintResult) -LWM(PrintFieldName, DWORDLONG, Agnostic_PrintResult) -LWM(PrintMethodName, DWORDLONG, Agnostic_PrintResult) -LWM(IsValueClass, DWORDLONG, DWORD) -LWM(IsMoreSpecificType, DLDL, DWORD) -LWM(IsExactType, DWORDLONG, DWORD) -LWM(IsGenericType, DWORDLONG, DWORD) -LWM(IsNullableType, DWORDLONG, DWORD) -LWM(IsEnum, DWORDLONG, DLD) -LWM(PInvokeMarshalingRequired, MethodOrSigInfoValue, DWORD) -LWM(ResolveToken, Agnostic_CORINFO_RESOLVED_TOKENin, ResolveTokenValue) -LWM(ResolveVirtualMethod, Agnostic_ResolveVirtualMethodKey, Agnostic_ResolveVirtualMethodResult) -LWM(SatisfiesMethodConstraints, DLDL, DWORD) -LWM(GetUnmanagedCallConv, MethodOrSigInfoValue, DD) -LWM(DoesFieldBelongToClass, DLDL, DWORD) -DENSELWM(SigInstHandleMap, DWORDLONG) -LWM(GetWasmTypeSymbol, Agnostic_GetWasmTypeSymbol, DWORDLONG) -LWM(GetAddressAlignment, DWORDLONG, DWORD) -LWM(CanValueClassInstancePointerEscape, DWORDLONG, DWORD) -LWM(GetWasmWellKnownGlobals, DWORD, Agnostic_CORINFO_WASM_WELLKNOWN_GLOBALS) -LWM(IsByRefLike, DWORDLONG, DWORD) -LWM(IsSharedInst, DWORDLONG, DWORD) - -#undef LWM -#undef DENSELWM diff --git a/src/coreclr/tools/superpmi/superpmi-shared/mclist.cpp b/src/coreclr/tools/superpmi/superpmi-shared/mclist.cpp deleted file mode 100644 index 79dca0cdc766ae..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/mclist.cpp +++ /dev/null @@ -1,257 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// MCList.h - MethodContext List utility class -//---------------------------------------------------------- - -#include "standardpch.h" -#include "mclist.h" -#include "logging.h" - -bool MCList::processArgAsMCL(char* input, int* count, int** list) -{ - // If it contains only '0-9', '-', ',' try to see it as a range list, else try to load as a file - bool isRangeList = true; - - size_t len = strlen(input); - - for (size_t i = 0; (i < len) && isRangeList; i++) - { - if ((input[i] != '-') && (input[i] != ',') && (!isdigit((unsigned char)input[i]))) - isRangeList = false; - } - - if (isRangeList) - { - // Count items - *count = 0; - unsigned rangeStart = 0; - bool inRange = false; - unsigned scratch = 0; - bool foundDigit = false; - - char* tail = input + len; - - for (char* head = input; head <= tail; head++) - { - scratch = 0; - foundDigit = false; - while ((head <= tail) && (isdigit((unsigned char)*head))) - { - scratch = (scratch * 10) + ((*head) - '0'); - foundDigit = true; - head++; - } - if (foundDigit) - { - if (inRange) - { - inRange = false; - if (rangeStart >= scratch) - { - LogError("Invalid range in '%s'", input); - return false; - } - (*count) += scratch - rangeStart; - } - else - { - rangeStart = scratch; - (*count)++; - } - } - if (*head == '-') - inRange = true; - } - - if (*count == 0) - { - LogError("Didn't find a list!"); - return false; - } - - inRange = false; - rangeStart = 0; - - int* ll = new int[*count]; - *list = ll; - int index = 0; - ll[index] = 0; - - for (char* head = input; head <= tail; head++) - { - scratch = 0; - foundDigit = false; - while ((head <= tail) && (isdigit((unsigned char)*head))) - { - scratch = (scratch * 10) + ((*head) - '0'); - foundDigit = true; - head++; - } - if (foundDigit) - { - if (inRange) - { - inRange = false; - for (unsigned int i = rangeStart + 1; i <= scratch; i++) - ll[index++] = i; - } - else - { - rangeStart = scratch; - ll[index++] = scratch; - } - } - if (*head == '-') - inRange = true; - } - if (inRange) - { - LogError("Found invalid external range in '%s'", input); - return false; - } - goto checkMCL; - } - else - { - char* lastdot = strrchr(input, '.'); - if (lastdot != nullptr && _stricmp(lastdot, ".mcl") == 0) - { - // Read MCLFile - if (!getLineData(input, count, list)) - return false; - if (*count >= 0) - goto checkMCL; - } - return false; - } - -checkMCL: // check that mcl list is increasing only - int* ll = (*list); - if (ll[0] == 0) - { - LogError("MCL list needs to start from 1!"); - return false; - } - for (int i = 1; i < *count; i++) - { - if (ll[i - 1] >= ll[i]) - { - LogError("MCL list must be increasing.. found %d -> %d", ll[i - 1], ll[i]); - return false; - } - } - return true; -} - -// Returns true on success, false on failure. -// On success, sets *pIndexCount to the number of indices read, and *pIndexes to a new array with all the indices read. -// The caller must free the memory with delete[]. -/* static */ -bool MCList::getLineData(const char* nameOfInput, /* OUT */ int* pIndexCount, /* OUT */ int** pIndexes) -{ - HANDLE hFile = CreateFileA(nameOfInput, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); - if (hFile == INVALID_HANDLE_VALUE) - { - LogError("Unable to open '%s'. GetLastError()=%u", nameOfInput, GetLastError()); - return false; - } - LARGE_INTEGER DataTemp; - if (!GetFileSizeEx(hFile, &DataTemp)) - { - LogError("GetFileSizeEx failed. GetLastError()=%u", GetLastError()); - return false; - } - - if (DataTemp.QuadPart > MAXMCLFILESIZE) - { - LogError("Size %d exceeds max size of %d", DataTemp.QuadPart, MAXMCLFILESIZE); - return false; - } - - int sz = DataTemp.u.LowPart; - char* buff = new char[sz]; - DWORD bytesRead; - if (ReadFile(hFile, buff, sz, &bytesRead, nullptr) == 0) - { - LogError("ReadFile failed. GetLastError()=%u", GetLastError()); - delete[] buff; - return false; - } - if (!CloseHandle(hFile)) - { - LogError("CloseHandle failed. GetLastError()=%u", GetLastError()); - delete[] buff; - return false; - } - - // Count the lines. Note that the last line better be terminated by a newline. - int lineCount = 0; - for (int i = 0; i < sz; i++) - { - if (buff[i] == '\n') - { - lineCount++; - } - } - - int* indexes = new int[lineCount]; - int indexCount = 0; - int i = 0; - while (i < sz) - { - // seek the first number on the line. This will skip empty lines and lines with no digits. - while (!isdigit((unsigned char)buff[i])) - i++; - // read in the number - indexes[indexCount++] = atoi(&buff[i]); - // seek to the start of next line - while ((i < sz) && (buff[i] != '\n')) - i++; - i++; - } - delete[] buff; - - *pIndexCount = indexCount; - *pIndexes = indexes; - return true; -} - -void MCList::InitializeMCL(char* filename) -{ - hMCLFile = CreateFileA(filename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (hMCLFile == INVALID_HANDLE_VALUE) - { - LogError("Failed to open output file '%s'. GetLastError()=%u", filename, GetLastError()); - } -} - -void MCList::AddMethodToMCL(int methodIndex) -{ - if (hMCLFile != INVALID_HANDLE_VALUE) - { - char strMethodIndex[12]; - DWORD charCount = 0; - DWORD bytesWritten = 0; - - charCount = sprintf_s(strMethodIndex, sizeof(strMethodIndex), "%d\r\n", methodIndex); - - if (!WriteFile(hMCLFile, strMethodIndex, charCount, &bytesWritten, nullptr) || bytesWritten != charCount) - { - LogError("Failed to write method index '%d'. GetLastError()=%u", strMethodIndex, GetLastError()); - } - } -} - -void MCList::CloseMCL() -{ - if (hMCLFile != INVALID_HANDLE_VALUE) - { - if (CloseHandle(hMCLFile) == 0) - { - LogError("CloseHandle failed. GetLastError()=%u", GetLastError()); - } - } -} diff --git a/src/coreclr/tools/superpmi/superpmi-shared/mclist.h b/src/coreclr/tools/superpmi/superpmi-shared/mclist.h deleted file mode 100644 index 44291f0600a0e0..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/mclist.h +++ /dev/null @@ -1,33 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// MCList.h - MethodContext List utility class -//---------------------------------------------------------- -#ifndef _MCList -#define _MCList -#define MAXMCLFILESIZE 0xFFFFFF - -class MCList -{ -public: - static bool processArgAsMCL(char* input, int* count, int** list); - - MCList() - { - // Initialize the static file handle - hMCLFile = INVALID_HANDLE_VALUE; - } - - // Methods to create an MCL file - void InitializeMCL(char* filename); - void AddMethodToMCL(int methodIndex); - void CloseMCL(); - -private: - static bool getLineData(const char* nameOfInput, /* OUT */ int* pIndexCount, /* OUT */ int** pIndexes); - - // File handle for MCL file - HANDLE hMCLFile; -}; -#endif diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp deleted file mode 100644 index d28b1bd0063270..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ /dev/null @@ -1,7916 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// MethodContext.cpp - Primary structure to store all the EE-JIT details required to replay creation of a method -// CompileResult contains the stuff generated by a compilation -//---------------------------------------------------------- - -#include "standardpch.h" -#include "methodcontext.h" -#include "compileresult.h" -#include "lightweightmap.h" -#include "callutils.h" -#include "spmirecordhelper.h" -#include "spmidumphelper.h" -#include "spmiutil.h" - -#define sparseMC // Support filling in details where guesses are okay and will still generate good code. (i.e. helper - // function addresses) - -MethodContext::MethodContext() -{ - methodSize = 0; - -#define LWM(map, key, value) map = nullptr; -#include "lwmlist.h" - - cr = new CompileResult(); - index = -1; - ignoreStoredConfig = false; -} - -MethodContext::~MethodContext() -{ - Destroy(); -} - -void MethodContext::Destroy() -{ -#define LWM(map, key, value) \ - if (map != nullptr) \ - delete map; -#include "lwmlist.h" - - delete cr; - FreeTempAllocations(); -} - -#define sparseAddLen(target) \ - if (target != nullptr) \ - { \ - if (target->GetCount() != 0) \ - totalLen += target->CalculateArraySize() + 6; /* packet canary from lightweightmap + packet marker */ \ - } - -#define sparseWriteFile(target) \ - if (target != nullptr) \ - { \ - if (target->GetCount() != 0) \ - { \ - buff2[buffIndex++] = (unsigned char)Packet_##target; \ - unsigned int loc = target->DumpToArray(&buff2[buffIndex + 4]); \ - memcpy(&buff2[buffIndex], &loc, sizeof(unsigned int)); \ - buffIndex += 4 + loc; \ - buff2[buffIndex++] = 0x42; \ - } \ - } - -#define sparseWriteFileCR(target) \ - if (cr != nullptr) \ - { \ - if (cr->target != nullptr) \ - { \ - if (cr->target->GetCount() != 0) \ - { \ - buff2[buffIndex++] = (unsigned char)PacketCR_##target; \ - unsigned int loc = cr->target->DumpToArray(&buff2[buffIndex + 4]); \ - memcpy(&buff2[buffIndex], &loc, sizeof(unsigned int)); \ - buffIndex += 4 + loc; \ - buff2[buffIndex++] = 0x42; \ - } \ - } \ - } - -#define sparseReadFile(target, key, value) \ - case Packet_##target: \ - { \ - target = new LightWeightMap(); \ - target->ReadFromArray(&buff2[buffIndex], localsize); \ - break; \ - } - -#define sparseReadFileCR(target, key, value, readCompileResults) \ - case PacketCR_##target: \ - { \ - if (readCompileResults) \ - { \ - cr->target = new LightWeightMap(); \ - cr->target->ReadFromArray(&buff2[buffIndex], localsize); \ - } \ - break; \ - } - -#define sparseReadFileDense(target, value) \ - case Packet_##target: \ - { \ - target = new DenseLightWeightMap(); \ - target->ReadFromArray(&buff2[buffIndex], localsize); \ - break; \ - } - -#define sparseReadFileCRDense(target, value, readCompileResults) \ - case PacketCR_##target: \ - { \ - if (readCompileResults) \ - { \ - cr->target = new DenseLightWeightMap(); \ - cr->target->ReadFromArray(&buff2[buffIndex], localsize); \ - } \ - break; \ - } - -unsigned int MethodContext::calculateFileSize() -{ - // Calculate file size - unsigned int totalLen = 0; - -#define LWM(map, key, value) sparseAddLen(map) -#include "lwmlist.h" - - // Compile Result members - if (cr != nullptr) - { -#define LWM(map, key, value) sparseAddLen(cr->map); -#include "crlwmlist.h" - } - - return totalLen; -} - -unsigned int MethodContext::calculateRawFileSize() -{ - return 2 /* leading magic cookie 'm', 'c' */ + 4 /* 4-byte data length */ + calculateFileSize() + - 2 /* end canary '4', '2' */; -} - -unsigned int MethodContext::saveToFile(HANDLE hFile) -{ - unsigned int totalLen = calculateFileSize(); - unsigned int totalFileSize = - 2 /* leading magic cookie 'm', 'c' */ + 4 /* 4-byte data length */ + totalLen + 2 /* end canary '4', '2' */; - - DWORD bytesWritten = 0; - unsigned int buffIndex = 0; - unsigned char* buff2 = new unsigned char[totalFileSize]; - buff2[buffIndex++] = 'm'; - buff2[buffIndex++] = 'c'; - memcpy(&buff2[buffIndex], &totalLen, sizeof(unsigned int)); - buffIndex += 4; - -#define LWM(map, key, value) sparseWriteFile(map) -#include "lwmlist.h" - -// Compile Result members -#define LWM(map, key, value) sparseWriteFileCR(map); -#include "crlwmlist.h" - - // Write the end canary - buff2[buffIndex++] = '4'; - buff2[buffIndex++] = '2'; - - Assert(buffIndex == totalFileSize); - - WriteFile(hFile, buff2, totalFileSize, &bytesWritten, NULL); - delete[] buff2; - return bytesWritten; -} - -// This code can't exist in a function with C++ objects needing destruction. Returns true on success -// (and sets *ppmc with new MethodContext), false on failure. -// -// static -bool MethodContext::Initialize(int mcIndex, unsigned char* buff, DWORD size, bool readCompileResults, /* OUT */ MethodContext** ppmc) -{ - MethodContext* mc = new MethodContext(); - mc->index = mcIndex; - *ppmc = mc; - return mc->Initialize(mcIndex, buff, size, readCompileResults); -} - -// static -bool MethodContext::Initialize(int mcIndex, HANDLE hFile, bool readCompileResults, /* OUT */ MethodContext** ppmc) -{ - MethodContext* mc = new MethodContext(); - mc->index = mcIndex; - *ppmc = mc; - return mc->Initialize(mcIndex, hFile, readCompileResults); -} - -bool MethodContext::Initialize(int mcIndex, unsigned char* buff, DWORD size, bool readCompileResults) -{ - bool result = true; - - struct Param - { - unsigned char* buff; - DWORD size; - MethodContext* pThis; - bool readCompileResults; - } param; - param.buff = buff; - param.size = size; - param.pThis = this; - param.readCompileResults = readCompileResults; - PAL_TRY(Param*, pParam, ¶m) - { - pParam->pThis->MethodInitHelper(pParam->buff, pParam->size, pParam->readCompileResults); - } - PAL_EXCEPT_FILTER(FilterSuperPMIExceptions_CatchMC) - { - LogError("Method %d is of low integrity.", mcIndex); - result = false; - } - PAL_ENDTRY - - return result; -} - -bool MethodContext::Initialize(int mcIndex, HANDLE hFile, bool readCompileResults) -{ - bool result = true; - - struct Param - { - HANDLE hFile; - MethodContext* pThis; - bool readCompileResults; - } param; - param.hFile = hFile; - param.pThis = this; - param.readCompileResults = readCompileResults; - - PAL_TRY(Param*, pParam, ¶m) - { - pParam->pThis->MethodInitHelperFile(pParam->hFile, pParam->readCompileResults); - } - PAL_EXCEPT_FILTER(FilterSuperPMIExceptions_CatchMC) - { - LogError("Method %d is of low integrity.", mcIndex); - result = false; - } - PAL_ENDTRY - - return result; -} - -void MethodContext::MethodInitHelperFile(HANDLE hFile, bool readCompileResults) -{ - DWORD bytesRead; - char buff[512]; - unsigned int totalLen = 0; - - AssertCode(ReadFile(hFile, buff, 2 + sizeof(unsigned int), &bytesRead, NULL) == TRUE, - EXCEPTIONCODE_MC); // Read Magic number and totalLen - AssertCodeMsg((buff[0] == 'm') && (buff[1] == 'c'), EXCEPTIONCODE_MC, "Didn't find magic number"); - memcpy(&totalLen, &buff[2], sizeof(unsigned int)); - unsigned char* buff2 = new unsigned char[totalLen + 2]; // total + End Canary - AssertCode(ReadFile(hFile, buff2, totalLen + 2, &bytesRead, NULL) == TRUE, EXCEPTIONCODE_MC); - AssertCodeMsg((buff2[totalLen] == '4') && (buff2[totalLen + 1] == '2'), EXCEPTIONCODE_MC, "Didn't find end canary"); - MethodInitHelper(buff2, totalLen, readCompileResults); -} - -void MethodContext::MethodInitHelper(unsigned char* buff2, unsigned int totalLen, bool readCompileResults) -{ - unsigned int buffIndex = 0; - unsigned int localsize = 0; - unsigned char canary = 0xff; - unsigned char* buff3 = nullptr; - - FreeTempAllocations(); - - while (buffIndex < totalLen) - { - mcPackets packetType = (mcPackets)buff2[buffIndex++]; - memcpy(&localsize, &buff2[buffIndex], sizeof(unsigned int)); - buffIndex += sizeof(unsigned int); - - switch (packetType) - { -#define LWM(map, key, value) sparseReadFile(map, key, value) -#define DENSELWM(map, value) sparseReadFileDense(map, value) -#include "lwmlist.h" - -#define LWM(map, key, value) sparseReadFileCR(map, key, value, readCompileResults) -#define DENSELWM(map, value) sparseReadFileCRDense(map, value, readCompileResults) -#include "crlwmlist.h" - - default: - LogException(EXCEPTIONCODE_MC, "Read ran into unknown packet type %u. Are you using a newer recorder?", - packetType); - // break; - } - buffIndex += localsize; - canary = buff2[buffIndex++]; - AssertCodeMsg(canary == 0x42, EXCEPTIONCODE_MC, "Didn't find trailing canary for map"); - } - AssertCodeMsg((buff2[buffIndex++] == '4') && (buff2[buffIndex++] == '2'), EXCEPTIONCODE_MC, - "Didn't find trailing canary for map"); - delete[] buff2; -} - -#define dumpStat(target) \ - if (target != nullptr) \ - { \ - if (target->GetCount() > 0) \ - { \ - int t = sprintf_s(buff, len, "%u", target->GetCount()); \ - buff += t; \ - len -= t; \ - } \ - } \ - { \ - *buff++ = ','; \ - len--; \ - } \ - if (target != nullptr) \ - { \ - int t = sprintf_s(buff, len, "%u", target->CalculateArraySize()); \ - buff += t; \ - len -= t; \ - } \ - { \ - *buff++ = ','; \ - len--; \ - } - -// Dump statistics about each LightWeightMap to the buffer: count of elements, and total size in bytes of map. -int MethodContext::dumpStatToBuffer(char* buff, int len) -{ - char* obuff = buff; -// assumption of enough buffer.. :-| - -#define LWM(map, key, value) dumpStat(map) -#include "lwmlist.h" - -// Compile Result members -#define LWM(map, key, value) dumpStat(cr->map); -#include "crlwmlist.h" - - return (int)(buff - obuff); -} -int MethodContext::dumpStatTitleToBuffer(char* buff, int len) -{ - const char* title = - -#define LWM(map, key, value) #map "," #map " SZ," -#include "lwmlist.h" - -#define LWM(map, key, value) "CR_" #map ",CR_" #map " SZ," -#include "crlwmlist.h" - - ; - - int titleLen = (int)strlen(title); - if ((titleLen + 1) > len) - { - LogError("titleLen is larger than given len"); - return 0; - } - strcpy_s(buff, len, title); - return titleLen; -} - -#define softMapEqual(a) \ - if (a != nullptr) \ - { \ - if (other->a == nullptr) \ - return false; \ - if (a->GetCount() != other->a->GetCount()) \ - return false; \ - } \ - else if (other->a != nullptr) \ - return false; - -bool MethodContext::Equal(MethodContext* other) -{ - // returns true if equal. Note this is permissive, that is to say that we may reason that too many things are - // equal. Adding more detailed checks would cause us to reason more things as unique; - - // Compare MethodInfo's first. - CORINFO_METHOD_INFO otherInfo; - unsigned otherFlags = 0; - CORINFO_OS otherOs = CORINFO_WINNT; - other->repCompileMethod(&otherInfo, &otherFlags, &otherOs); - - CORINFO_METHOD_INFO ourInfo; - unsigned ourFlags = 0; - CORINFO_OS ourOs = CORINFO_WINNT; - repCompileMethod(&ourInfo, &ourFlags, &ourOs); - - if (otherInfo.ILCodeSize != ourInfo.ILCodeSize) - return false; - if (otherInfo.args.numArgs != ourInfo.args.numArgs) - return false; - if (otherInfo.args.retType != ourInfo.args.retType) - return false; - if (otherInfo.locals.numArgs != ourInfo.locals.numArgs) - return false; - if (otherInfo.EHcount != ourInfo.EHcount) - return false; - if (otherInfo.options != ourInfo.options) - return false; - for (unsigned int j = 0; j < otherInfo.ILCodeSize; j++) - if (otherInfo.ILCode[j] != ourInfo.ILCode[j]) - return false; - if (otherInfo.maxStack != ourInfo.maxStack) - return false; - if (otherInfo.regionKind != ourInfo.regionKind) - return false; - if (otherInfo.args.callConv != ourInfo.args.callConv) - return false; - if (otherInfo.args.cbSig != ourInfo.args.cbSig) - return false; - if (otherInfo.args.flags != ourInfo.args.flags) - return false; - if (otherInfo.locals.cbSig != ourInfo.locals.cbSig) - return false; - if (otherFlags != ourFlags) - return false; - if (otherOs != ourOs) - return false; - -// Now compare the other maps to "estimate" equality. - -#define LWM(map, key, value) softMapEqual(map) -#include "lwmlist.h" - -// Compile Result members -#define LWM(map, key, value) softMapEqual(cr->map) -#include "crlwmlist.h" - - // Base case is we "match" - return true; -} - -//------------------------------------------------------------------------------ -// MethodContext::recGlobalContext -// This method copies any relevant global (i.e. per-JIT-instance) data from -// the given method context. Currently this is limited to configuration -// values, but may grow to encompass other information in the future (e.g. -// any information that is exposed by the ICorJitHost interface and is -// therefore accessible outside the context of a call to -// `ICJI::compileMethod`). -// -// This method is intended to be called as part of initializing a method -// during collection. -void MethodContext::recGlobalContext(const MethodContext& other) -{ - Assert(GetIntConfigValue == nullptr); - Assert(GetStringConfigValue == nullptr); - - if (other.GetIntConfigValue != nullptr) - { - GetIntConfigValue = new LightWeightMap(*other.GetIntConfigValue); - } - - if (other.GetStringConfigValue != nullptr) - { - GetStringConfigValue = new LightWeightMap(*other.GetStringConfigValue); - } -} - -// dumpToConsole: Display the method context numbered `mcNumber` to the console. If `simple` is true, -// dump without function name information. This is useful to debug problems with the creation of that -// information, which requires looking at the dumped info. -void MethodContext::dumpToConsole(int mcNumber, bool simple) -{ - printf("*****************************************"); - if (mcNumber != -1) - { - printf(" method context #%d", mcNumber); - } - - if (!simple) - { - // Dump method name, etc., to output. - char bufferIdentityInfo[METHOD_IDENTITY_INFO_SIZE]; - int cbLen = dumpMethodIdentityInfoToBuffer(bufferIdentityInfo, METHOD_IDENTITY_INFO_SIZE); - if (cbLen >= 0) - { - printf(" %s", bufferIdentityInfo); - } - } - - printf("\n"); - -#define LWM(map, key, value) dumpLWM(this, map) -#define DENSELWM(map, value) dumpLWMDense(this, map) -#include "lwmlist.h" - -// Compile Result members -#define LWM(map, key, value) dumpLWM(this->cr, map) -#define DENSELWM(map, value) dumpLWMDense(this->cr, map) -#include "crlwmlist.h" -} - -const char* toString(InfoAccessType iat) -{ - switch (iat) - { - case IAT_VALUE: - return "VALUE"; - case IAT_PVALUE: - return "PVALUE"; - case IAT_PPVALUE: - return "PPVALUE"; - case IAT_RELPVALUE: - return "RELPVALUE"; - default: - return "UNKNOWN"; - } -}; - -const char* toString(CORINFO_CALL_KIND cick) -{ - switch (cick) - { - case CORINFO_CALL: - return "CALL"; - case CORINFO_CALL_CODE_POINTER: - return "CALL_CODE_POINTER"; - case CORINFO_VIRTUALCALL_STUB: - return "VIRTUALCALL_STUB"; - case CORINFO_VIRTUALCALL_LDVIRTFTN: - return "VIRTUALCALL_LDVIRTFTN"; - case CORINFO_VIRTUALCALL_VTABLE: - return "VIRTUALCALL_VTABLE"; - default: - return "UNKNOWN"; - } -}; - -const char* toString(CorInfoType cit) -{ - switch (cit) - { - case CORINFO_TYPE_UNDEF: - return "undef"; - case CORINFO_TYPE_VOID: - return "void"; - case CORINFO_TYPE_BOOL: - return "bool"; - case CORINFO_TYPE_CHAR: - return "char"; - case CORINFO_TYPE_BYTE: - return "byte"; - case CORINFO_TYPE_UBYTE: - return "ubyte"; - case CORINFO_TYPE_SHORT: - return "short"; - case CORINFO_TYPE_USHORT: - return "ushort"; - case CORINFO_TYPE_INT: - return "int"; - case CORINFO_TYPE_UINT: - return "uint"; - case CORINFO_TYPE_LONG: - return "long"; - case CORINFO_TYPE_ULONG: - return "ulong"; - case CORINFO_TYPE_NATIVEINT: - return "nativeint"; - case CORINFO_TYPE_NATIVEUINT: - return "nativeuint"; - case CORINFO_TYPE_FLOAT: - return "float"; - case CORINFO_TYPE_DOUBLE: - return "double"; - case CORINFO_TYPE_CLASS: - return "class"; - case CORINFO_TYPE_PTR: - return "ptr"; - case CORINFO_TYPE_BYREF: - return "byref"; - case CORINFO_TYPE_VALUECLASS: - return "valueclass"; - default: - return "UNKNOWN"; - } -} - -const char* toString(CorInfoTypeWithMod cit) -{ - // Need to cast `cit` to numeric type to avoid clang compiler warnings - // "case value not in enumerated type 'CorInfoTypeWithMod'". - switch ((unsigned)cit) - { - case (unsigned)(CORINFO_TYPE_BYREF | CORINFO_TYPE_MOD_PINNED): - return "pinned byref"; - case (unsigned)(CORINFO_TYPE_CLASS | CORINFO_TYPE_MOD_PINNED): - return "pinned class"; - default: - return toString((CorInfoType)(cit & CORINFO_TYPE_MASK)); - } -} - -unsigned int toCorInfoSize(CorInfoType cit) -{ - switch (cit) - { - case CORINFO_TYPE_BOOL: - case CORINFO_TYPE_BYTE: - case CORINFO_TYPE_UBYTE: - return 1; - - case CORINFO_TYPE_CHAR: - case CORINFO_TYPE_SHORT: - case CORINFO_TYPE_USHORT: - return 2; - - case CORINFO_TYPE_FLOAT: - case CORINFO_TYPE_INT: - case CORINFO_TYPE_UINT: - return 4; - - case CORINFO_TYPE_DOUBLE: - case CORINFO_TYPE_LONG: - case CORINFO_TYPE_ULONG: - return 8; - - case CORINFO_TYPE_NATIVEINT: - case CORINFO_TYPE_NATIVEUINT: - case CORINFO_TYPE_PTR: - case CORINFO_TYPE_BYREF: - case CORINFO_TYPE_CLASS: - return (int)SpmiTargetPointerSize(); - - case CORINFO_TYPE_VALUECLASS: - case CORINFO_TYPE_UNDEF: - case CORINFO_TYPE_VOID: - default: - DEBUG_BREAK; - return 0; - } - return -1; -} - -void MethodContext::recCompileMethod(CORINFO_METHOD_INFO* info, unsigned flags, CORINFO_OS os) -{ - if (CompileMethod == nullptr) - CompileMethod = new LightWeightMap(); - - Agnostic_CompileMethod value; - - value.info.ftn = CastHandle(info->ftn); - value.info.scope = CastHandle(info->scope); - value.info.ILCode_offset = (DWORD)CompileMethod->AddBuffer(info->ILCode, info->ILCodeSize); - value.info.ILCodeSize = (DWORD)info->ILCodeSize; - value.info.maxStack = (DWORD)info->maxStack; - value.info.EHcount = (DWORD)info->EHcount; - value.info.options = (DWORD)info->options; - value.info.regionKind = (DWORD)info->regionKind; - - value.info.args = SpmiRecordsHelper::StoreAgnostic_CORINFO_SIG_INFO(info->args, CompileMethod, SigInstHandleMap); - value.info.locals = SpmiRecordsHelper::StoreAgnostic_CORINFO_SIG_INFO(info->locals, CompileMethod, SigInstHandleMap); - - value.os = (DWORD)os; - - value.flags = (DWORD)flags; - - CompileMethod->Add(0, value); - DEBUG_REC(dmpCompileMethod(0, value)); -} -void MethodContext::dmpCompileMethod(DWORD key, const Agnostic_CompileMethod& value) -{ - printf("CompileMethod key %u, value ftn-%016" PRIX64 " scp-%016" PRIX64 " ilo-%u ils-%u ms-%u ehc-%u opt-%u rk-%u args-%s locals-%s flg-%08X os-%u", - key, value.info.ftn, value.info.scope, value.info.ILCode_offset, value.info.ILCodeSize, value.info.maxStack, - value.info.EHcount, value.info.options, value.info.regionKind, - SpmiDumpHelper::DumpAgnostic_CORINFO_SIG_INFO(value.info.args, CompileMethod, SigInstHandleMap).c_str(), - SpmiDumpHelper::DumpAgnostic_CORINFO_SIG_INFO(value.info.locals, CompileMethod, SigInstHandleMap).c_str(), - value.flags, value.os); -} -void MethodContext::repCompileMethod(CORINFO_METHOD_INFO* info, unsigned* flags, CORINFO_OS* os) -{ - Agnostic_CompileMethod value; - value = LookupByKeyOrMissNoMessage(CompileMethod, 0); // The only item in this set is a single group of inputs to CompileMethod - - DEBUG_REP(dmpCompileMethod(0, value)); - - info->ftn = (CORINFO_METHOD_HANDLE)value.info.ftn; - info->scope = (CORINFO_MODULE_HANDLE)value.info.scope; - info->ILCode = CompileMethod->GetBuffer(value.info.ILCode_offset); - info->ILCodeSize = (unsigned)value.info.ILCodeSize; - methodSize = info->ILCodeSize; - info->maxStack = (unsigned)value.info.maxStack; - info->EHcount = (unsigned)value.info.EHcount; - info->options = (CorInfoOptions)value.info.options; - info->regionKind = (CorInfoRegionKind)value.info.regionKind; - - info->args = SpmiRecordsHelper::Restore_CORINFO_SIG_INFO(value.info.args, CompileMethod, SigInstHandleMap, cr->getOrCreateMemoryTracker()); - info->locals = SpmiRecordsHelper::Restore_CORINFO_SIG_INFO(value.info.locals, CompileMethod, SigInstHandleMap, cr->getOrCreateMemoryTracker()); - - *flags = (unsigned)value.flags; - *os = (CORINFO_OS)value.os; -} - -void MethodContext::recGetMethodClass(CORINFO_METHOD_HANDLE methodHandle, CORINFO_CLASS_HANDLE classHandle) -{ - if (GetMethodClass == nullptr) - GetMethodClass = new LightWeightMap(); - - DWORDLONG key = CastHandle(methodHandle); - DWORDLONG value = CastHandle(classHandle); - GetMethodClass->Add(key, value); - DEBUG_REC(dmpGetMethodClass(key, value)); -} -void MethodContext::dmpGetMethodClass(DWORDLONG key, DWORDLONG value) -{ - printf("GetMethodClass key %016" PRIX64 ", value %016" PRIX64 "", key, value); -} -CORINFO_CLASS_HANDLE MethodContext::repGetMethodClass(CORINFO_METHOD_HANDLE methodHandle) -{ - DWORDLONG key = CastHandle(methodHandle); - DWORDLONG value = LookupByKeyOrMiss(GetMethodClass, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetMethodClass(key, value)); - CORINFO_CLASS_HANDLE result = (CORINFO_CLASS_HANDLE)value; - return result; -} - -void MethodContext::recGetClassAttribs(CORINFO_CLASS_HANDLE classHandle, DWORD attribs) -{ - if (GetClassAttribs == nullptr) - GetClassAttribs = new LightWeightMap(); - - DWORDLONG key = CastHandle(classHandle); - GetClassAttribs->Add(key, attribs); - DEBUG_REC(dmpGetClassAttribs(key, attribs)); -} -void MethodContext::dmpGetClassAttribs(DWORDLONG key, DWORD value) -{ - printf("GetClassAttribs key %016" PRIX64 ", value %08X (%s)", key, value, SpmiDumpHelper::DumpCorInfoFlag((CorInfoFlag)value).c_str()); -} -DWORD MethodContext::repGetClassAttribs(CORINFO_CLASS_HANDLE classHandle) -{ - DWORDLONG key = CastHandle(classHandle); - DWORD value = LookupByKeyOrMiss(GetClassAttribs, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetClassAttribs(key, value)); - return value; -} - -void MethodContext::recIsIntrinsic(CORINFO_METHOD_HANDLE ftn, bool result) -{ - if (IsIntrinsic == nullptr) - IsIntrinsic = new LightWeightMap(); - - DWORDLONG key = CastHandle(ftn); - DWORD value = result ? 1 : 0; - IsIntrinsic->Add(key, value); - DEBUG_REC(dmpIsIntrinsic(key, value)); -} -void MethodContext::dmpIsIntrinsic(DWORDLONG key, DWORD value) -{ - printf("IsIntrinsic key ftn-%016" PRIX64 ", value res-%u", key, value); -} -bool MethodContext::repIsIntrinsic(CORINFO_METHOD_HANDLE ftn) -{ - DWORDLONG key = CastHandle(ftn); - DWORD value = LookupByKeyOrMiss(IsIntrinsic, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpIsIntrinsic(key, value)); - return value != 0; -} - -void MethodContext::recNotifyMethodInfoUsage(CORINFO_METHOD_HANDLE ftn, bool result) -{ - if (NotifyMethodInfoUsage == nullptr) - NotifyMethodInfoUsage = new LightWeightMap(); - - DWORDLONG key = CastHandle(ftn); - DWORD value = result ? 1 : 0; - NotifyMethodInfoUsage->Add(key, value); - DEBUG_REC(dmpNotifyMethodInfoUsage(key, value)); -} -void MethodContext::dmpNotifyMethodInfoUsage(DWORDLONG key, DWORD value) -{ - printf("NotifyMethodInfoUsage key ftn-%016" PRIX64 ", value res-%u", key, value); -} -bool MethodContext::repNotifyMethodInfoUsage(CORINFO_METHOD_HANDLE ftn) -{ - DWORDLONG key = CastHandle(ftn); - DWORD value = LookupByKeyOrMiss(NotifyMethodInfoUsage, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpNotifyMethodInfoUsage(key, value)); - return value != 0; -} - -void MethodContext::recNotifyInstructionSetUsage(CORINFO_InstructionSet isa, bool supported, bool preserveNegativeDependency, bool result) -{ - if (NotifyInstructionSetUsage == nullptr) - NotifyInstructionSetUsage = new LightWeightMap(); - - DD key{}; - key.A = (DWORD)isa; - key.B = (supported ? 1 : 0) | (preserveNegativeDependency ? 2 : 0); - NotifyInstructionSetUsage->Add(key, result ? 1 : 0); - DEBUG_REC(dmpNotifyInstructionSetUsage(key, result ? 1 : 0)); -} -void MethodContext::dmpNotifyInstructionSetUsage(DD key, DWORD value) -{ - printf("NotifyInstructionSetUsage key isa-%u, supported-%u, preserve-negative-dependency-%u, res-%u", - key.A, key.B & 1, (key.B >> 1) & 1, value); -} -bool MethodContext::repNotifyInstructionSetUsage(CORINFO_InstructionSet isa, bool supported, bool preserveNegativeDependency) -{ - DD key{}; - key.A = (DWORD)isa; - key.B = (supported ? 1 : 0) | (preserveNegativeDependency ? 2 : 0); - - if (NotifyInstructionSetUsage != nullptr) - { - int index = NotifyInstructionSetUsage->GetIndex(key); - if (index != -1) - { - DWORD value = NotifyInstructionSetUsage->GetItem(index); - DEBUG_REP(dmpNotifyInstructionSetUsage(key, value)); - return value != 0; - } - } - - // Fall back to most likely implementation instead of missing, since ISA - // usage changes are quite common on normal JIT changes. - return supported; -} - -void MethodContext::recGetMethodAttribs(CORINFO_METHOD_HANDLE methodHandle, DWORD attribs) -{ - if (GetMethodAttribs == nullptr) - GetMethodAttribs = new LightWeightMap(); - - DWORDLONG key = CastHandle(methodHandle); - GetMethodAttribs->Add(key, attribs); - DEBUG_REC(dmpGetMethodAttribs(key, attribs)); -} -void MethodContext::dmpGetMethodAttribs(DWORDLONG key, DWORD value) -{ - printf("GetMethodAttribs key %016" PRIX64 ", value %08X (%s)", key, value, SpmiDumpHelper::DumpCorInfoFlag((CorInfoFlag)value).c_str()); -} -DWORD MethodContext::repGetMethodAttribs(CORINFO_METHOD_HANDLE methodHandle) -{ - DWORDLONG key = CastHandle(methodHandle); - DWORD value = LookupByKeyOrMiss(GetMethodAttribs, key, ": key %016" PRIX64 "", key); - - DEBUG_REP(dmpGetMethodAttribs(key, value)); - - if ((cr->repSetMethodAttribs(methodHandle) & CORINFO_FLG_BAD_INLINEE) != 0) - value |= CORINFO_FLG_DONT_INLINE; - return value; -} - -void MethodContext::recGetClassAssemblyName(CORINFO_CLASS_HANDLE cls, const char* assemblyName) -{ - if (GetClassAssemblyName == nullptr) - GetClassAssemblyName = new LightWeightMap(); - - DWORD value; - if (assemblyName != nullptr) - { - value = GetClassAssemblyName->AddBuffer((const unsigned char*)assemblyName, (DWORD)strlen(assemblyName) + 1); - } - else - { - value = (DWORD)-1; - } - - DWORDLONG key = CastHandle(cls); - GetClassAssemblyName->Add(key, value); - DEBUG_REC(dmpGetClassAssemblyName(key, value)); -} -void MethodContext::dmpGetClassAssemblyName(DWORDLONG key, DWORD value) -{ - const char* assemblyName = (const char*)GetClassAssemblyName->GetBuffer(value); - printf("GetClassAssemblyName cls-%016" PRIX64 ", value-%u '%s'", key, value, assemblyName); - GetClassAssemblyName->Unlock(); -} -const char* MethodContext::repGetClassAssemblyName(CORINFO_CLASS_HANDLE cls) -{ - DWORDLONG key = CastHandle(cls); - DWORD value = LookupByKeyOrMiss(GetClassAssemblyName, key, ": key %016" PRIX64 "", key); - const char* result = nullptr; - - DEBUG_REP(dmpGetClassAssemblyName(key, value)); - - if (value != (DWORD)-1) - { - result = (const char*)GetClassAssemblyName->GetBuffer(value); - } - - return result; -} - -// Note - the jit will call freearray on the array we give back.... -void MethodContext::recGetVars(CORINFO_METHOD_HANDLE ftn, - ULONG32* cVars, - ICorDebugInfo::ILVarInfo** vars_in, - bool* extendOthers) -{ - if (GetVars == nullptr) - GetVars = new LightWeightMap(); - - Agnostic_GetVars value; - value.cVars = (DWORD)*cVars; - value.vars_offset = - (DWORD)GetVars->AddBuffer((unsigned char*)*vars_in, sizeof(ICorDebugInfo::ILVarInfo) * (*cVars)); - value.extendOthers = (DWORD)*extendOthers; - - DWORDLONG key = CastHandle(ftn); - GetVars->Add(key, value); - DEBUG_REC(dmpGetVars(key, value)); -} -void MethodContext::dmpGetVars(DWORDLONG key, const Agnostic_GetVars& value) -{ - ICorDebugInfo::ILVarInfo* vars = (ICorDebugInfo::ILVarInfo*)GetVars->GetBuffer(value.vars_offset); - printf("GetVars key ftn-%016" PRIX64 ", value cVars-%u extendOthers-%u (", key, value.cVars, value.extendOthers); - for (unsigned int i = 0; i < value.cVars; i++) - printf("(%u %u %u %u)", i, vars[i].startOffset, vars[i].endOffset, vars[i].varNumber); - printf(")"); - GetVars->Unlock(); -} -void MethodContext::repGetVars(CORINFO_METHOD_HANDLE ftn, - ULONG32* cVars, - ICorDebugInfo::ILVarInfo** vars_in, - bool* extendOthers) -{ - if (GetVars == nullptr) - { - *cVars = 0; - return; - } - - DWORDLONG key = CastHandle(ftn); - Agnostic_GetVars value = GetVars->Get(key); - DEBUG_REP(dmpGetVars(key, value)); - - *cVars = (ULONG32)value.cVars; - if (*cVars > 0) - *vars_in = (ICorDebugInfo::ILVarInfo*)GetVars->GetBuffer(value.vars_offset); - *extendOthers = value.extendOthers != 0; -} - -// Note - the jit will call freearray on the array we give back.... -void MethodContext::recGetBoundaries(CORINFO_METHOD_HANDLE ftn, - unsigned int* cILOffsets, - uint32_t** pILOffsets, - ICorDebugInfo::BoundaryTypes* implicitBoundaries) -{ - if (GetBoundaries == nullptr) - GetBoundaries = new LightWeightMap(); - - Agnostic_GetBoundaries value; - - value.cILOffsets = (DWORD)*cILOffsets; - value.pILOffset_offset = - (DWORD)GetBoundaries->AddBuffer((unsigned char*)*pILOffsets, sizeof(DWORD) * (*cILOffsets)); - value.implicitBoundaries = *implicitBoundaries; - - DWORDLONG key = CastHandle(ftn); - GetBoundaries->Add(key, value); - DEBUG_REC(dmpGetBoundaries(key, value)); -} -void MethodContext::dmpGetBoundaries(DWORDLONG key, const Agnostic_GetBoundaries& value) -{ - printf("GetBoundaries key ftn-%016" PRIX64 ", value cnt-%u imp-%u{", key, value.cILOffsets, value.implicitBoundaries); - DWORD* bnd = (DWORD*)GetBoundaries->GetBuffer(value.pILOffset_offset); - for (unsigned int i = 0; i < value.cILOffsets; i++) - { - printf("%u", bnd[i]); - if (i < (value.cILOffsets + 1)) - printf(","); - } - GetBoundaries->Unlock(); - printf("}"); -} -void MethodContext::repGetBoundaries(CORINFO_METHOD_HANDLE ftn, - unsigned int* cILOffsets, - uint32_t** pILOffsets, - ICorDebugInfo::BoundaryTypes* implicitBoundaries) -{ - DWORDLONG key = CastHandle(ftn); - Agnostic_GetBoundaries value = LookupByKeyOrMiss(GetBoundaries, key, ": key %016" PRIX64 "", key); - - DEBUG_REP(dmpGetBoundaries(key, value)); - - *cILOffsets = (unsigned int)value.cILOffsets; - if (*cILOffsets > 0) - *pILOffsets = (uint32_t*)GetBoundaries->GetBuffer(value.pILOffset_offset); - *implicitBoundaries = (ICorDebugInfo::BoundaryTypes)value.implicitBoundaries; -} - -void MethodContext::recInitClass(CORINFO_FIELD_HANDLE field, - CORINFO_METHOD_HANDLE method, - CORINFO_CONTEXT_HANDLE context, - CorInfoInitClassResult result) -{ - if (InitClass == nullptr) - InitClass = new LightWeightMap(); - - Agnostic_InitClass key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.field = CastHandle(field); - key.method = CastHandle(method); - key.context = CastHandle(context); - - DWORD value = (DWORD)result; - InitClass->Add(key, value); - DEBUG_REC(dmpInitClass(key, value)); -} -void MethodContext::dmpInitClass(const Agnostic_InitClass& key, DWORD value) -{ - printf("InitClass key fld-%016" PRIX64 " meth-%016" PRIX64 " con-%016" PRIX64 ", value res-%u", key.field, key.method, - key.context, value); -} -CorInfoInitClassResult MethodContext::repInitClass(CORINFO_FIELD_HANDLE field, - CORINFO_METHOD_HANDLE method, - CORINFO_CONTEXT_HANDLE context) -{ - Agnostic_InitClass key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.field = CastHandle(field); - key.method = CastHandle(method); - key.context = CastHandle(context); - - DWORD value = - LookupByKeyOrMiss(InitClass, key, ": fld-%016" PRIX64 " meth-%016" PRIX64 " con-%016" PRIX64, - key.field, key.method, key.context); - - DEBUG_REP(dmpInitClass(key, value)); - CorInfoInitClassResult result = (CorInfoInitClassResult)value; - return result; -} - -void MethodContext::recGetMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftn, - char* methodName, - const char** className, - const char** namespaceName, - const char** enclosingClassNames, - size_t maxEnclosingClassNames) -{ - if (GetMethodNameFromMetadata == nullptr) - GetMethodNameFromMetadata = new LightWeightMap(); - Agnostic_CORINFO_METHODNAME_TOKENout value; - Agnostic_CORINFO_METHODNAME_TOKENin key; - key.ftn = CastHandle(ftn); - key.className = (className != nullptr); - key.namespaceName = (namespaceName != nullptr); - key.maxEnclosingClassNames = (DWORD)maxEnclosingClassNames; - - if (methodName != nullptr) - value.methodName = GetMethodNameFromMetadata->AddBuffer((unsigned char*)methodName, (DWORD)strlen(methodName) + 1); - else - value.methodName = (DWORD)-1; - - if ((className != nullptr) && (*className != nullptr)) - value.className = GetMethodNameFromMetadata->AddBuffer((unsigned char*)*className, (DWORD)strlen(*className) + 1); - else - value.className = (DWORD)-1; - - if ((namespaceName != nullptr) && (*namespaceName != nullptr)) - value.namespaceName = - GetMethodNameFromMetadata->AddBuffer((unsigned char*)*namespaceName, (DWORD)strlen(*namespaceName) + 1); - else - value.namespaceName = (DWORD)-1; - - DWORD* enclosingClassNameIndices = static_cast(alloca(sizeof(DWORD) * maxEnclosingClassNames)); - for (size_t i = 0; i < maxEnclosingClassNames; i++) - { - const char* enclosingClassName = enclosingClassNames[i]; - if (enclosingClassName != nullptr) - enclosingClassNameIndices[i] = GetMethodNameFromMetadata->AddBuffer((unsigned char*)enclosingClassName, (DWORD)strlen(enclosingClassName) + 1); - else - enclosingClassNameIndices[i] = (DWORD)-1; - } - - if (maxEnclosingClassNames > 0) - value.enclosingClassNames = GetMethodNameFromMetadata->AddBuffer((unsigned char*)enclosingClassNameIndices, sizeof(DWORD) * (DWORD)maxEnclosingClassNames); - else - value.enclosingClassNames = (DWORD)-1; - - GetMethodNameFromMetadata->Add(key, value); - DEBUG_REC(dmpGetMethodNameFromMetadata(key, value)); -} - -void MethodContext::dmpGetMethodNameFromMetadata(Agnostic_CORINFO_METHODNAME_TOKENin key, Agnostic_CORINFO_METHODNAME_TOKENout value) -{ - unsigned char* methodName = (unsigned char*)GetMethodNameFromMetadata->GetBuffer(value.methodName); - unsigned char* className = (unsigned char*)GetMethodNameFromMetadata->GetBuffer(value.className); - unsigned char* namespaceName = (unsigned char*)GetMethodNameFromMetadata->GetBuffer(value.namespaceName); - unsigned char* enclosingClassNameIndices = GetMethodNameFromMetadata->GetBuffer(value.enclosingClassNames); - printf("GetMethodNameFromMetadata key - ftn-%016" PRIX64 " classNonNull-%u namespaceNonNull-%u maxEnclosingClassNames-%u, value meth-'%s', " - "class-'%s', namespace-'%s'", - key.ftn, key.className, key.namespaceName, key.maxEnclosingClassNames, methodName, className, namespaceName); - - for (DWORD i = 0; i < key.maxEnclosingClassNames; i++) - { - DWORD index; - memcpy(&index, &enclosingClassNameIndices[i * sizeof(DWORD)], sizeof(DWORD)); - - unsigned char* enclosingClassName = GetMethodNameFromMetadata->GetBuffer(index); - if (enclosingClassName != nullptr) - printf(" enclosingClass%u-'%s'", i, enclosingClassName); - } - - GetMethodNameFromMetadata->Unlock(); -} - -const char* MethodContext::repGetMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftn, - const char** moduleName, - const char** namespaceName, - const char** enclosingClassNames, - size_t maxEnclosingClassNames) -{ - Agnostic_CORINFO_METHODNAME_TOKENin key; - - key.ftn = CastHandle(ftn); - key.className = (moduleName != nullptr); - key.namespaceName = (namespaceName != nullptr); - key.maxEnclosingClassNames = (DWORD)maxEnclosingClassNames; - - Agnostic_CORINFO_METHODNAME_TOKENout value = LookupByKeyOrMiss( - GetMethodNameFromMetadata, - key, - ": ftn-%016" PRIX64 " className-%u namespaceName-%u maxEnclosingClassNames-%u", - key.ftn, - key.className, - key.namespaceName, - key.maxEnclosingClassNames); - - DEBUG_REP(dmpGetMethodNameFromMetadata(key, value)); - - const char* result = (const char*)GetMethodNameFromMetadata->GetBuffer(value.methodName); - - if (moduleName != nullptr) - { - *moduleName = (const char*)GetMethodNameFromMetadata->GetBuffer(value.className); - } - - if (namespaceName != nullptr) - { - *namespaceName = (const char*)GetMethodNameFromMetadata->GetBuffer(value.namespaceName); - } - - unsigned char* enclosingClassNameIndices = GetMethodNameFromMetadata->GetBuffer(value.enclosingClassNames); - for (size_t i = 0; i < maxEnclosingClassNames; i++) - { - DWORD index; - memcpy(&index, &enclosingClassNameIndices[i * sizeof(DWORD)], sizeof(DWORD)); - enclosingClassNames[i] = (const char*)GetMethodNameFromMetadata->GetBuffer(index); - } - - return result; -} - -void MethodContext::recGetJitFlags(CORJIT_FLAGS* jitFlags, DWORD sizeInBytes, DWORD result) -{ - if (GetJitFlags == nullptr) - GetJitFlags = new LightWeightMap(); - - DD value; - value.A = (DWORD)GetJitFlags->AddBuffer((unsigned char*)jitFlags, sizeInBytes); - value.B = result; - - // NOTE: getJitFlags() is expected to be idempotent per method, so the mapping key is always - // zero. - GetJitFlags->Add(0, value); - DEBUG_REC(dmpGetJitFlags(0, value)); -} - -// TODO: we need a widely-available utility function that can print a CORJIT_FLAGS::CorJitFlag. -// Maybe something in corjitflags.h itself. -const char* CorJitFlagToString(CORJIT_FLAGS::CorJitFlag flag) -{ - switch (flag) - { - case CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_SPEED_OPT: - return "CORJIT_FLAG_SPEED_OPT"; - case CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_SIZE_OPT: - return "CORJIT_FLAG_SIZE_OPT"; - case CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_DEBUG_CODE: - return "CORJIT_FLAG_DEBUG_CODE"; - case CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_DEBUG_EnC: - return "CORJIT_FLAG_DEBUG_EnC"; - case CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_DEBUG_INFO: - return "CORJIT_FLAG_DEBUG_INFO"; - case CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_MIN_OPT: - return "CORJIT_FLAG_MIN_OPT"; - case CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_ENABLE_CFG: - return "CORJIT_FLAG_ENABLE_CFG"; - case CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_OSR: - return "CORJIT_FLAG_OSR"; - case CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_ALT_JIT: - return "CORJIT_FLAG_ALT_JIT"; - case CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_FROZEN_ALLOC_ALLOWED: - return "CORJIT_FLAG_FROZEN_ALLOC_ALLOWED"; - case CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_PORTABLE_ENTRY_POINTS: - return "CORJIT_FLAG_PORTABLE_ENTRY_POINTS"; - case CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_AOT: - return "CORJIT_FLAG_AOT"; - case CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_PROF_ENTERLEAVE: - return "CORJIT_FLAG_PROF_ENTERLEAVE"; - case CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_PROF_NO_PINVOKE_INLINE: - return "CORJIT_FLAG_PROF_NO_PINVOKE_INLINE"; - case CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_RELOC: - return "CORJIT_FLAG_RELOC"; - case CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_IL_STUB: - return "CORJIT_FLAG_IL_STUB"; - case CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_PROCSPLIT: - return "CORJIT_FLAG_PROCSPLIT"; - case CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_BBINSTR: - return "CORJIT_FLAG_BBINSTR"; - case CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_BBINSTR_IF_LOOPS: - return "CORJIT_FLAG_BBINSTR_IF_LOOPS"; - case CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_BBOPT: - return "CORJIT_FLAG_BBOPT"; - case CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_FRAMED: - return "CORJIT_FLAG_FRAMED"; - case CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_USE_PINVOKE_HELPERS: - return "CORJIT_FLAG_USE_PINVOKE_HELPERS"; - case CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_REVERSE_PINVOKE: - return "CORJIT_FLAG_REVERSE_PINVOKE"; - case CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_TRACK_TRANSITIONS: - return "CORJIT_FLAG_TRACK_TRANSITIONS"; - case CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_TIER0: - return "CORJIT_FLAG_TIER0"; - case CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_TIER1: - return "CORJIT_FLAG_TIER1"; - case CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_NO_INLINING: - return "CORJIT_FLAG_NO_INLINING"; - -#if defined(TARGET_ARM) - case CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_RELATIVE_CODE_RELOCS: - return "CORJIT_FLAG_RELATIVE_CODE_RELOCS"; - case CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_SOFTFP_ABI: - return "CORJIT_FLAG_SOFTFP_ABI"; -#endif // defined(TARGET_ARM) - - case CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_ASYNC: - return "CORJIT_FLAG_ASYNC"; - case CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_USE_DISPATCH_HELPERS: - return "CORJIT_FLAG_USE_DISPATCH_HELPERS"; - case CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_WASM_MANAGED_HELPER: - return "CORJIT_FLAG_WASM_MANAGED_HELPER"; - - default: - return ""; - } -} - -void MethodContext::dmpGetJitFlags(DWORD key, DD value) -{ - CORJIT_FLAGS* jitflags = (CORJIT_FLAGS*)GetJitFlags->GetBuffer(value.A); - printf("GetJitFlags key %u sizeInBytes-%u jitFlags-%016" PRIX64 " instructionSetFlags-", key, value.B, jitflags->GetFlagsRaw()); - - uint64_t *raw = jitflags->GetInstructionSetFlagsRaw(); - const int flagsFieldCount = jitflags->GetInstructionFlagsFieldCount(); - for (int i = flagsFieldCount - 1; i >= 0; i--) - { - printf("%016" PRIX64 "", raw[i]); - } - - // Print text string for the flags - printf(" ("); - - unsigned maxCorJitFlag = sizeof(uint64_t) * 8; // There's no API to determine the largest possible `corJitFlags`. - for (CORJIT_FLAGS::CorJitFlag flag = (CORJIT_FLAGS::CorJitFlag)0; (unsigned)flag < maxCorJitFlag; flag = (CORJIT_FLAGS::CorJitFlag)((unsigned)flag + 1)) - { - if (jitflags->IsSet(flag)) - { - printf(" %s", CorJitFlagToString(flag)); - } - } - - unsigned maxInstructionSetFlagCount = sizeof(uint64_t) * 8 * flagsFieldCount; - for (CORINFO_InstructionSet isa = (CORINFO_InstructionSet)0; (unsigned)isa < maxInstructionSetFlagCount; isa = (CORINFO_InstructionSet)((unsigned)isa + 1)) - { - if (jitflags->IsSet(isa)) - { - printf(" %s", InstructionSetToString(isa)); - } - } - - printf(" )"); - GetJitFlags->Unlock(); -} -DWORD MethodContext::repGetJitFlags(CORJIT_FLAGS* jitFlags, DWORD sizeInBytes) -{ - DD value = LookupByKeyOrMissNoMessage(GetJitFlags, 0); - - DEBUG_REP(dmpGetJitFlags(0, value)); - - CORJIT_FLAGS* resultFlags = (CORJIT_FLAGS*)GetJitFlags->GetBuffer(value.A); - Assert(sizeInBytes >= value.B); - memcpy((void*)jitFlags, (void*)resultFlags, value.B); - return value.B; -} - -void MethodContext::recCanInline(CORINFO_METHOD_HANDLE callerHnd, - CORINFO_METHOD_HANDLE calleeHnd, - CorInfoInline response, - DWORD exceptionCode) -{ - if (CanInline == nullptr) - CanInline = new LightWeightMap(); - - DLDL key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(callerHnd); - key.B = CastHandle(calleeHnd); - - Agnostic_CanInline value; - value.result = (DWORD)response; - value.exceptionCode = (DWORD)exceptionCode; - - CanInline->Add(key, value); - DEBUG_REC(dmpCanInline(key, value)); -} -void MethodContext::dmpCanInline(DLDL key, const Agnostic_CanInline& value) -{ - printf("CanInline key - callerHnd-%016" PRIX64 " calleeHnd-%016" PRIX64 ", value result-%u exceptionCode-%08X", - key.A, key.B, value.result, value.exceptionCode); -} -CorInfoInline MethodContext::repCanInline(CORINFO_METHOD_HANDLE callerHnd, - CORINFO_METHOD_HANDLE calleeHnd, - DWORD* exceptionCode) -{ - DLDL key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(callerHnd); - key.B = CastHandle(calleeHnd); - - if ((CanInline == nullptr) || (CanInline->GetIndex(key) == -1)) - { -#ifdef sparseMC - LogDebug("Sparse - repCanInline saying INLINE_FAIL"); - return INLINE_FAIL; // if we have no info, its pretty safe to say we can't inline it. -#else - LogException(EXCEPTIONCODE_MC, "Didn't find %016" PRIx64 ", %016" PRIx64 ". probably a missing exception in canInline", - key.A, key.B); -#endif - } - - Agnostic_CanInline value = CanInline->Get(key); - DEBUG_REP(dmpCanInline(key, value)); - - *exceptionCode = value.exceptionCode; - - CorInfoInline response = (CorInfoInline)value.result; - return response; -} - -void MethodContext::recResolveToken(CORINFO_RESOLVED_TOKEN* pResolvedToken, DWORD exceptionCode) -{ - if (ResolveToken == nullptr) - ResolveToken = new LightWeightMap(); - - Agnostic_CORINFO_RESOLVED_TOKENin key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key = SpmiRecordsHelper::CreateAgnostic_CORINFO_RESOLVED_TOKENin(pResolvedToken); - - ResolveTokenValue value; - if (exceptionCode != ERROR_SUCCESS) - { - // The output token memory might be corrupt or uninitialized, so just zero it out. - // (Set indexes to -1, indicating no buffer). - ZeroMemory(&value.tokenOut, sizeof(value.tokenOut)); - value.tokenOut.pTypeSpec_Index = (DWORD)-1; - value.tokenOut.pMethodSpec_Index = (DWORD)-1; - } - else - { - value.tokenOut = SpmiRecordsHelper::StoreAgnostic_CORINFO_RESOLVED_TOKENout(pResolvedToken, ResolveToken); - } - value.exceptionCode = exceptionCode; - - ResolveToken->Add(key, value); - DEBUG_REC(dmpResolveToken(key, value)); -} -void MethodContext::dmpResolveToken(const Agnostic_CORINFO_RESOLVED_TOKENin& key, const ResolveTokenValue& value) -{ - printf("ResolveToken key: %s, value: %s excp-%08X", - SpmiDumpHelper::DumpAgnostic_CORINFO_RESOLVED_TOKENin(key).c_str(), - SpmiDumpHelper::DumpAgnostic_CORINFO_RESOLVED_TOKENout(value.tokenOut).c_str(), - value.exceptionCode); -} -void MethodContext::repResolveToken(CORINFO_RESOLVED_TOKEN* pResolvedToken, DWORD* exceptionCode) -{ - Agnostic_CORINFO_RESOLVED_TOKENin key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key = SpmiRecordsHelper::CreateAgnostic_CORINFO_RESOLVED_TOKENin(pResolvedToken); - - ResolveTokenValue value = LookupByKeyOrMiss(ResolveToken, key, ": token %x", pResolvedToken->token); - DEBUG_REP(dmpResolveToken(key, value)); - - SpmiRecordsHelper::Restore_CORINFO_RESOLVED_TOKENout(pResolvedToken, value.tokenOut, ResolveToken); - *exceptionCode = (DWORD)value.exceptionCode; -} - -void MethodContext::recGetCallInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, - CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_CALLINFO_FLAGS flags, - CORINFO_CALL_INFO* pResult, - DWORD exceptionCode) -{ - if (GetCallInfo == nullptr) - GetCallInfo = new LightWeightMap(); - - Agnostic_GetCallInfo key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.ResolvedToken = SpmiRecordsHelper::StoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, GetCallInfo); - - if (pConstrainedResolvedToken != nullptr) - { - key.ConstrainedResolvedToken = - SpmiRecordsHelper::StoreAgnostic_CORINFO_RESOLVED_TOKEN(pConstrainedResolvedToken, GetCallInfo); - } - - key.callerHandle = CastHandle(callerHandle); - key.flags = (DWORD)flags; - - Agnostic_CORINFO_CALL_INFO value; - ZeroMemory(&value, sizeof(Agnostic_CORINFO_CALL_INFO)); - - if (exceptionCode == 0) - { - value.hMethod = CastHandle(pResult->hMethod); - value.methodFlags = (DWORD)pResult->methodFlags; - value.classFlags = (DWORD)pResult->classFlags; - value.sig = SpmiRecordsHelper::StoreAgnostic_CORINFO_SIG_INFO(pResult->sig, GetCallInfo, SigInstHandleMap); - - value.accessAllowed = (DWORD)pResult->accessAllowed; - value.callsiteCalloutHelper.helperNum = (DWORD)pResult->callsiteCalloutHelper.helperNum; - value.callsiteCalloutHelper.numArgs = (DWORD)pResult->callsiteCalloutHelper.numArgs; - for (int i = 0; i < CORINFO_ACCESS_ALLOWED_MAX_ARGS; i++) - { - value.callsiteCalloutHelper.args[i].constant = (DWORDLONG)pResult->callsiteCalloutHelper.args[i].constant; - value.callsiteCalloutHelper.args[i].argType = (DWORD)pResult->callsiteCalloutHelper.args[i].argType; - } - value.thisTransform = (DWORD)pResult->thisTransform; - - value.kind = (DWORD)pResult->kind; - value.nullInstanceCheck = (DWORD)pResult->nullInstanceCheck; - value.contextHandle = CastHandle(pResult->contextHandle); - value.exactContextNeedsRuntimeLookup = (DWORD)pResult->exactContextNeedsRuntimeLookup; - - value.stubLookup = SpmiRecordsHelper::StoreAgnostic_CORINFO_LOOKUP(&pResult->stubLookup); - - value.instParamLookup.accessType = (DWORD)pResult->instParamLookup.accessType; - value.instParamLookup.handle = CastHandle(pResult->instParamLookup.handle); - } - - value.exceptionCode = (DWORD)exceptionCode; - - GetCallInfo->Add(key, value); - DEBUG_REC(dmpGetCallInfo(key, value)); -} - -void MethodContext::dmpGetCallInfo(const Agnostic_GetCallInfo& key, const Agnostic_CORINFO_CALL_INFO& value) -{ - printf("GetCallInfo key rt{%s} crt{%s} ch-%016" PRIX64 " flg-%08X" - ", value mth-%016" PRIX64 ", mf-%08X (%s) cf-%08X (%s)" - " sig-%s" - " aa-%u" - " cch{hn-%u na-%u (TODO: dump callsiteCalloutHelper.args)}" - " tt-%u" - " k-%u (%s)" - " nic-%u (%s)" - " ch-%016" PRIX64 "" - " ecnrl-%u (%s)" - " stubLookup{%s}" - " ipl{at-%08X (%s) hnd-%016" PRIX64 "}" - " excp-%08X", - // input - SpmiDumpHelper::DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.ResolvedToken).c_str(), - SpmiDumpHelper::DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.ConstrainedResolvedToken).c_str(), - key.callerHandle, - key.flags, - // output - value.hMethod, - value.methodFlags, - SpmiDumpHelper::DumpCorInfoFlag((CorInfoFlag)value.methodFlags).c_str(), - value.classFlags, - SpmiDumpHelper::DumpCorInfoFlag((CorInfoFlag)value.classFlags).c_str(), - SpmiDumpHelper::DumpAgnostic_CORINFO_SIG_INFO(value.sig, GetCallInfo, SigInstHandleMap).c_str(), - value.accessAllowed, - value.callsiteCalloutHelper.helperNum, - value.callsiteCalloutHelper.numArgs, - value.thisTransform, - value.kind, - toString((CORINFO_CALL_KIND)value.kind), - value.nullInstanceCheck, - (bool)value.nullInstanceCheck ? "true" : "false", - value.contextHandle, - value.exactContextNeedsRuntimeLookup, - (bool)value.exactContextNeedsRuntimeLookup ? "true" : "false", - SpmiDumpHelper::DumpAgnostic_CORINFO_LOOKUP(value.stubLookup).c_str(), - value.instParamLookup.accessType, - toString((InfoAccessType)value.instParamLookup.accessType), - value.instParamLookup.handle, - value.exceptionCode); -} -void MethodContext::repGetCallInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, - CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_CALLINFO_FLAGS flags, - CORINFO_CALL_INFO* pResult, - DWORD* exceptionCode) -{ - AssertMapExistsNoMessage(GetCallInfo); - - Agnostic_GetCallInfo key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.ResolvedToken = SpmiRecordsHelper::RestoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, GetCallInfo); - if (pConstrainedResolvedToken != nullptr) - { - key.ConstrainedResolvedToken = - SpmiRecordsHelper::RestoreAgnostic_CORINFO_RESOLVED_TOKEN(pConstrainedResolvedToken, GetCallInfo); - } - key.callerHandle = CastHandle(callerHandle); - key.flags = (DWORD)flags; - - Agnostic_CORINFO_CALL_INFO value = LookupByKeyOrMiss(GetCallInfo, key, ": key %08x, %016" PRIx64 "", - key.ResolvedToken.inValue.token, key.ResolvedToken.outValue.hClass); - - if (value.exceptionCode != 0) - { - // If there was an exception, the stored data is ignored. - ZeroMemory(pResult, sizeof(*pResult)); - } - else - { - pResult->hMethod = (CORINFO_METHOD_HANDLE)value.hMethod; - pResult->methodFlags = (unsigned)value.methodFlags; - // We could have stored getCallInfo from a previous call in this - // context without the CORINFO_FLG_DONT_INLINE bit. If the JIT later - // realized that this will be an always no-inline then it would call - // setMethodAttribs with that information, but a later getCallInfo call - // would not update the recorded SPMI entry. In that case let's mimic - // the behavior on the runtime side by calculating this particular - // dynamic flag here (the same logic is present in getMethodAttribs). - // - // This doesn't handle all cases (e.g. parallelism could still cause - // us to record these flags without CORINFO_FLG_DONT_INLINE). - if ((cr->repSetMethodAttribs(pResult->hMethod) & CORINFO_FLG_BAD_INLINEE) != 0) - pResult->methodFlags |= CORINFO_FLG_DONT_INLINE; - - pResult->classFlags = (unsigned)value.classFlags; - pResult->sig = SpmiRecordsHelper::Restore_CORINFO_SIG_INFO(value.sig, GetCallInfo, SigInstHandleMap, cr->getOrCreateMemoryTracker()); - pResult->accessAllowed = (CorInfoIsAccessAllowedResult)value.accessAllowed; - pResult->callsiteCalloutHelper.helperNum = (CorInfoHelpFunc)value.callsiteCalloutHelper.helperNum; - pResult->callsiteCalloutHelper.numArgs = (unsigned)value.callsiteCalloutHelper.numArgs; - for (int i = 0; i < CORINFO_ACCESS_ALLOWED_MAX_ARGS; i++) - { - pResult->callsiteCalloutHelper.args[i].constant = (size_t)value.callsiteCalloutHelper.args[i].constant; - pResult->callsiteCalloutHelper.args[i].argType = - (CorInfoAccessAllowedHelperArgType)value.callsiteCalloutHelper.args[i].argType; - } - pResult->thisTransform = (CORINFO_THIS_TRANSFORM)value.thisTransform; - pResult->kind = (CORINFO_CALL_KIND)value.kind; - pResult->nullInstanceCheck = (bool)value.nullInstanceCheck; - pResult->contextHandle = (CORINFO_CONTEXT_HANDLE)value.contextHandle; - pResult->exactContextNeedsRuntimeLookup = (bool)value.exactContextNeedsRuntimeLookup; - pResult->stubLookup = SpmiRecordsHelper::RestoreCORINFO_LOOKUP(value.stubLookup); - - if (pResult->kind == CORINFO_VIRTUALCALL_STUB) - { - cr->CallTargetTypes->Add(CastPointer(pResult->stubLookup.constLookup.addr), - (DWORD)CORINFO_VIRTUALCALL_STUB); - } - pResult->instParamLookup.accessType = (InfoAccessType)value.instParamLookup.accessType; - pResult->instParamLookup.handle = (CORINFO_GENERIC_HANDLE)value.instParamLookup.handle; - } - - *exceptionCode = (DWORD)value.exceptionCode; - - DEBUG_REP(dmpGetCallInfo(key, value)); -} - -// -// Variant of repGetCallInfo that only requires a method handle, i.e. it performs a reverse lookup to find the -// resolved token info that, along with the given method handle, was passed into getCallInfo. -// -// Arguments: -// methodHandle - The method handle to find call info for. -// pResult - [out] The call info for the given method. -// -// Notes: -// If this fails to find a recorded call to getCallInfo with the given method handle, this will throw an -// exception. -// -void MethodContext::repGetCallInfoFromMethodHandle(CORINFO_METHOD_HANDLE methodHandle, CORINFO_CALL_INFO* pResult) -{ - if (GetCallInfo != nullptr) - { - for (unsigned int i = 0; i < GetCallInfo->GetCount(); i++) - { - Agnostic_GetCallInfo key = GetCallInfo->GetKey(i); - Agnostic_CORINFO_CALL_INFO val = GetCallInfo->GetItem(i); - - if ((CORINFO_METHOD_HANDLE)val.hMethod == methodHandle) - { - CORINFO_RESOLVED_TOKEN resolvedToken; - DWORD exceptionCode; - - resolvedToken.tokenContext = (CORINFO_CONTEXT_HANDLE)key.ResolvedToken.inValue.tokenContext; - resolvedToken.tokenScope = (CORINFO_MODULE_HANDLE)key.ResolvedToken.inValue.tokenScope; - resolvedToken.token = (mdToken)key.ResolvedToken.inValue.token; - resolvedToken.tokenType = (CorInfoTokenKind)key.ResolvedToken.inValue.tokenType; - - repResolveToken(&resolvedToken, &exceptionCode); - - // If the original call to getCallInfo passed in a null constrainedResolvedToken pointer, - // then we won't be able to replay it. In that case, we'll need to pass a null pointer into - // repGetCallInfo for constrainedResolvedToken, instead of just passing the address of our - // local (but meaningless) constrainedResolvedToken struct. - CORINFO_RESOLVED_TOKEN constrainedResolvedToken; - CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken = nullptr; - - if (key.ConstrainedResolvedToken.inValue.tokenContext != 0 && - key.ConstrainedResolvedToken.inValue.tokenScope != 0) - { - constrainedResolvedToken.tokenContext = - (CORINFO_CONTEXT_HANDLE)key.ConstrainedResolvedToken.inValue.tokenContext; - constrainedResolvedToken.tokenScope = - (CORINFO_MODULE_HANDLE)key.ConstrainedResolvedToken.inValue.tokenScope; - constrainedResolvedToken.token = (mdToken)key.ConstrainedResolvedToken.inValue.token; - constrainedResolvedToken.tokenType = - (CorInfoTokenKind)key.ConstrainedResolvedToken.inValue.tokenType; - pConstrainedResolvedToken = &constrainedResolvedToken; - - repResolveToken(pConstrainedResolvedToken, &exceptionCode); - } - - repGetCallInfo(&resolvedToken, pConstrainedResolvedToken, (CORINFO_METHOD_HANDLE)key.callerHandle, - (CORINFO_CALLINFO_FLAGS)key.flags, pResult, &exceptionCode); - return; - } - } - } - - // If we reached here, we didn't find a key associated with the given method handle - LogException(EXCEPTIONCODE_MC, "Didn't find key %016" PRIX64 ".", methodHandle); -} - -void MethodContext::recExpandRawHandleIntrinsic(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_HANDLE callerHandle, CORINFO_GENERICHANDLE_RESULT* pResult) -{ - if (ExpandRawHandleIntrinsic == nullptr) - ExpandRawHandleIntrinsic = new LightWeightMap; - - Agnostic_ExpandRawHandleIntrinsic key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.ResolvedToken = SpmiRecordsHelper::CreateAgnostic_CORINFO_RESOLVED_TOKENin(pResolvedToken); - key.hCallerHandle = CastHandle(callerHandle); - - Agnostic_CORINFO_GENERICHANDLE_RESULT value; - value.lookup = SpmiRecordsHelper::StoreAgnostic_CORINFO_LOOKUP(&pResult->lookup); - value.compileTimeHandle = CastHandle(pResult->compileTimeHandle); - value.handleType = (DWORD)pResult->handleType; - - ExpandRawHandleIntrinsic->Add(key, value); - DEBUG_REC(dmpExpandRawHandleIntrinsic(key, value)); -} -void MethodContext::dmpExpandRawHandleIntrinsic(const Agnostic_ExpandRawHandleIntrinsic& key, const Agnostic_CORINFO_GENERICHANDLE_RESULT& result) -{ - printf("ExpandRawHandleIntrinsic key: %s, value %s cth-%016" PRIx64 " ht-%u", - SpmiDumpHelper::DumpAgnostic_CORINFO_RESOLVED_TOKENin(key.ResolvedToken).c_str(), - SpmiDumpHelper::DumpAgnostic_CORINFO_LOOKUP(result.lookup).c_str(), - result.compileTimeHandle, - result.handleType); -} -void MethodContext::repExpandRawHandleIntrinsic(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_HANDLE callerHandle, CORINFO_GENERICHANDLE_RESULT* pResult) -{ - Agnostic_ExpandRawHandleIntrinsic key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - - key.ResolvedToken = SpmiRecordsHelper::CreateAgnostic_CORINFO_RESOLVED_TOKENin(pResolvedToken); - key.hCallerHandle = CastHandle(callerHandle); - - Agnostic_CORINFO_GENERICHANDLE_RESULT value = - LookupByKeyOrMiss(ExpandRawHandleIntrinsic, key, ": key %x", pResolvedToken->token); - - DEBUG_REP(dmpExpandRawHandleIntrinsic(key, value)); - - pResult->lookup = SpmiRecordsHelper::RestoreCORINFO_LOOKUP(value.lookup); - pResult->compileTimeHandle = (CORINFO_GENERIC_HANDLE)value.compileTimeHandle; - pResult->handleType = (CorInfoGenericHandleType)value.handleType; -} - -void MethodContext::recIsIntrinsicType(CORINFO_CLASS_HANDLE cls, bool result) -{ - if (IsIntrinsicType == nullptr) - IsIntrinsicType = new LightWeightMap(); - - DWORDLONG key = CastHandle(cls); - DWORD value = result ? 1 : 0; - IsIntrinsicType->Add(key, value); - DEBUG_REC(dmpIsIntrinsicType(key, value)); -} -void MethodContext::dmpIsIntrinsicType(DWORDLONG key, DWORD value) -{ - printf("IsIntrinsicType key mth-%016" PRIX64 ", value intr-%u", key, value); -} -bool MethodContext::repIsIntrinsicType(CORINFO_CLASS_HANDLE cls) -{ - DWORDLONG key = CastHandle(cls); - DWORD value = LookupByKeyOrMiss(IsIntrinsicType, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpIsIntrinsicType(key, value)); - return value != 0; -} - -void MethodContext::recAsCorInfoType(CORINFO_CLASS_HANDLE cls, CorInfoType result) -{ - if (AsCorInfoType == nullptr) - AsCorInfoType = new LightWeightMap(); - - DWORDLONG key = CastHandle(cls); - DWORD value = (DWORD)result; - AsCorInfoType->Add(key, value); - DEBUG_REC(dmpAsCorInfoType(key, value)); -} -void MethodContext::dmpAsCorInfoType(DWORDLONG key, DWORD value) -{ - printf("AsCorInfoType key cls-%016" PRIX64 ", value cit-%u(%s)", key, value, toString((CorInfoType)value)); -} -CorInfoType MethodContext::repAsCorInfoType(CORINFO_CLASS_HANDLE cls) -{ - DWORDLONG key = CastHandle(cls); - DWORD value = LookupByKeyOrMiss(AsCorInfoType, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpAsCorInfoType(key, value)); - CorInfoType result = (CorInfoType)value; - return result; -} - -void MethodContext::recIsValueClass(CORINFO_CLASS_HANDLE cls, bool result) -{ - if (IsValueClass == nullptr) - IsValueClass = new LightWeightMap(); - - DWORDLONG key = CastHandle(cls); - DWORD value = result ? 1 : 0; - IsValueClass->Add(key, value); - DEBUG_REC(dmpIsValueClass(key, value)); -} -void MethodContext::dmpIsValueClass(DWORDLONG key, DWORD value) -{ - printf("IsValueClass key cls-%016" PRIX64 ", value res-%u", key, value); -} -bool MethodContext::repIsValueClass(CORINFO_CLASS_HANDLE cls) -{ - DWORDLONG key = CastHandle(cls); - DWORD value = LookupByKeyOrMiss(IsValueClass, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpIsValueClass(key, value)); - return value != 0; -} - -void MethodContext::recIsByRefLike(CORINFO_CLASS_HANDLE cls, bool result) -{ - if (IsByRefLike == nullptr) - IsByRefLike = new LightWeightMap(); - - DWORDLONG key = CastHandle(cls); - DWORD value = result ? 1 : 0; - IsByRefLike->Add(key, value); - DEBUG_REC(dmpIsByRefLike(key, value)); -} -void MethodContext::dmpIsByRefLike(DWORDLONG key, DWORD value) -{ - printf("IsByRefLike key cls-%016" PRIX64 ", value res-%u", key, value); -} -bool MethodContext::repIsByRefLike(CORINFO_CLASS_HANDLE cls) -{ - DWORDLONG key = CastHandle(cls); - DWORD value = LookupByKeyOrMiss(IsByRefLike, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpIsByRefLike(key, value)); - return value != 0; -} - -void MethodContext::recIsSharedInst(CORINFO_CLASS_HANDLE cls, bool result) -{ - if (IsSharedInst == nullptr) - IsSharedInst = new LightWeightMap(); - - DWORDLONG key = CastHandle(cls); - DWORD value = result ? 1 : 0; - IsSharedInst->Add(key, value); - DEBUG_REC(dmpIsSharedInst(key, value)); -} -void MethodContext::dmpIsSharedInst(DWORDLONG key, DWORD value) -{ - printf("IsSharedInst key cls-%016" PRIX64 ", value res-%u", key, value); -} -bool MethodContext::repIsSharedInst(CORINFO_CLASS_HANDLE cls) -{ - DWORDLONG key = CastHandle(cls); - DWORD value = LookupByKeyOrMiss(IsSharedInst, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpIsSharedInst(key, value)); - return value != 0; -} - -void MethodContext::recGetClassSize(CORINFO_CLASS_HANDLE cls, unsigned result) -{ - if (GetClassSize == nullptr) - GetClassSize = new LightWeightMap(); - - DWORDLONG key = CastHandle(cls); - DWORD value = (DWORD)result; - GetClassSize->Add(key, value); - DEBUG_REC(dmpGetClassSize(key, value)); -} -void MethodContext::dmpGetClassSize(DWORDLONG key, DWORD val) -{ - printf("GetClassSize key %016" PRIX64 ", value %u", key, val); -} -unsigned MethodContext::repGetClassSize(CORINFO_CLASS_HANDLE cls) -{ - DWORDLONG key = CastHandle(cls); - DWORD value = LookupByKeyOrMiss(GetClassSize, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetClassSize(key, value)); - unsigned result = (unsigned)value; - return result; -} - -void MethodContext::recGetHeapClassSize(CORINFO_CLASS_HANDLE cls, unsigned result) -{ - if (GetHeapClassSize == nullptr) - GetHeapClassSize = new LightWeightMap(); - - DWORDLONG key = CastHandle(cls); - DWORD value = (DWORD)result; - GetHeapClassSize->Add(key, value); - DEBUG_REC(dmpGetHeapClassSize(key, value)); -} -void MethodContext::dmpGetHeapClassSize(DWORDLONG key, DWORD val) -{ - printf("GetHeapClassSize key %016" PRIX64 ", value %u", key, val); -} -unsigned MethodContext::repGetHeapClassSize(CORINFO_CLASS_HANDLE cls) -{ - DWORDLONG key = CastHandle(cls); - DWORD value = LookupByKeyOrMiss(GetHeapClassSize, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetHeapClassSize(key, value)); - unsigned result = (unsigned)value; - return result; -} - -void MethodContext::recCanAllocateOnStack(CORINFO_CLASS_HANDLE cls, bool result) -{ - if (CanAllocateOnStack == nullptr) - CanAllocateOnStack = new LightWeightMap(); - - DWORDLONG key = CastHandle(cls); - DWORD value = result ? 1 : 0; - CanAllocateOnStack->Add(key, value); - DEBUG_REC(dmpCanAllocateOnStack(key, value)); -} -void MethodContext::dmpCanAllocateOnStack(DWORDLONG key, DWORD val) -{ - printf("CanAllocateOnStack key %016" PRIX64 ", value %u", key, val); -} -bool MethodContext::repCanAllocateOnStack(CORINFO_CLASS_HANDLE cls) -{ - DWORDLONG key = CastHandle(cls); - DWORD value = LookupByKeyOrMiss(CanAllocateOnStack, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpCanAllocateOnStack(key, value)); - return value != 0; -} - -void MethodContext::recGetClassNumInstanceFields(CORINFO_CLASS_HANDLE cls, unsigned result) -{ - if (GetClassNumInstanceFields == nullptr) - GetClassNumInstanceFields = new LightWeightMap(); - - DWORDLONG key = CastHandle(cls); - DWORD value = (DWORD)result; - GetClassNumInstanceFields->Add(key, value); - DEBUG_REC(dmpGetClassNumInstanceFields(key, value)); -} -void MethodContext::dmpGetClassNumInstanceFields(DWORDLONG key, DWORD value) -{ - printf("GetClassNumInstanceFields key cls-%016" PRIX64 ", value res-%u", key, value); -} -unsigned MethodContext::repGetClassNumInstanceFields(CORINFO_CLASS_HANDLE cls) -{ - DWORDLONG key = CastHandle(cls); - DWORD value = LookupByKeyOrMiss(GetClassNumInstanceFields, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetClassNumInstanceFields(key, value)); - unsigned result = (unsigned)value; - return result; -} - -void MethodContext::recGetNewArrHelper(CORINFO_CLASS_HANDLE arrayCls, CorInfoHelpFunc result) -{ - if (GetNewArrHelper == nullptr) - GetNewArrHelper = new LightWeightMap(); - - DWORDLONG key = CastHandle(arrayCls); - DWORD value = (DWORD)result; - GetNewArrHelper->Add(key, value); - DEBUG_REC(dmpGetNewArrHelper(key, value)); -} -void MethodContext::dmpGetNewArrHelper(DWORDLONG key, DWORD value) -{ - printf("GetNewArrHelper key cls-%016" PRIX64 ", value res-%u", key, value); -} -CorInfoHelpFunc MethodContext::repGetNewArrHelper(CORINFO_CLASS_HANDLE arrayCls) -{ - DWORDLONG key = CastHandle(arrayCls); - DWORD value = LookupByKeyOrMiss(GetNewArrHelper, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetNewArrHelper(key, value)); - CorInfoHelpFunc result = (CorInfoHelpFunc)value; - return result; -} - -void MethodContext::recGetSharedCCtorHelper(CORINFO_CLASS_HANDLE clsHnd, CorInfoHelpFunc result) -{ - if (GetSharedCCtorHelper == nullptr) - GetSharedCCtorHelper = new LightWeightMap(); - - DWORDLONG key = CastHandle(clsHnd); - DWORD value = (DWORD)result; - GetSharedCCtorHelper->Add(key, value); - DEBUG_REC(dmpGetSharedCCtorHelper(key, value)); -} -void MethodContext::dmpGetSharedCCtorHelper(DWORDLONG key, DWORD value) -{ - printf("GetSharedCCtorHelper key cls-%016" PRIX64 ", value res-%u", key, value); -} -CorInfoHelpFunc MethodContext::repGetSharedCCtorHelper(CORINFO_CLASS_HANDLE clsHnd) -{ - DWORDLONG key = CastHandle(clsHnd); - DWORD value = LookupByKeyOrMiss(GetSharedCCtorHelper, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetSharedCCtorHelper(key, value)); - CorInfoHelpFunc result = (CorInfoHelpFunc)value; - return result; -} - -void MethodContext::recGetTypeForBox(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE result) -{ - if (GetTypeForBox == nullptr) - GetTypeForBox = new LightWeightMap(); - - DWORDLONG key = CastHandle(cls); - DWORDLONG value = CastHandle(result); - GetTypeForBox->Add(key, value); - DEBUG_REC(dmpGetTypeForBox(key, value)); -} -void MethodContext::dmpGetTypeForBox(DWORDLONG key, DWORDLONG value) -{ - printf("GetTypeForBox key cls-%016" PRIX64 ", value res-%016" PRIX64 "", key, value); -} -CORINFO_CLASS_HANDLE MethodContext::repGetTypeForBox(CORINFO_CLASS_HANDLE cls) -{ - DWORDLONG key = CastHandle(cls); - DWORDLONG value = LookupByKeyOrMiss(GetTypeForBox, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetTypeForBox(key, value)); - CORINFO_CLASS_HANDLE result = (CORINFO_CLASS_HANDLE)value; - return result; -} - -void MethodContext::recGetBoxHelper(CORINFO_CLASS_HANDLE cls, CorInfoHelpFunc result) -{ - if (GetBoxHelper == nullptr) - GetBoxHelper = new LightWeightMap(); - - DWORDLONG key = CastHandle(cls); - DWORD value = (DWORD)result; - GetBoxHelper->Add(key, value); - DEBUG_REC(dmpGetBoxHelper(key, value)); -} -void MethodContext::dmpGetBoxHelper(DWORDLONG key, DWORD value) -{ - printf("GetBoxHelper key cls-%016" PRIX64 ", value res-%u", key, value); -} -CorInfoHelpFunc MethodContext::repGetBoxHelper(CORINFO_CLASS_HANDLE cls) -{ - DWORDLONG key = CastHandle(cls); - DWORD value = LookupByKeyOrMiss(GetBoxHelper, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetBoxHelper(key, value)); - CorInfoHelpFunc result = (CorInfoHelpFunc)value; - return result; -} - -void MethodContext::recGetBuiltinClass(CorInfoClassId classId, CORINFO_CLASS_HANDLE result) -{ - if (GetBuiltinClass == nullptr) - GetBuiltinClass = new LightWeightMap(); - - DWORD key = (DWORD)classId; - DWORDLONG value = CastHandle(result); - GetBuiltinClass->Add(key, value); - DEBUG_REC(dmpGetBuiltinClass(key, value)); -} -void MethodContext::dmpGetBuiltinClass(DWORD key, DWORDLONG value) -{ - printf("GetBuiltinClass key cls-%08X, value cls-%016" PRIX64 "", key, value); -} -CORINFO_CLASS_HANDLE MethodContext::repGetBuiltinClass(CorInfoClassId classId) -{ - DWORD key = (DWORD)classId; - DWORDLONG value = LookupByKeyOrMiss(GetBuiltinClass, key, ": key %08X", key); - DEBUG_REP(dmpGetBuiltinClass(key, value)); - CORINFO_CLASS_HANDLE result = (CORINFO_CLASS_HANDLE)value; - return result; -} - -void MethodContext::recGetTypeForPrimitiveValueClass(CORINFO_CLASS_HANDLE cls, CorInfoType result) -{ - if (GetTypeForPrimitiveValueClass == nullptr) - GetTypeForPrimitiveValueClass = new LightWeightMap(); - - DWORDLONG key = CastHandle(cls); - DWORD value = (DWORD)result; - GetTypeForPrimitiveValueClass->Add(key, value); - DEBUG_REC(dmpGetTypeForPrimitiveValueClass(key, value)); -} -void MethodContext::dmpGetTypeForPrimitiveValueClass(DWORDLONG key, DWORD value) -{ - printf("GetTypeForPrimitiveValueClass key cls-%016" PRIX64 ", value cit-%u(%s)", key, value, toString((CorInfoType)value)); -} -CorInfoType MethodContext::repGetTypeForPrimitiveValueClass(CORINFO_CLASS_HANDLE cls) -{ - DWORDLONG key = CastHandle(cls); - DWORD value = LookupByKeyOrMiss(GetTypeForPrimitiveValueClass, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetTypeForPrimitiveValueClass(key, value)); - CorInfoType result = (CorInfoType)value; - return result; -} - -void MethodContext::recGetTypeForPrimitiveNumericClass(CORINFO_CLASS_HANDLE cls, CorInfoType result) -{ - if (GetTypeForPrimitiveNumericClass == nullptr) - GetTypeForPrimitiveNumericClass = new LightWeightMap(); - - DWORDLONG key = CastHandle(cls); - DWORD value = (DWORD)result; - GetTypeForPrimitiveNumericClass->Add(key, value); - DEBUG_REC(dmpGetTypeForPrimitiveNumericClass(key, value)); -} -void MethodContext::dmpGetTypeForPrimitiveNumericClass(DWORDLONG key, DWORD value) -{ - printf("GetTypeForPrimitiveNumericClass key cls-%016" PRIX64 ", value cit-%u(%s)", key, value, - toString((CorInfoType)value)); -} -CorInfoType MethodContext::repGetTypeForPrimitiveNumericClass(CORINFO_CLASS_HANDLE cls) -{ - DWORDLONG key = CastHandle(cls); - DWORD value = LookupByKeyOrMiss(GetTypeForPrimitiveNumericClass, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetTypeForPrimitiveNumericClass(key, value)); - CorInfoType result = (CorInfoType)value; - return result; -} - -void MethodContext::recGetParentType(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE result) -{ - if (GetParentType == nullptr) - GetParentType = new LightWeightMap(); - - DWORDLONG key = CastHandle(cls); - DWORDLONG value = CastHandle(result); - GetParentType->Add(key, value); - DEBUG_REC(dmpGetParentType(key, value)); -} -void MethodContext::dmpGetParentType(DWORDLONG key, DWORDLONG value) -{ - printf("GetParentType key cls-%016" PRIX64 ", value cls-%016" PRIX64 "", key, value); -} -CORINFO_CLASS_HANDLE MethodContext::repGetParentType(CORINFO_CLASS_HANDLE cls) -{ - DWORDLONG key = CastHandle(cls); - DWORDLONG value = LookupByKeyOrMiss(GetParentType, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetParentType(key, value)); - CORINFO_CLASS_HANDLE result = (CORINFO_CLASS_HANDLE)value; - return result; -} - -void MethodContext::recIsSDArray(CORINFO_CLASS_HANDLE cls, bool result) -{ - if (IsSDArray == nullptr) - IsSDArray = new LightWeightMap(); - - DWORDLONG key = CastHandle(cls); - DWORD value = result ? 1 : 0; - IsSDArray->Add(key, value); - DEBUG_REC(dmpIsSDArray(key, value)); -} -void MethodContext::dmpIsSDArray(DWORDLONG key, DWORD value) -{ - printf("IsSDArray key cls-%016" PRIX64 ", value res-%u", key, value); -} -bool MethodContext::repIsSDArray(CORINFO_CLASS_HANDLE cls) -{ - DWORDLONG key = CastHandle(cls); - DWORD value = LookupByKeyOrMiss(IsSDArray, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpIsSDArray(key, value)); - return value != 0; -} - -void MethodContext::recGetFieldClass(CORINFO_FIELD_HANDLE field, CORINFO_CLASS_HANDLE result) -{ - if (GetFieldClass == nullptr) - GetFieldClass = new LightWeightMap(); - - DWORDLONG key = CastHandle(field); - DWORDLONG value = CastHandle(result); - GetFieldClass->Add(key, value); - DEBUG_REC(dmpGetFieldClass(key, value)); -} -void MethodContext::dmpGetFieldClass(DWORDLONG key, DWORDLONG value) -{ - printf("GetFieldClass key %016" PRIX64 ", value %016" PRIX64 "", key, value); -} -CORINFO_CLASS_HANDLE MethodContext::repGetFieldClass(CORINFO_FIELD_HANDLE field) -{ - DWORDLONG key = CastHandle(field); - DWORDLONG value = LookupByKeyOrMiss(GetFieldClass, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetFieldClass(key, value)); - CORINFO_CLASS_HANDLE result = (CORINFO_CLASS_HANDLE)value; - return result; -} - -void MethodContext::recGetFieldOffset(CORINFO_FIELD_HANDLE field, unsigned result) -{ - if (GetFieldOffset == nullptr) - GetFieldOffset = new LightWeightMap(); - - DWORDLONG key = CastHandle(field); - DWORD value = (DWORD)result; - GetFieldOffset->Add(key, value); - DEBUG_REC(dmpGetFieldOffset(key, value)); -} -void MethodContext::dmpGetFieldOffset(DWORDLONG key, DWORD value) -{ - printf("GetFieldOffset key FLD-%016" PRIX64 ", value %08X", key, value); -} -unsigned MethodContext::repGetFieldOffset(CORINFO_FIELD_HANDLE field) -{ - DWORDLONG key = CastHandle(field); - DWORD value = LookupByKeyOrMiss(GetFieldOffset, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetFieldOffset(key, value)); - unsigned result = (unsigned)value; - return result; -} - -void MethodContext::recGetUnBoxHelper(CORINFO_CLASS_HANDLE cls, CorInfoHelpFunc result) -{ - if (GetUnBoxHelper == nullptr) - GetUnBoxHelper = new LightWeightMap(); - - DWORDLONG key = CastHandle(cls); - DWORD value = (DWORD)result; - GetUnBoxHelper->Add(key, value); - DEBUG_REC(dmpGetUnBoxHelper(key, value)); -} -void MethodContext::dmpGetUnBoxHelper(DWORDLONG key, DWORD value) -{ - printf("GetUnBoxHelper key cls-%016" PRIX64 ", value res-%u", key, value); -} -CorInfoHelpFunc MethodContext::repGetUnBoxHelper(CORINFO_CLASS_HANDLE cls) -{ - DWORDLONG key = CastHandle(cls); - DWORD value = LookupByKeyOrMiss(GetUnBoxHelper, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetUnBoxHelper(key, value)); - CorInfoHelpFunc result = (CorInfoHelpFunc)value; - return result; -} - -void MethodContext::recGetRuntimeTypePointer(CORINFO_CLASS_HANDLE cls, CORINFO_OBJECT_HANDLE result) -{ - if (GetRuntimeTypePointer == nullptr) - GetRuntimeTypePointer = new LightWeightMap(); - - DWORDLONG key = CastHandle(cls); - DWORDLONG value = CastHandle(result); - GetRuntimeTypePointer->Add(key, value); - DEBUG_REC(dmpGetRuntimeTypePointer(key, value)); -} -void MethodContext::dmpGetRuntimeTypePointer(DWORDLONG key, DWORDLONG value) -{ - printf("GetRuntimeTypePointer key cls-%016" PRIX64 ", value res-%016" PRIX64 "", key, value); -} -CORINFO_OBJECT_HANDLE MethodContext::repGetRuntimeTypePointer(CORINFO_CLASS_HANDLE cls) -{ - DWORDLONG key = CastHandle(cls); - DWORDLONG value = LookupByKeyOrMiss(GetRuntimeTypePointer, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetRuntimeTypePointer(key, value)); - return (CORINFO_OBJECT_HANDLE)value; -} - -void MethodContext::recIsObjectImmutable(CORINFO_OBJECT_HANDLE objPtr, bool result) -{ - if (IsObjectImmutable == nullptr) - IsObjectImmutable = new LightWeightMap(); - - DWORDLONG key = CastHandle(objPtr); - DWORD value = (DWORD)result; - IsObjectImmutable->Add(key, value); - DEBUG_REC(dmpIsObjectImmutable(key, value)); -} -void MethodContext::dmpIsObjectImmutable(DWORDLONG key, DWORD value) -{ - printf("IsObjectImmutable key obj-%016" PRIX64 ", value res-%u", key, value); -} -bool MethodContext::repIsObjectImmutable(CORINFO_OBJECT_HANDLE objPtr) -{ - DWORDLONG key = CastHandle(objPtr); - DWORD value = LookupByKeyOrMiss(IsObjectImmutable, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpIsObjectImmutable(key, value)); - return (bool)value; -} - -void MethodContext::recGetStringChar(CORINFO_OBJECT_HANDLE strObj, int index, uint16_t* charValue, bool result) -{ - if (GetStringChar == nullptr) - GetStringChar = new LightWeightMap(); - - DLD key; - ZeroMemory(&key, sizeof(key)); - key.A = CastHandle(strObj); - key.B = (DWORD)index; - - DD value; - ZeroMemory(&value, sizeof(value)); - value.A = (DWORD)result; - value.B = (DWORD)*charValue; - - GetStringChar->Add(key, value); - DEBUG_REC(dmpGetStringChar(key, value)); -} -void MethodContext::dmpGetStringChar(DLD key, DD value) -{ - printf("IsObjectImmutable key obj-%016" PRIX64 ", index-%u, value res-%u, val-%u", key.A, key.B, value.A, value.B); -} -bool MethodContext::repGetStringChar(CORINFO_OBJECT_HANDLE strObj, int index, uint16_t* charValue) -{ - DLD key; - ZeroMemory(&key, sizeof(key)); - key.A = CastHandle(strObj); - key.B = (DWORD)index; - - DD value = LookupByKeyOrMiss(GetStringChar, key, ": key %016" PRIX64 "", key.A); - - DEBUG_REP(dmpGetStringChar(key, value)); - *charValue = (uint16_t)value.B; - return (bool)value.A; -} - -void MethodContext::recGetObjectType(CORINFO_OBJECT_HANDLE objPtr, CORINFO_CLASS_HANDLE result) -{ - if (GetObjectType == nullptr) - GetObjectType = new LightWeightMap(); - - DWORDLONG key = CastHandle(objPtr); - DWORDLONG value = CastHandle(result); - GetObjectType->Add(key, value); - DEBUG_REC(dmpGetObjectType(key, value)); -} -void MethodContext::dmpGetObjectType(DWORDLONG key, DWORDLONG value) -{ - printf("GetObjectType key obj-%016" PRIX64 ", value res-%016" PRIX64 "", key, value); -} -CORINFO_CLASS_HANDLE MethodContext::repGetObjectType(CORINFO_OBJECT_HANDLE objPtr) -{ - DWORDLONG key = CastHandle(objPtr); - DWORDLONG value = LookupByKeyOrMiss(GetObjectType, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetObjectType(key, value)); - return (CORINFO_CLASS_HANDLE)value; -} - -void MethodContext::recGetReadyToRunHelper(CORINFO_RESOLVED_TOKEN* pResolvedToken, - CorInfoHelpFunc id, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_CONST_LOOKUP* pLookup, - bool result) -{ - if (GetReadyToRunHelper == nullptr) - GetReadyToRunHelper = new LightWeightMap(); - - GetReadyToRunHelper_TOKENin key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.ResolvedToken = SpmiRecordsHelper::StoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, GetReadyToRunHelper); - key.id = (DWORD)id; - key.callerHandle = CastHandle(callerHandle); - GetReadyToRunHelper_TOKENout value; - value.Lookup = SpmiRecordsHelper::StoreAgnostic_CORINFO_CONST_LOOKUP(pLookup); - value.result = result; - - GetReadyToRunHelper->Add(key, value); - DEBUG_REC(dmpGetReadyToRunHelper(key, value)); -} - -void MethodContext::dmpGetReadyToRunHelper(GetReadyToRunHelper_TOKENin key, GetReadyToRunHelper_TOKENout value) -{ - printf("GetReadyToRunHelper key: tk{%s} id-%u", - SpmiDumpHelper::DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.ResolvedToken).c_str(), key.id); - printf(", value: lk{ %s } %u", SpmiDumpHelper::DumpAgnostic_CORINFO_CONST_LOOKUP(value.Lookup).c_str(), - value.result); -} - -bool MethodContext::repGetReadyToRunHelper(CORINFO_RESOLVED_TOKEN* pResolvedToken, - CorInfoHelpFunc id, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_CONST_LOOKUP* pLookup) -{ - AssertMapExistsNoMessage(GetReadyToRunHelper); - - GetReadyToRunHelper_TOKENin key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.ResolvedToken = SpmiRecordsHelper::RestoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, GetReadyToRunHelper); - key.id = (DWORD)id; - key.callerHandle = CastHandle(callerHandle); - - GetReadyToRunHelper_TOKENout value = LookupByKeyOrMissNoMessage(GetReadyToRunHelper, key); - - DEBUG_REP(dmpGetReadyToRunHelper(key, value)); - - *pLookup = SpmiRecordsHelper::RestoreCORINFO_CONST_LOOKUP(value.Lookup); - return value.result; -} - -void MethodContext::recGetReadyToRunDelegateCtorHelper(CORINFO_RESOLVED_TOKEN* pTargetMethod, - mdToken targetConstraint, - CORINFO_CLASS_HANDLE delegateType, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_LOOKUP* pLookup) -{ - if (GetReadyToRunDelegateCtorHelper == nullptr) - GetReadyToRunDelegateCtorHelper = - new LightWeightMap(); - - GetReadyToRunDelegateCtorHelper_TOKENIn key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.TargetMethod = - SpmiRecordsHelper::StoreAgnostic_CORINFO_RESOLVED_TOKEN(pTargetMethod, GetReadyToRunDelegateCtorHelper); - key.targetConstraint = targetConstraint; - key.delegateType = CastHandle(delegateType); - key.callerHandle = CastHandle(callerHandle); - Agnostic_CORINFO_LOOKUP value = SpmiRecordsHelper::StoreAgnostic_CORINFO_LOOKUP(pLookup); - GetReadyToRunDelegateCtorHelper->Add(key, value); - DEBUG_REC(dmpGetReadyToRunDelegateCtorHelper(key, value)); -} - -void MethodContext::dmpGetReadyToRunDelegateCtorHelper(GetReadyToRunDelegateCtorHelper_TOKENIn key, - Agnostic_CORINFO_LOOKUP value) -{ - printf("GetReadyToRunDelegateCtorHelper key: method tk{%s} type-%016" PRIX64 " constraint-%08X", - SpmiDumpHelper::DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.TargetMethod).c_str(), key.delegateType, key.targetConstraint); - printf(", value: %s", SpmiDumpHelper::DumpAgnostic_CORINFO_LOOKUP(value).c_str()); -} - -void MethodContext::repGetReadyToRunDelegateCtorHelper(CORINFO_RESOLVED_TOKEN* pTargetMethod, - mdToken targetConstraint, - CORINFO_CLASS_HANDLE delegateType, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_LOOKUP* pLookup) -{ - AssertMapExistsNoMessage(GetReadyToRunDelegateCtorHelper); - - GetReadyToRunDelegateCtorHelper_TOKENIn key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.TargetMethod = - SpmiRecordsHelper::RestoreAgnostic_CORINFO_RESOLVED_TOKEN(pTargetMethod, GetReadyToRunDelegateCtorHelper); - key.targetConstraint = targetConstraint; - key.delegateType = CastHandle(delegateType); - key.callerHandle = CastHandle(callerHandle); - - Agnostic_CORINFO_LOOKUP value = LookupByKeyOrMissNoMessage(GetReadyToRunDelegateCtorHelper, key); - - DEBUG_REP(dmpGetReadyToRunDelegateCtorHelper(key, value)); - - *pLookup = SpmiRecordsHelper::RestoreCORINFO_LOOKUP(value); -} - -void MethodContext::recGetHelperFtn(CorInfoHelpFunc ftnNum, CORINFO_CONST_LOOKUP pNativeEntrypoint,CORINFO_METHOD_HANDLE methodHandle) -{ - if (GetHelperFtn == nullptr) - GetHelperFtn = new LightWeightMap(); - - DWORD key = (DWORD)ftnNum; - - Agnostic_GetHelperFtn value; - value.helperLookup = SpmiRecordsHelper::StoreAgnostic_CORINFO_CONST_LOOKUP(&pNativeEntrypoint); - value.helperMethod = CastHandle(methodHandle); - - GetHelperFtn->Add(key, value); - DEBUG_REC(dmpGetHelperFtn(key, value)); -} -void MethodContext::dmpGetHelperFtn(DWORD key, Agnostic_GetHelperFtn value) -{ - printf("GetHelperFtn key ftn-%u nativeEntrypoint {%s}, helperMethod-%016" PRIX64 "", key, - SpmiDumpHelper::DumpAgnostic_CORINFO_CONST_LOOKUP(value.helperLookup).c_str(), - value.helperMethod); -} - -void MethodContext::repGetHelperFtn(CorInfoHelpFunc ftnNum, CORINFO_CONST_LOOKUP* pNativeEntrypoint,CORINFO_METHOD_HANDLE *pMethodHandle) -{ - DWORD key = (DWORD)ftnNum; - Agnostic_GetHelperFtn value = LookupByKeyOrMiss(GetHelperFtn, key, ": key %u", key); - DEBUG_REP(dmpGetHelperFtn(key, value)); - - if (pNativeEntrypoint != nullptr) - { - *pNativeEntrypoint = SpmiRecordsHelper::RestoreCORINFO_CONST_LOOKUP(value.helperLookup); - } - if (pMethodHandle != nullptr) - { - *pMethodHandle = (CORINFO_METHOD_HANDLE)value.helperMethod; - } -} - -// -// Finds the identifier (i.e. the CorInfoHelpFunc enum) of a helper function, based on the address where it -// is located in memory. -// -// Arguments: -// functionAddress - The starting address of the helper function in memory. -// pResult - [out] Pointer to write out the identifier of the helper function located at the given -// address. -// -// Return Value: -// True if there is a helper function associated with the given target address; false otherwise. -// -// Notes: -// - This might not work correctly with method contexts recorded via NGen compilation; it doesn't compare -// the ppIndirection value. -// -bool MethodContext::fndGetHelperFtn(void* functionAddress, CorInfoHelpFunc* pResult) -{ - if (GetHelperFtn != nullptr) - { - for (unsigned int i = 0; i < GetHelperFtn->GetCount(); i++) - { - DWORD key = GetHelperFtn->GetKey(i); - Agnostic_GetHelperFtn val = GetHelperFtn->GetItem(i); - - // TODO-Cleanup: this only compares the function addresses, and doesn't account for - // ppIndirection, which will break if the helper is a dynamic helper function. - if (val.helperLookup.handle == CastPointer(functionAddress)) - { - *pResult = (CorInfoHelpFunc)key; - return true; - } - } - } - - LogDebug("fndGetHelperFtn - didn't find value %p", functionAddress); - return false; -} - -void MethodContext::recGetJustMyCodeHandle(CORINFO_METHOD_HANDLE method, - CORINFO_JUST_MY_CODE_HANDLE** ppIndirection, - CORINFO_JUST_MY_CODE_HANDLE result) -{ - if (GetJustMyCodeHandle == nullptr) - GetJustMyCodeHandle = new LightWeightMap(); - - DLDL value; - value.A = CastPointer(*ppIndirection); - value.B = CastHandle(result); - - DWORDLONG key = CastHandle(method); - GetJustMyCodeHandle->Add(key, value); - DEBUG_REC(dmpGetJustMyCodeHandle(key, value)); -} -void MethodContext::dmpGetJustMyCodeHandle(DWORDLONG key, DLDL value) -{ - printf("GetJustMyCodeHandle key ftn-%016" PRIX64 ", value pp-%016" PRIX64 ", res-%016" PRIX64 "", key, value.A, value.B); -} -CORINFO_JUST_MY_CODE_HANDLE MethodContext::repGetJustMyCodeHandle(CORINFO_METHOD_HANDLE method, - CORINFO_JUST_MY_CODE_HANDLE** ppIndirection) -{ - DWORDLONG key = CastHandle(method); - DLDL value = LookupByKeyOrMiss(GetJustMyCodeHandle, key, ": key %016" PRIX64 "", key); - - DEBUG_REP(dmpGetJustMyCodeHandle(key, value)); - - *ppIndirection = (CORINFO_JUST_MY_CODE_HANDLE*)value.A; - CORINFO_JUST_MY_CODE_HANDLE result = (CORINFO_JUST_MY_CODE_HANDLE)value.B; - return result; -} - -void MethodContext::recGetFunctionEntryPoint(CORINFO_METHOD_HANDLE ftn, - CORINFO_CONST_LOOKUP* pResult, - CORINFO_ACCESS_FLAGS accessFlags) -{ - if (GetFunctionEntryPoint == nullptr) - GetFunctionEntryPoint = new LightWeightMap(); - - DLD key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(ftn); - key.B = (DWORD)accessFlags; - - DLD value; - value.A = CastPointer(pResult->addr); // First union member - value.B = (DWORD)pResult->accessType; - - GetFunctionEntryPoint->Add(key, value); - DEBUG_REC(dmpGetFunctionEntryPoint(key, value)); -} -void MethodContext::dmpGetFunctionEntryPoint(DLD key, DLD value) -{ - printf("GetFunctionEntryPoint key ftn-%016" PRIX64 " af-%08X, value add-%016" PRIX64 " at-%u", key.A, key.B, value.A, value.B); -} -void MethodContext::repGetFunctionEntryPoint(CORINFO_METHOD_HANDLE ftn, - CORINFO_CONST_LOOKUP* pResult, - CORINFO_ACCESS_FLAGS accessFlags) -{ - DLD key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(ftn); - key.B = (DWORD)accessFlags; - - if (GetFunctionEntryPoint == nullptr) - { -#ifdef sparseMC - LogDebug("Sparse - repGetFunctionEntryPoint fabricated result for request."); - pResult->accessType = (InfoAccessType)IAT_PVALUE; - pResult->addr = (void*)(CastHandle(ftn) + 0x1c); - return; -#else - LogException(EXCEPTIONCODE_MC, "Didn't find %016" PRIX64 ", %8x", CastHandle(ftn), accessFlags); -#endif - } - if (GetFunctionEntryPoint->GetIndex(key) == -1) - { -#ifdef sparseMC - key.B ^= (DWORD)CORINFO_ACCESS_NONNULL; - if (GetFunctionEntryPoint->GetIndex(key) != -1) - { - LogDebug("Sparse - repGetFunctionEntryPoint found result with inverted CORINFO_ACCESS_NONNULL"); - } - else - { - LogDebug("Sparse - repGetFunctionEntryPoint fabricated result for request."); - pResult->accessType = (InfoAccessType)IAT_PVALUE; - pResult->addr = (void*)(CastHandle(ftn) + 0x1c); - return; - } -#else - LogException(EXCEPTIONCODE_MC, "Didn't find %016" PRIX64 ", %8x", CastHandle(ftn), accessFlags); -#endif - } - - DLD value = GetFunctionEntryPoint->Get(key); - DEBUG_REP(dmpGetFunctionEntryPoint(key, value)); - - pResult->accessType = (InfoAccessType)value.B; - pResult->addr = (void*)value.A; -} - -// -// Finds the method handle associated with a method, based on the address where its generated code is located -// in memory. -// -// Arguments: -// methodAddress - The starting address of the generated code for the method. -// pResult - [out] Pointer to a method handle to write into. If this successfully finds a method -// handle associated with the given target address, it will be written to here. -// -// Return Value: -// True if there is a function associated with the given target address; false otherwise. -// -// Assumptions: -// - The given method address does not point to a jump stub. -// - The given method is not a generic method. -// - Only the lower 32 bits of the method address are necessary to identify the method. -// -// Notes: -// On 64-bit platforms, this only checks if the lower 32 bits of the method address match a recorded -// function entry point because, on AMD64, this only supports reverse lookups for near calls, which -// encode their target address as a 32-bit PC-relative displacement. -// -// Practically speaking, there are two concrete reasons why we ignore the upper 64 bits. First, on -// AMD64, when the JIT emits a near call, it records the displacement it encodes into the call with -// the EE as a 32-bit relative "relocation". Consequently, this leads to the second reason why we -// ignore the upper 64 bits: when SuperPMI is replaying method compilation, it patches up addresses -// based on the "relocations" the JIT had previously recorded with the EE. Since these relocations -// are only 32-bit deltas, what you'll usually end up seeing is that, after SuperPMI has applied -// these fixups, the lower 32 bits of method addresses will match, but the upper 32 bits will differ. -// -bool MethodContext::fndGetFunctionEntryPoint(DLD value, CORINFO_METHOD_HANDLE* pResult) -{ - if (GetFunctionEntryPoint != nullptr) - { - for (unsigned int i = 0; i < GetFunctionEntryPoint->GetCount(); i++) - { - DLD key = GetFunctionEntryPoint->GetKey(i); - DLD val = GetFunctionEntryPoint->GetItem(i); - - // TODO-Cleanup: we should be more conscious of the rest of the information in CORINFO_CONST_LOOKUP - if ((DWORD)val.A == (DWORD)value.A) - { - *pResult = (CORINFO_METHOD_HANDLE)key.A; - return true; - } - } - } - - LogDebug("fndGetFunctionEntryPoint - didn't find value %016" PRIX64 "", value.A); - return false; -} - -void MethodContext::recConstructStringLiteral(CORINFO_MODULE_HANDLE moduleHandle, - mdToken metaTok, - void* pValue, - InfoAccessType result) -{ - if (ConstructStringLiteral == nullptr) - ConstructStringLiteral = new LightWeightMap(); - - DLD key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(moduleHandle); - key.B = (DWORD)metaTok; - - DLD value; - value.A = CastPointer(pValue); - value.B = (DWORD)result; - - ConstructStringLiteral->Add(key, value); - DEBUG_REC(dmpConstructStringLiteral(key, value)); -} -void MethodContext::dmpConstructStringLiteral(DLD key, DLD value) -{ - printf("ConstructStringLiteral key mod-%016" PRIX64 " tok-%08X, value pp-%016" PRIX64 " iat-%u", key.A, key.B, value.A, value.B); -} -InfoAccessType MethodContext::repConstructStringLiteral(CORINFO_MODULE_HANDLE moduleHandle, mdToken metaTok, void** ppValue) -{ - DLD key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(moduleHandle); - key.B = (DWORD)metaTok; - - DLD value = LookupByKeyOrMiss(ConstructStringLiteral, key, ": key %016" PRIX64 "", CastHandle(moduleHandle)); - - DEBUG_REP(dmpConstructStringLiteral(key, value)); - - *ppValue = (void*)value.A; - return (InfoAccessType)value.B; -} - -void MethodContext::recConvertPInvokeCalliToCall(CORINFO_RESOLVED_TOKEN* pResolvedToken, bool fMustConvert, bool result) -{ - if (ConvertPInvokeCalliToCall == nullptr) - ConvertPInvokeCalliToCall = new LightWeightMap(); - - DLD key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(pResolvedToken->tokenScope); - key.B = (DWORD)pResolvedToken->token; - - DLDL value; - value.A = CastHandle(result ? pResolvedToken->hClass : 0); - value.B = CastHandle(result ? pResolvedToken->hMethod : 0); - - ConvertPInvokeCalliToCall->Add(key, value); - DEBUG_REC(dmpConvertPInvokeCalliToCall(key, value)); -} -void MethodContext::dmpConvertPInvokeCalliToCall(DLD key, DLDL value) -{ - printf("ConvertPInvokeCalliToCall key mod-%016" PRIX64 " tok-%08X, value cls-%016" PRIX64 " meth-%016" PRIX64 "", - key.A, key.B, value.A, value.B); -} -bool MethodContext::repConvertPInvokeCalliToCall(CORINFO_RESOLVED_TOKEN* pResolvedToken, bool fMustConvert) -{ - AssertMapExistsNoMessage(ConvertPInvokeCalliToCall); - - DLD key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(pResolvedToken->tokenScope); - key.B = (DWORD)pResolvedToken->token; - - DLDL value = LookupByKeyOrMissNoMessage(ConvertPInvokeCalliToCall, key); - DEBUG_REP(dmpConvertPInvokeCalliToCall(key, value)); - - pResolvedToken->hClass = (CORINFO_CLASS_HANDLE)value.A; - pResolvedToken->hMethod = (CORINFO_METHOD_HANDLE)value.B; - return value.B != 0; -} - -void MethodContext::recEmptyStringLiteral(void** pValue, InfoAccessType result) -{ - if (EmptyStringLiteral == nullptr) - EmptyStringLiteral = new DenseLightWeightMap(); - DLD temp2; - temp2.A = CastPointer(*pValue); - temp2.B = (DWORD)result; - - EmptyStringLiteral->Append(temp2); -} -void MethodContext::dmpEmptyStringLiteral(DWORD key, DLD value) -{ - printf("EmptyStringLiteral key %u, value pVal-%016" PRIX64 " res-%u", key, value.A, value.B); -} -InfoAccessType MethodContext::repEmptyStringLiteral(void** ppValue) -{ - // TODO-Cleanup: sketchy if someone calls this twice - DLD temp2; - temp2 = LookupByKeyOrMissNoMessage(EmptyStringLiteral, 0); - - *ppValue = (void*)temp2.A; - return (InfoAccessType)temp2.B; -} - -void MethodContext::recGetArgType(CORINFO_SIG_INFO* sig, - CORINFO_ARG_LIST_HANDLE args, - CORINFO_CLASS_HANDLE* vcTypeRet, - CorInfoTypeWithMod result, - DWORD exceptionCode) -{ - if (GetArgType == nullptr) - GetArgType = new LightWeightMap(); - - Agnostic_GetArgType_Key key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - - // Only setting values for CORINFO_SIG_INFO things the EE seems to pay attention to... this is necessary since some of the values - // are unset and fail our precise comparisons ... - // TODO: verify that the above comment is still true (that some of the fields of incoming argument `sig` contain garbage), or - // can we store the whole thing and use StoreAgnostic_CORINFO_SIG_INFO()? - - key.flags = (DWORD)sig->flags; - key.numArgs = (DWORD)sig->numArgs; - - SpmiRecordsHelper::StoreAgnostic_CORINFO_SIG_INST_HandleArray(sig->sigInst.classInstCount, sig->sigInst.classInst, SigInstHandleMap, &key.sigInst_classInstCount, &key.sigInst_classInst_Index); - SpmiRecordsHelper::StoreAgnostic_CORINFO_SIG_INST_HandleArray(sig->sigInst.methInstCount, sig->sigInst.methInst, SigInstHandleMap, &key.sigInst_methInstCount, &key.sigInst_methInst_Index); - - key.methodSignature = CastPointer(sig->methodSignature); - key.scope = CastHandle(sig->scope); - key.args = CastHandle(args); - - Agnostic_GetArgType_Value value; - value.vcTypeRet = CastHandle(*vcTypeRet); - value.result = (DWORD)result; - value.exceptionCode = (DWORD)exceptionCode; - - GetArgType->Add(key, value); - DEBUG_REC(dmpGetArgType(key, value)); -} - -void MethodContext::dmpGetArgType(const Agnostic_GetArgType_Key& key, const Agnostic_GetArgType_Value& value) -{ - printf("GetArgType key flg-%08X na-%u %s %s msig-%016" PRIX64 " scp-%016" PRIX64 " arg-%016" PRIX64 "", - key.flags, key.numArgs, - SpmiDumpHelper::DumpAgnostic_CORINFO_SIG_INST_Element("", "cc", "ci", key.sigInst_classInstCount, key.sigInst_classInst_Index, SigInstHandleMap).c_str(), - SpmiDumpHelper::DumpAgnostic_CORINFO_SIG_INST_Element("", "mc", "mi", key.sigInst_methInstCount, key.sigInst_methInst_Index, SigInstHandleMap).c_str(), - key.methodSignature, key.scope, key.args); - printf(", value result(cit)-%u(%s) vcType-%016" PRIX64 " excp-%08X", value.result, toString((CorInfoTypeWithMod)value.result), value.vcTypeRet, value.exceptionCode); -} - -CorInfoTypeWithMod MethodContext::repGetArgType(CORINFO_SIG_INFO* sig, - CORINFO_ARG_LIST_HANDLE args, - CORINFO_CLASS_HANDLE* vcTypeRet, - DWORD* exceptionCode) -{ - AssertMapExists(GetArgType, ": key %016" PRIX64 " %016" PRIX64 "", CastHandle(sig->scope), CastHandle(args)); - - Agnostic_GetArgType_Key key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.flags = (DWORD)sig->flags; - key.numArgs = (DWORD)sig->numArgs; - key.sigInst_classInstCount = (DWORD)sig->sigInst.classInstCount; - key.sigInst_methInstCount = (DWORD)sig->sigInst.methInstCount; - key.methodSignature = CastPointer(sig->methodSignature); - key.scope = CastHandle(sig->scope); - key.args = CastHandle(args); - - key.sigInst_classInst_Index = SpmiRecordsHelper::ContainsHandleMap(sig->sigInst.classInstCount, sig->sigInst.classInst, SigInstHandleMap); - key.sigInst_methInst_Index = SpmiRecordsHelper::ContainsHandleMap(sig->sigInst.methInstCount, sig->sigInst.methInst, SigInstHandleMap); - - Agnostic_GetArgType_Value value = LookupByKeyOrMiss(GetArgType, key, ": key %016" PRIX64 " %016" PRIX64 "", key.scope, key.args); - - DEBUG_REP(dmpGetArgType(key, value)); - - *vcTypeRet = (CORINFO_CLASS_HANDLE)value.vcTypeRet; - CorInfoTypeWithMod temp = (CorInfoTypeWithMod)value.result; - *exceptionCode = (DWORD)value.exceptionCode; - return temp; -} - -void MethodContext::recGetExactClasses(CORINFO_CLASS_HANDLE baseType, int maxExactClasses, CORINFO_CLASS_HANDLE* exactClsRet, int result) -{ - if (GetExactClasses == nullptr) - GetExactClasses = new LightWeightMap(); - - DLD key; - ZeroMemory(&key, sizeof(key)); - key.A = CastHandle(baseType); - key.B = maxExactClasses; - - int numResults = result < 0 ? 0 : result; - - DWORDLONG* exactClassesAgnostic = new DWORDLONG[numResults]; - for (int i = 0; i < numResults; i++) - exactClassesAgnostic[i] = CastHandle(exactClsRet[i]); - - Agnostic_GetExactClassesResult value; - value.numClasses = result; - value.classes = GetExactClasses->AddBuffer((unsigned char*)exactClassesAgnostic, (unsigned int)(numResults * sizeof(DWORDLONG))); - - delete[] exactClassesAgnostic; - - GetExactClasses->Add(key, value); -} -void MethodContext::dmpGetExactClasses(DLD key, const Agnostic_GetExactClassesResult& value) -{ - printf("GetExactClasses key baseType-%016" PRIX64 ", maxExactCls-%u, value numClasses-%d", - key.A, key.B, value.numClasses); -} -int MethodContext::repGetExactClasses(CORINFO_CLASS_HANDLE baseType, int maxExactClasses, CORINFO_CLASS_HANDLE* exactClsRet) -{ - DLD key; - ZeroMemory(&key, sizeof(key)); - key.A = CastHandle(baseType); - key.B = maxExactClasses; - - Agnostic_GetExactClassesResult value = LookupByKeyOrMiss(GetExactClasses, key, ": key %016" PRIX64 " %08X", key.A, key.B); - - Assert(maxExactClasses >= value.numClasses); - - unsigned char* buffer = GetExactClasses->GetBuffer(value.classes); - for (int i = 0; i < value.numClasses; i++) - { - DWORDLONG handle; - memcpy(&handle, &buffer[i * sizeof(DWORDLONG)], sizeof(handle)); - exactClsRet[i] = (CORINFO_CLASS_HANDLE)handle; - } - - return value.numClasses; -} - -void MethodContext::recGetArgNext(CORINFO_ARG_LIST_HANDLE args, CORINFO_ARG_LIST_HANDLE result) -{ - if (GetArgNext == nullptr) - GetArgNext = new LightWeightMap(); - - DWORDLONG key = CastHandle(args); - DWORDLONG value = CastHandle(result); - GetArgNext->Add(key, value); - DEBUG_REC(dmpGetArgNext(key, value)); -} -void MethodContext::dmpGetArgNext(DWORDLONG key, DWORDLONG value) -{ - printf("GetArgNext key %016" PRIX64 ", value %016" PRIX64 "", key, value); -} -CORINFO_ARG_LIST_HANDLE MethodContext::repGetArgNext(CORINFO_ARG_LIST_HANDLE args) -{ - DWORDLONG key = CastHandle(args); - DWORDLONG value = LookupByKeyOrMiss(GetArgNext, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetArgNext(key, value)); - CORINFO_ARG_LIST_HANDLE result = (CORINFO_ARG_LIST_HANDLE)value; - return result; -} -void MethodContext::recGetMethodSig(CORINFO_METHOD_HANDLE ftn, CORINFO_SIG_INFO* sig, CORINFO_CLASS_HANDLE memberParent) -{ - if (GetMethodSig == nullptr) - GetMethodSig = new LightWeightMap(); - - DLDL key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(ftn); - key.B = CastHandle(memberParent); - - Agnostic_CORINFO_SIG_INFO value = SpmiRecordsHelper::StoreAgnostic_CORINFO_SIG_INFO(*sig, GetMethodSig, SigInstHandleMap); - - GetMethodSig->Add(key, value); - DEBUG_REC(dmpGetMethodSig(key, value)); -} -void MethodContext::dmpGetMethodSig(DLDL key, const Agnostic_CORINFO_SIG_INFO& value) -{ - printf("GetMethodSig key ftn-%016" PRIX64 " prt-%016" PRIX64 ", value-%s", key.A, key.B, - SpmiDumpHelper::DumpAgnostic_CORINFO_SIG_INFO(value, GetMethodSig, SigInstHandleMap).c_str()); -} -void MethodContext::repGetMethodSig(CORINFO_METHOD_HANDLE ftn, CORINFO_SIG_INFO* sig, CORINFO_CLASS_HANDLE memberParent) -{ - DLDL key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(ftn); - key.B = CastHandle(memberParent); - - Agnostic_CORINFO_SIG_INFO value = LookupByKeyOrMiss(GetMethodSig, key, ": key ftn-%016" PRIX64 " prt-%016" PRIX64 "", key.A, key.B); - - DEBUG_REP(dmpGetMethodSig(key, value)); - - *sig = SpmiRecordsHelper::Restore_CORINFO_SIG_INFO(value, GetMethodSig, SigInstHandleMap, cr->getOrCreateMemoryTracker()); -} - -void MethodContext::recGetArgClass(CORINFO_SIG_INFO* sig, - CORINFO_ARG_LIST_HANDLE args, - CORINFO_CLASS_HANDLE result, - DWORD exceptionCode) -{ - if (GetArgClass == nullptr) - GetArgClass = new LightWeightMap(); - - Agnostic_GetArgClass_Key key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - - // Only setting values for CORINFO_SIG_INFO things the EE seems to pay attention to... this is necessary since some of the values - // are unset and fail our precise comparisons... - - SpmiRecordsHelper::StoreAgnostic_CORINFO_SIG_INST_HandleArray(sig->sigInst.classInstCount, sig->sigInst.classInst, SigInstHandleMap, &key.sigInst_classInstCount, &key.sigInst_classInst_Index); - SpmiRecordsHelper::StoreAgnostic_CORINFO_SIG_INST_HandleArray(sig->sigInst.methInstCount, sig->sigInst.methInst, SigInstHandleMap, &key.sigInst_methInstCount, &key.sigInst_methInst_Index); - - key.methodSignature = CastPointer(sig->methodSignature); - key.scope = CastHandle(sig->scope); - key.args = CastHandle(args); - - Agnostic_GetArgClass_Value value; - value.result = CastHandle(result); - value.exceptionCode = exceptionCode; - - GetArgClass->Add(key, value); - DEBUG_REC(dmpGetArgClass(key, value)); -} -void MethodContext::dmpGetArgClass(const Agnostic_GetArgClass_Key& key, const Agnostic_GetArgClass_Value& value) -{ - printf("GetArgClass key %s %s msig-%016" PRIX64 " scp-%016" PRIX64 " args-%016" PRIX64 "", - SpmiDumpHelper::DumpAgnostic_CORINFO_SIG_INST_Element("", "cc", "ci", key.sigInst_classInstCount, key.sigInst_classInst_Index, SigInstHandleMap).c_str(), - SpmiDumpHelper::DumpAgnostic_CORINFO_SIG_INST_Element("", "mc", "mi", key.sigInst_methInstCount, key.sigInst_methInst_Index, SigInstHandleMap).c_str(), - key.methodSignature, key.scope, key.args); - printf(", value %016" PRIX64 " excp-%08X", value.result, value.exceptionCode); -} -CORINFO_CLASS_HANDLE MethodContext::repGetArgClass(CORINFO_SIG_INFO* sig, - CORINFO_ARG_LIST_HANDLE args, - DWORD* exceptionCode) -{ - Agnostic_GetArgClass_Key key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.sigInst_classInstCount = (DWORD)sig->sigInst.classInstCount; - key.sigInst_methInstCount = (DWORD)sig->sigInst.methInstCount; - key.methodSignature = CastPointer(sig->methodSignature); - key.scope = CastHandle(sig->scope); - key.args = CastHandle(args); - key.sigInst_classInst_Index = SpmiRecordsHelper::ContainsHandleMap(sig->sigInst.classInstCount, sig->sigInst.classInst, SigInstHandleMap); - key.sigInst_methInst_Index = SpmiRecordsHelper::ContainsHandleMap(sig->sigInst.methInstCount, sig->sigInst.methInst, SigInstHandleMap); - - Agnostic_GetArgClass_Value value = LookupByKeyOrMiss(GetArgClass, key, ": key %016" PRIX64 " %016" PRIX64 "", key.scope, key.args); - - DEBUG_REP(dmpGetArgClass(key, value)); - - *exceptionCode = value.exceptionCode; - return (CORINFO_CLASS_HANDLE)value.result; -} - -void MethodContext::recGetHFAType(CORINFO_CLASS_HANDLE clsHnd, CorInfoHFAElemType result) -{ - if (GetHFAType == nullptr) - GetHFAType = new LightWeightMap(); - - DWORDLONG key = CastHandle(clsHnd); - DWORD value = (DWORD)result; - GetHFAType->Add(key, value); - DEBUG_REC(dmpGetHFAType(key, value)); -} -void MethodContext::dmpGetHFAType(DWORDLONG key, DWORD value) -{ - printf("GetHFAType key %016" PRIX64 ", value %u ", key, value); -} -CorInfoHFAElemType MethodContext::repGetHFAType(CORINFO_CLASS_HANDLE clsHnd) -{ - DWORDLONG key = CastHandle(clsHnd); - DWORD value = LookupByKeyOrMiss(GetHFAType, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetHFAType(key, value)); - return (CorInfoHFAElemType)value; -} - -void MethodContext::recGetMethodInfo(CORINFO_METHOD_HANDLE ftn, - CORINFO_METHOD_INFO* info, - CORINFO_CONTEXT_HANDLE context, - bool result, - DWORD exceptionCode) -{ - if (GetMethodInfo == nullptr) - GetMethodInfo = new LightWeightMap(); - - Agnostic_GetMethodInfo value; - ZeroMemory(&value, sizeof(value)); - - if (result) - { - value.info.ftn = CastHandle(info->ftn); - value.info.scope = CastHandle(info->scope); - value.info.ILCode_offset = (DWORD)GetMethodInfo->AddBuffer(info->ILCode, info->ILCodeSize); - value.info.ILCodeSize = (DWORD)info->ILCodeSize; - value.info.maxStack = (DWORD)info->maxStack; - value.info.EHcount = (DWORD)info->EHcount; - value.info.options = (DWORD)info->options; - value.info.regionKind = (DWORD)info->regionKind; - - value.info.args = SpmiRecordsHelper::StoreAgnostic_CORINFO_SIG_INFO(info->args, GetMethodInfo, SigInstHandleMap); - value.info.locals = SpmiRecordsHelper::StoreAgnostic_CORINFO_SIG_INFO(info->locals, GetMethodInfo, SigInstHandleMap); - } - value.result = result; - value.exceptionCode = (DWORD)exceptionCode; - - DLDL key; - key.A = CastHandle(ftn); - key.B = CastHandle(context); - GetMethodInfo->Add(key, value); - DEBUG_REC(dmpGetMethodInfo(key, value)); -} -void MethodContext::dmpGetMethodInfo(DLDL key, const Agnostic_GetMethodInfo& value) -{ - if (value.result) - { - printf("GetMethodInfo key ftn-%016" PRIX64 " ctx-%016" PRIX64 ", value res-%u ftn-%016" PRIX64 " scp-%016" PRIX64 " ilo-%u ils-%u ms-%u ehc-%u opt-%08X rk-%u args-%s locals-%s excp-%08X", - key.A, key.B, value.result, value.info.ftn, value.info.scope, value.info.ILCode_offset, value.info.ILCodeSize, - value.info.maxStack, value.info.EHcount, value.info.options, value.info.regionKind, - SpmiDumpHelper::DumpAgnostic_CORINFO_SIG_INFO(value.info.args, GetMethodInfo, SigInstHandleMap).c_str(), - SpmiDumpHelper::DumpAgnostic_CORINFO_SIG_INFO(value.info.locals, GetMethodInfo, SigInstHandleMap).c_str(), - value.exceptionCode); - } - else - { - printf("GetMethodInfo key ftn-%016" PRIX64 " ctx-%016" PRIX64 ", value res-%u excp-%08X", - key.A, key.B, value.result, value.exceptionCode); - } -} -bool MethodContext::repGetMethodInfo(CORINFO_METHOD_HANDLE ftn, CORINFO_METHOD_INFO* info, CORINFO_CONTEXT_HANDLE context, DWORD* exceptionCode) -{ - DLDL key; - key.A = CastHandle(ftn); - key.B = CastHandle(context); - Agnostic_GetMethodInfo value = LookupByKeyOrMiss(GetMethodInfo, key, ": key %016" PRIX64 "", key.A); - - DEBUG_REP(dmpGetMethodInfo(key, value)); - - if (value.result) - { - info->ftn = (CORINFO_METHOD_HANDLE)value.info.ftn; - info->scope = (CORINFO_MODULE_HANDLE)value.info.scope; - info->ILCode = GetMethodInfo->GetBuffer(value.info.ILCode_offset); - info->ILCodeSize = (unsigned)value.info.ILCodeSize; - info->maxStack = (unsigned)value.info.maxStack; - info->EHcount = (unsigned)value.info.EHcount; - info->options = (CorInfoOptions)value.info.options; - info->regionKind = (CorInfoRegionKind)value.info.regionKind; - - info->args = SpmiRecordsHelper::Restore_CORINFO_SIG_INFO(value.info.args, GetMethodInfo, SigInstHandleMap, cr->getOrCreateMemoryTracker()); - info->locals = SpmiRecordsHelper::Restore_CORINFO_SIG_INFO(value.info.locals, GetMethodInfo, SigInstHandleMap, cr->getOrCreateMemoryTracker()); - } - bool result = value.result; - *exceptionCode = (DWORD)value.exceptionCode; - return result; -} - -void MethodContext::recHaveSameMethodDefinition(CORINFO_METHOD_HANDLE methHnd1, CORINFO_METHOD_HANDLE methHnd2, bool result) -{ - if (HaveSameMethodDefinition == nullptr) - HaveSameMethodDefinition = new LightWeightMap(); - - DLDL key; - key.A = CastHandle(methHnd1); - key.B = CastHandle(methHnd2); - - DWORD value = result ? 1 : 0; - HaveSameMethodDefinition->Add(key, value); -} -void MethodContext::dmpHaveSameMethodDefinition(const DLDL& key, DWORD value) -{ - printf("HaveSameMethodDefinition key methHnd1-%016" PRIX64 ", methHnd2-%016" PRIX64 ", value %u", key.A, key.B, value); -} -bool MethodContext::repHaveSameMethodDefinition(CORINFO_METHOD_HANDLE methHnd1, CORINFO_METHOD_HANDLE methHnd2) -{ - DLDL key; - key.A = CastHandle(methHnd1); - key.B = CastHandle(methHnd2); - - DWORD value = LookupByKeyOrMiss(HaveSameMethodDefinition, key, "key %016" PRIX64 ", %016" PRIX64, key.A, key.B); - return value != 0; -} - -void MethodContext::recGetTypeDefinition(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE result) -{ - if (GetTypeDefinition == nullptr) - GetTypeDefinition = new LightWeightMap(); - - DWORDLONG key = CastHandle(cls); - DWORDLONG value = CastHandle(result); - GetTypeDefinition->Add(key, value); - DEBUG_REC(dmpGetTypeDefinition(key, value)); -} -void MethodContext::dmpGetTypeDefinition(DWORDLONG key, DWORDLONG value) -{ - printf("GetTypeDefinition key cls-%016" PRIX64 ", value cls-%016" PRIX64 "", key, value); -} -CORINFO_CLASS_HANDLE MethodContext::repGetTypeDefinition(CORINFO_CLASS_HANDLE cls) -{ - DWORDLONG key = CastHandle(cls); - DWORDLONG value = LookupByKeyOrMiss(GetTypeDefinition, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetTypeDefinition(key, value)); - CORINFO_CLASS_HANDLE result = (CORINFO_CLASS_HANDLE)value; - return result; -} - -void MethodContext::recGetNewHelper(CORINFO_CLASS_HANDLE classHandle, - bool hasSideEffects, - CorInfoHelpFunc result, - DWORD exceptionCode) -{ - if (GetNewHelper == nullptr) - GetNewHelper = new LightWeightMap(); - - DWORDLONG key = CastHandle(classHandle); - - DDD value; - value.A = hasSideEffects ? 1 : 0; - value.B = (DWORD)result; - value.C = exceptionCode; - - GetNewHelper->Add(key, value); - DEBUG_REC(dmpGetNewHelper(key, value)); -} -void MethodContext::dmpGetNewHelper(DWORDLONG key, const DDD& value) -{ - printf("GetNewHelper key %016" PRIX64 ", hasSideEffects-%u, value res-%u, exceptionCode-%08X", key, value.A, value.B, value.C); -} -CorInfoHelpFunc MethodContext::repGetNewHelper(CORINFO_CLASS_HANDLE classHandle, - bool* pHasSideEffects, - DWORD* exceptionCode) -{ - DWORDLONG key = CastHandle(classHandle); - - DDD value = LookupByKeyOrMiss(GetNewHelper, key, ": key %016" PRIX64, key); - DEBUG_REP(dmpGetNewHelper(key, value)); - - if (pHasSideEffects != nullptr) - { - *pHasSideEffects = value.A != 0; - } - CorInfoHelpFunc result = (CorInfoHelpFunc)value.B; - *exceptionCode = value.C; - return result; -} - -void MethodContext::recEmbedGenericHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken, - bool fEmbedParent, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_GENERICHANDLE_RESULT* pResult) -{ - if (EmbedGenericHandle == nullptr) - EmbedGenericHandle = new LightWeightMap(); - - Agnostic_EmbedGenericHandle key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.ResolvedToken = SpmiRecordsHelper::StoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, EmbedGenericHandle); - key.fEmbedParent = (DWORD)fEmbedParent; - key.hCallerHandle = CastHandle(callerHandle); - - Agnostic_CORINFO_GENERICHANDLE_RESULT value; - value.lookup = SpmiRecordsHelper::StoreAgnostic_CORINFO_LOOKUP(&pResult->lookup); - value.compileTimeHandle = CastHandle(pResult->compileTimeHandle); - value.handleType = (DWORD)pResult->handleType; - - EmbedGenericHandle->Add(key, value); - DEBUG_REC(dmpEmbedGenericHandle(key, value)); -} -void MethodContext::dmpEmbedGenericHandle(const Agnostic_EmbedGenericHandle& key, - const Agnostic_CORINFO_GENERICHANDLE_RESULT& value) -{ - printf("EmbedGenericHandle key rt{%s} emb-%u, value %s cth-%016" PRIX64 " ht-%u", - SpmiDumpHelper::DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.ResolvedToken).c_str(), - key.fEmbedParent, - SpmiDumpHelper::DumpAgnostic_CORINFO_LOOKUP(value.lookup).c_str(), - value.compileTimeHandle, - value.handleType); -} -void MethodContext::repEmbedGenericHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken, - bool fEmbedParent, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_GENERICHANDLE_RESULT* pResult) -{ - AssertMapExistsNoMessage(EmbedGenericHandle); - - Agnostic_EmbedGenericHandle key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.ResolvedToken = SpmiRecordsHelper::RestoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, EmbedGenericHandle); - key.fEmbedParent = (DWORD)fEmbedParent; - key.hCallerHandle = CastHandle(callerHandle); - - Agnostic_CORINFO_GENERICHANDLE_RESULT value = LookupByKeyOrMissNoMessage(EmbedGenericHandle, key); - - DEBUG_REP(dmpEmbedGenericHandle(key, value)); - - pResult->lookup = SpmiRecordsHelper::RestoreCORINFO_LOOKUP(value.lookup); - pResult->compileTimeHandle = (CORINFO_GENERIC_HANDLE)value.compileTimeHandle; - pResult->handleType = (CorInfoGenericHandleType)value.handleType; -} - -void MethodContext::recGetEHinfo(CORINFO_METHOD_HANDLE ftn, unsigned EHnumber, CORINFO_EH_CLAUSE* clause) -{ - if (GetEHinfo == nullptr) - GetEHinfo = new LightWeightMap(); - - DLD key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(ftn); - key.B = (DWORD)EHnumber; - - Agnostic_CORINFO_EH_CLAUSE value; - value.Flags = (DWORD)clause->Flags; - value.TryOffset = (DWORD)clause->TryOffset; - value.TryLength = (DWORD)clause->TryLength; - value.HandlerOffset = (DWORD)clause->HandlerOffset; - value.HandlerLength = (DWORD)clause->HandlerLength; - value.ClassToken = (DWORD)clause->ClassToken; - - GetEHinfo->Add(key, value); - DEBUG_REC(dmpGetEHinfo(key, value)); -} -void MethodContext::dmpGetEHinfo(DLD key, const Agnostic_CORINFO_EH_CLAUSE& value) -{ - printf("GetEHinfo key ftn-%016" PRIX64 " ehn-%u, value flg-%u to-%u tl-%u ho-%u hl-%u ct-%u", key.A, key.B, value.Flags, - value.TryOffset, value.TryLength, value.HandlerOffset, value.HandlerLength, value.ClassToken); -} -void MethodContext::repGetEHinfo(CORINFO_METHOD_HANDLE ftn, unsigned EHnumber, CORINFO_EH_CLAUSE* clause) -{ - AssertMapExists(GetEHinfo, ": key %016" PRIX64 "", CastHandle(ftn)); - - DLD key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(ftn); - key.B = (DWORD)EHnumber; - - Agnostic_CORINFO_EH_CLAUSE value = LookupByKeyOrMiss(GetEHinfo, key, ": key %016" PRIX64 "", CastHandle(ftn)); - - DEBUG_REP(dmpGetEHinfo(key, value)); - - clause->Flags = (CORINFO_EH_CLAUSE_FLAGS)value.Flags; - clause->TryOffset = (DWORD)value.TryOffset; - clause->TryLength = (DWORD)value.TryLength; - clause->HandlerOffset = (DWORD)value.HandlerOffset; - clause->HandlerLength = (DWORD)value.HandlerLength; - clause->ClassToken = (DWORD)value.ClassToken; -} - -void MethodContext::recGetMethodVTableOffset(CORINFO_METHOD_HANDLE method, - unsigned* offsetOfIndirection, - unsigned* offsetAfterIndirection, - bool* isRelative) -{ - if (GetMethodVTableOffset == nullptr) - GetMethodVTableOffset = new LightWeightMap(); - - DDD value; - value.A = (DWORD)*offsetOfIndirection; - value.B = (DWORD)*offsetAfterIndirection; - value.C = *isRelative ? 1 : 0; - - DWORDLONG key = CastHandle(method); - GetMethodVTableOffset->Add(key, value); - DEBUG_REC(dmpGetMethodVTableOffset(key, value)); -} -void MethodContext::dmpGetMethodVTableOffset(DWORDLONG key, DDD value) -{ - printf("GetMethodVTableOffset key ftn-%016" PRIX64 ", value offi-%u, offa-%u. offr-%d", key, value.A, value.B, value.C); -} -void MethodContext::repGetMethodVTableOffset(CORINFO_METHOD_HANDLE method, - unsigned* offsetOfIndirection, - unsigned* offsetAfterIndirection, - bool* isRelative) -{ - DWORDLONG key = CastHandle(method); - DDD value = LookupByKeyOrMiss(GetMethodVTableOffset, key, ": key %016" PRIX64 "", key); - - DEBUG_REP(dmpGetMethodVTableOffset(key, value)); - - *offsetOfIndirection = (unsigned)value.A; - *offsetAfterIndirection = (unsigned)value.B; - *isRelative = (value.C != 0); -} - -void MethodContext::recResolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO * info, bool returnValue) -{ - if (ResolveVirtualMethod == nullptr) - { - ResolveVirtualMethod = new LightWeightMap(); - } - - Agnostic_ResolveVirtualMethodKey key; - ZeroMemory(&key, sizeof(key)); // Zero token including any struct padding - key.virtualMethod = CastHandle(info->virtualMethod); - key.objClass = CastHandle(info->objClass); - key.context = CastHandle(info->context); - - key.pResolvedTokenVirtualMethodNonNull = info->pResolvedTokenVirtualMethod != NULL ? 1 : 0; - if (key.pResolvedTokenVirtualMethodNonNull) - key.pResolvedTokenVirtualMethod = SpmiRecordsHelper::StoreAgnostic_CORINFO_RESOLVED_TOKEN(info->pResolvedTokenVirtualMethod, ResolveToken); - - Agnostic_ResolveVirtualMethodResult result; - result.returnValue = returnValue; - result.devirtualizedMethod = CastHandle(info->devirtualizedMethod); - result.tokenLookupContext = CastHandle(info->tokenLookupContext); - result.detail = (DWORD)info->detail; - result.instParamLookup = SpmiRecordsHelper::StoreAgnostic_CORINFO_LOOKUP(&info->instParamLookup); - - if (returnValue) - { - result.resolvedTokenDevirtualizedMethod = SpmiRecordsHelper::StoreAgnostic_CORINFO_RESOLVED_TOKEN(&info->resolvedTokenDevirtualizedMethod, ResolveToken); - result.resolvedTokenDevirtualizedUnboxedMethod = SpmiRecordsHelper::StoreAgnostic_CORINFO_RESOLVED_TOKEN(&info->resolvedTokenDevirtualizedUnboxedMethod, ResolveToken); - } - else - { - ZeroMemory(&result.resolvedTokenDevirtualizedMethod, sizeof(result.resolvedTokenDevirtualizedMethod)); - ZeroMemory(&result.resolvedTokenDevirtualizedUnboxedMethod, sizeof(result.resolvedTokenDevirtualizedUnboxedMethod)); - } - - ResolveVirtualMethod->Add(key, result); - DEBUG_REC(dmpResolveVirtualMethod(key, result)); -} - -void MethodContext::dmpResolveVirtualMethod(const Agnostic_ResolveVirtualMethodKey& key, const Agnostic_ResolveVirtualMethodResult& result) -{ - printf("ResolveVirtualMethod key virtMethod-%016" PRIX64 ", objClass-%016" PRIX64 ", context-%016" PRIX64 " pResolvedTokenVirtualMethodNonNull-%08X pResolvedTokenVirtualMethod{%s}", - key.virtualMethod, - key.objClass, - key.context, - key.pResolvedTokenVirtualMethodNonNull, - key.pResolvedTokenVirtualMethodNonNull ? SpmiDumpHelper::DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.pResolvedTokenVirtualMethod).c_str() : "???"); - printf(", value returnValue-%s, devirtMethod-%016" PRIX64 ", tokenLookupContext-%016" PRIX64 ", detail-%d, tokDvMeth{%s}, tokDvUnboxMeth{%s}, instParamLookup{%s}", - result.returnValue ? "true" : "false", - result.devirtualizedMethod, - result.tokenLookupContext, - result.detail, - result.returnValue ? SpmiDumpHelper::DumpAgnostic_CORINFO_RESOLVED_TOKEN(result.resolvedTokenDevirtualizedMethod).c_str() : "???", - result.returnValue ? SpmiDumpHelper::DumpAgnostic_CORINFO_RESOLVED_TOKEN(result.resolvedTokenDevirtualizedUnboxedMethod).c_str() : "???", - SpmiDumpHelper::DumpAgnostic_CORINFO_LOOKUP(result.instParamLookup).c_str()); -} - -bool MethodContext::repResolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO * info) -{ - Agnostic_ResolveVirtualMethodKey key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.virtualMethod = CastHandle(info->virtualMethod); - key.objClass = CastHandle(info->objClass); - key.context = CastHandle(info->context); - - key.pResolvedTokenVirtualMethodNonNull = info->pResolvedTokenVirtualMethod != NULL ? 1 : 0; - if (key.pResolvedTokenVirtualMethodNonNull) - key.pResolvedTokenVirtualMethod = SpmiRecordsHelper::StoreAgnostic_CORINFO_RESOLVED_TOKEN(info->pResolvedTokenVirtualMethod, ResolveToken); - - Agnostic_ResolveVirtualMethodResult result = LookupByKeyOrMiss(ResolveVirtualMethod, key, ": %016" PRIX64 "-%016" PRIX64 "-%016" PRIX64 "-%08X", key.virtualMethod, key.objClass, key.context, key.pResolvedTokenVirtualMethodNonNull); - - DEBUG_REP(dmpResolveVirtualMethod(key, result)); - - info->devirtualizedMethod = (CORINFO_METHOD_HANDLE) result.devirtualizedMethod; - info->tokenLookupContext = (CORINFO_CONTEXT_HANDLE) result.tokenLookupContext; - info->detail = (CORINFO_DEVIRTUALIZATION_DETAIL) result.detail; - info->instParamLookup = SpmiRecordsHelper::RestoreCORINFO_LOOKUP(result.instParamLookup); - if (result.returnValue) - { - info->resolvedTokenDevirtualizedMethod = SpmiRecordsHelper::Restore_CORINFO_RESOLVED_TOKEN(&result.resolvedTokenDevirtualizedMethod, ResolveToken); - info->resolvedTokenDevirtualizedUnboxedMethod = SpmiRecordsHelper::Restore_CORINFO_RESOLVED_TOKEN(&result.resolvedTokenDevirtualizedUnboxedMethod, ResolveToken); - } - return result.returnValue; -} - -void MethodContext::recGetAsyncOtherVariant(CORINFO_METHOD_HANDLE ftn, - bool variantIsThunk, - CORINFO_METHOD_HANDLE result) -{ - if (GetAsyncOtherVariant == nullptr) - { - GetAsyncOtherVariant = new LightWeightMap(); - } - - DWORDLONG key = CastHandle(ftn); - DLD value; - value.A = CastHandle(result); - value.B = (DWORD)variantIsThunk ? 1 : 0; - GetAsyncOtherVariant->Add(key, value); - DEBUG_REC(dmpGetAsyncOtherVariant(key, value)); -} - -void MethodContext::dmpGetAsyncOtherVariant(DWORDLONG key, DLD value) -{ - printf("GetAsyncOtherVariant ftn-%016" PRIX64 ", result-%016" PRIX64 ", variantIsThunk-%u", key, value.A, value.B); -} - -CORINFO_METHOD_HANDLE MethodContext::repGetAsyncOtherVariant(CORINFO_METHOD_HANDLE ftn, bool* variantIsThunk) -{ - DWORDLONG key = CastHandle(ftn); - - DLD value = LookupByKeyOrMiss(GetAsyncOtherVariant, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetAsyncOtherVariant(key, value)); - *variantIsThunk = (value.B != 0); - return (CORINFO_METHOD_HANDLE)(value.A); -} - -void MethodContext::recGetDefaultComparerClass(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE result) -{ - if (GetDefaultComparerClass == nullptr) - GetDefaultComparerClass = new LightWeightMap(); - - DWORDLONG key = CastHandle(cls); - DWORDLONG value = CastHandle(result); - GetDefaultComparerClass->Add(key, value); - DEBUG_REC(dmpGetDefaultComparerClass(key, value)); -} -void MethodContext::dmpGetDefaultComparerClass(DWORDLONG key, DWORDLONG value) -{ - printf("GetDefaultComparerClass key cls-%016" PRIX64 ", value cls-%016" PRIX64 "", key, value); -} -CORINFO_CLASS_HANDLE MethodContext::repGetDefaultComparerClass(CORINFO_CLASS_HANDLE cls) -{ - DWORDLONG key = CastHandle(cls); - DWORDLONG value = LookupByKeyOrMiss(GetDefaultComparerClass, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetDefaultComparerClass(key, value)); - CORINFO_CLASS_HANDLE result = (CORINFO_CLASS_HANDLE)value; - return result; -} - -void MethodContext::recGetDefaultEqualityComparerClass(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE result) -{ - if (GetDefaultEqualityComparerClass == nullptr) - GetDefaultEqualityComparerClass = new LightWeightMap(); - - DWORDLONG key = CastHandle(cls); - DWORDLONG value = CastHandle(result); - GetDefaultEqualityComparerClass->Add(key, value); - DEBUG_REC(dmpGetDefaultEqualityComparerClass(key, value)); -} -void MethodContext::dmpGetDefaultEqualityComparerClass(DWORDLONG key, DWORDLONG value) -{ - printf("GetDefaultEqualityComparerClass key cls-%016" PRIX64 ", value cls-%016" PRIX64 "", key, value); -} -CORINFO_CLASS_HANDLE MethodContext::repGetDefaultEqualityComparerClass(CORINFO_CLASS_HANDLE cls) -{ - DWORDLONG key = CastHandle(cls); - DWORDLONG value = LookupByKeyOrMiss(GetDefaultEqualityComparerClass, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetDefaultEqualityComparerClass(key, value)); - CORINFO_CLASS_HANDLE result = (CORINFO_CLASS_HANDLE)value; - return result; -} - -void MethodContext::recGetSZArrayHelperEnumeratorClass(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE result) -{ - if (GetSZArrayHelperEnumeratorClass == nullptr) - GetSZArrayHelperEnumeratorClass = new LightWeightMap(); - - DWORDLONG key = CastHandle(cls); - DWORDLONG value = CastHandle(result); - GetSZArrayHelperEnumeratorClass->Add(key, value); - DEBUG_REC(dmpGetSZArrayHelperEnumeratorClass(key, value)); -} -void MethodContext::dmpGetSZArrayHelperEnumeratorClass(DWORDLONG key, DWORDLONG value) -{ - printf("GetSZArrayHelperEnumeratorClass key cls-%016" PRIX64 ", value cls-%016" PRIX64 "", key, value); -} -CORINFO_CLASS_HANDLE MethodContext::repGetSZArrayHelperEnumeratorClass(CORINFO_CLASS_HANDLE cls) -{ - DWORDLONG key = CastHandle(cls); - DWORDLONG value = LookupByKeyOrMiss(GetSZArrayHelperEnumeratorClass, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetSZArrayHelperEnumeratorClass(key, value)); - CORINFO_CLASS_HANDLE result = (CORINFO_CLASS_HANDLE)value; - return result; -} - -void MethodContext::recGetTokenTypeAsHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_CLASS_HANDLE result) -{ - if (GetTokenTypeAsHandle == nullptr) - GetTokenTypeAsHandle = new LightWeightMap(); - - GetTokenTypeAsHandleValue key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.hMethod = CastHandle(pResolvedToken->hMethod); - key.hField = CastHandle(pResolvedToken->hField); - - DWORDLONG value = CastHandle(result); - GetTokenTypeAsHandle->Add(key, value); - DEBUG_REC(dmpGetTokenTypeAsHandle(key, value)); -} -void MethodContext::dmpGetTokenTypeAsHandle(const GetTokenTypeAsHandleValue& key, DWORDLONG value) -{ - printf("GetTokenTypeAsHandle key ftn-%016" PRIX64 " fld-%016" PRIX64 ", value cls-%016" PRIX64 "", key.hMethod, key.hField, value); -} -CORINFO_CLASS_HANDLE MethodContext::repGetTokenTypeAsHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken) -{ - GetTokenTypeAsHandleValue key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.hMethod = CastHandle(pResolvedToken->hMethod); - key.hField = CastHandle(pResolvedToken->hField); - - DWORDLONG value = LookupByKeyOrMissNoMessage(GetTokenTypeAsHandle, key); - - DEBUG_REP(dmpGetTokenTypeAsHandle(key, value)); - CORINFO_CLASS_HANDLE result = (CORINFO_CLASS_HANDLE)value; - return result; -} - -void MethodContext::recGetFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_ACCESS_FLAGS flags, - CORINFO_FIELD_INFO* pResult) -{ - if (GetFieldInfo == nullptr) - GetFieldInfo = new LightWeightMap(); - - Agnostic_GetFieldInfo key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.ResolvedToken = SpmiRecordsHelper::StoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, GetFieldInfo); - key.callerHandle = CastHandle(callerHandle); - key.flags = (DWORD)flags; - - Agnostic_CORINFO_FIELD_INFO value; - value.fieldAccessor = (DWORD)pResult->fieldAccessor; - value.fieldFlags = (DWORD)pResult->fieldFlags; - value.helper = (DWORD)pResult->helper; - value.offset = (DWORD)pResult->offset; - value.fieldType = (DWORD)pResult->fieldType; - value.structType = CastHandle(pResult->structType); - value.accessAllowed = (DWORD)pResult->accessAllowed; - value.accessCalloutHelper.helperNum = (DWORD)pResult->accessCalloutHelper.helperNum; - value.accessCalloutHelper.numArgs = (DWORD)pResult->accessCalloutHelper.numArgs; - value.fieldLookup = SpmiRecordsHelper::StoreAgnostic_CORINFO_CONST_LOOKUP(&pResult->fieldLookup); - for (int i = 0; i < CORINFO_ACCESS_ALLOWED_MAX_ARGS; i++) - { - value.accessCalloutHelper.args[i].constant = (DWORDLONG)pResult->accessCalloutHelper.args[i].constant; - value.accessCalloutHelper.args[i].argType = (DWORD)pResult->accessCalloutHelper.args[i].argType; - } - GetFieldInfo->Add(key, value); - DEBUG_REC(dmpGetFieldInfo(key, value)); -} -void MethodContext::dmpGetFieldInfo(const Agnostic_GetFieldInfo& key, const Agnostic_CORINFO_FIELD_INFO& value) -{ - printf("GetFieldInfo key ch-%016" PRIX64 " flg-%08X rt{%s}", key.callerHandle, key.flags, - SpmiDumpHelper::DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.ResolvedToken).c_str()); - - printf(", value fa-%u fflg-%08X hlp-%u off-%u fT-%u(%s) sT-%016" PRIX64 " aa-%u hnum-%u na-%u {", value.fieldAccessor, - value.fieldFlags, value.helper, value.offset, value.fieldType, toString((CorInfoType)value.fieldType), - value.structType, value.accessAllowed, value.accessCalloutHelper.helperNum, - value.accessCalloutHelper.numArgs); - - for (int i = 0; i < CORINFO_ACCESS_ALLOWED_MAX_ARGS; i++) - { - switch ((CorInfoAccessAllowedHelperArgType)value.accessCalloutHelper.args[i].argType) - { - default: - printf("{%u: illegal}", i); - break; - case CORINFO_HELPER_ARG_TYPE_Field: - printf("{%u: fld-%016" PRIX64 "}", i, value.accessCalloutHelper.args[i].constant); - break; - case CORINFO_HELPER_ARG_TYPE_Method: - printf("{%u: mth-%016" PRIX64 "}", i, value.accessCalloutHelper.args[i].constant); - break; - case CORINFO_HELPER_ARG_TYPE_Class: - printf("{%u: cls-%016" PRIX64 "}", i, value.accessCalloutHelper.args[i].constant); - break; - case CORINFO_HELPER_ARG_TYPE_Module: - printf("{%u: mod-%016" PRIX64 "}", i, value.accessCalloutHelper.args[i].constant); - break; - case CORINFO_HELPER_ARG_TYPE_Const: - printf("{%u: const-%016" PRIX64 "}", i, value.accessCalloutHelper.args[i].constant); - break; - } - } - printf(" fl %s}", SpmiDumpHelper::DumpAgnostic_CORINFO_CONST_LOOKUP(value.fieldLookup).c_str()); -} -void MethodContext::repGetFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_ACCESS_FLAGS flags, - CORINFO_FIELD_INFO* pResult) -{ - AssertMapExists(GetFieldInfo, ": key %x", pResolvedToken->token); - - Agnostic_GetFieldInfo key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.ResolvedToken = SpmiRecordsHelper::RestoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, GetFieldInfo); - key.callerHandle = CastHandle(callerHandle); - key.flags = (DWORD)flags; - - DWORD origFlag = key.flags; - - int keyIndex = GetFieldInfo->GetIndex(key); - if (keyIndex == -1) - { -#ifdef sparseMC - key.flags = origFlag ^ ((DWORD)CORINFO_ACCESS_THIS); - keyIndex = GetFieldInfo->GetIndex(key); - if (keyIndex != -1) - { - LogDebug( - "Sparse - repGetFieldInfo found value with inverted CORINFO_ACCESS_THIS"); - } - else - { - key.flags = origFlag ^ (DWORD)CORINFO_ACCESS_INLINECHECK; - keyIndex = GetFieldInfo->GetIndex(key); - if (keyIndex != -1) - { - LogDebug("Sparse - repGetFieldInfo found value with inverted CORINFO_ACCESS_INLINECHECK"); - } - else - { - LogException(EXCEPTIONCODE_MC, "repGetFieldInfo: didn't find %x", pResolvedToken->token); - } - } -#else - LogException(EXCEPTIONCODE_MC, "repGetFieldInfo: didn't find %x", pResolvedToken->token); -#endif - } - - Agnostic_CORINFO_FIELD_INFO value = GetFieldInfo->GetItem(keyIndex); - DEBUG_REP(dmpGetFieldInfo(key, value)); - - pResult->fieldAccessor = (CORINFO_FIELD_ACCESSOR)value.fieldAccessor; - pResult->fieldFlags = (unsigned)value.fieldFlags; - pResult->helper = (CorInfoHelpFunc)value.helper; - pResult->offset = (DWORD)value.offset; - pResult->fieldType = (CorInfoType)value.fieldType; - pResult->structType = (CORINFO_CLASS_HANDLE)value.structType; - pResult->accessAllowed = (CorInfoIsAccessAllowedResult)value.accessAllowed; - pResult->accessCalloutHelper.helperNum = (CorInfoHelpFunc)value.accessCalloutHelper.helperNum; - pResult->accessCalloutHelper.numArgs = (unsigned)value.accessCalloutHelper.numArgs; - pResult->fieldLookup = SpmiRecordsHelper::RestoreCORINFO_CONST_LOOKUP(value.fieldLookup); - for (int i = 0; i < CORINFO_ACCESS_ALLOWED_MAX_ARGS; i++) - { - pResult->accessCalloutHelper.args[i].constant = (size_t)value.accessCalloutHelper.args[i].constant; - pResult->accessCalloutHelper.args[i].argType = - (CorInfoAccessAllowedHelperArgType)value.accessCalloutHelper.args[i].argType; - } -} - -void MethodContext::recGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, bool isGCType, uint32_t result) -{ - if (GetThreadLocalFieldInfo == nullptr) - GetThreadLocalFieldInfo = new LightWeightMap(); - - DLD key; - ZeroMemory(&key, sizeof(key)); - key.A = CastHandle(field); - key.B = isGCType ? 0 : 1; - GetThreadLocalFieldInfo->Add(key, result); - DEBUG_REC(dmpGetThreadLocalFieldInfo(key, result)); -} - -void MethodContext::dmpGetThreadLocalFieldInfo(DLD key, DWORD value) -{ - printf("GetThreadLocalFieldInfo key hnd-%016" PRIX64 ",gctype-%d result-%u", key.A, key.B, value); -} - -uint32_t MethodContext::repGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, bool isGCType) -{ - DLD key; - ZeroMemory(&key, sizeof(key)); - - key.A = CastHandle(field); - key.B = isGCType ? 0 : 1; - DWORD value = LookupByKeyOrMiss(GetThreadLocalFieldInfo, key, ": key hnd-%016" PRIX64 ", gctype-%u", key.A, key.B); - - DEBUG_REP(dmpGetThreadLocalFieldInfo(key, value)); - - return value; -} - -void MethodContext::recGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) -{ - if (GetThreadLocalStaticBlocksInfo == nullptr) - GetThreadLocalStaticBlocksInfo = new LightWeightMap(); - - Agnostic_GetThreadLocalStaticBlocksInfo value; - ZeroMemory(&value, sizeof(value)); - - value.tlsIndex = SpmiRecordsHelper::StoreAgnostic_CORINFO_CONST_LOOKUP(&pInfo->tlsIndex); - value.tlsGetAddrFtnPtr = CastPointer(pInfo->tlsGetAddrFtnPtr); - value.tlsIndexObject = CastPointer(pInfo->tlsIndexObject); - value.threadVarsSection = CastPointer(pInfo->threadVarsSection); - value.offsetOfThreadLocalStoragePointer = pInfo->offsetOfThreadLocalStoragePointer; - value.offsetOfMaxThreadStaticBlocks = pInfo->offsetOfMaxThreadStaticBlocks; - value.offsetOfThreadStaticBlocks = pInfo->offsetOfThreadStaticBlocks; - value.offsetOfBaseOfThreadLocalData = pInfo->offsetOfBaseOfThreadLocalData; - - // This data is same for entire process, so just add it against key '0'. - DWORD key = 0; - GetThreadLocalStaticBlocksInfo->Add(key, value); - DEBUG_REC(dmpGetThreadLocalStaticBlocksInfo(key, value)); -} - -void MethodContext::dmpGetThreadLocalStaticBlocksInfo(DWORD key, const Agnostic_GetThreadLocalStaticBlocksInfo& value) -{ - printf("GetThreadLocalStaticBlocksInfo key %u, tlsIndex-%s, " - ", tlsGetAddrFtnPtr-%016" PRIX64 ", tlsIndexObject - %016" PRIX64 - ", threadVarsSection - %016" PRIX64 - ", offsetOfThreadLocalStoragePointer-%u" - ", offsetOfMaxThreadStaticBlocks-%u" - ", offsetOfThreadStaticBlocks-%u" - ", offsetOfBaseOfThreadLocalData-%u", - key, SpmiDumpHelper::DumpAgnostic_CORINFO_CONST_LOOKUP(value.tlsIndex).c_str(), value.tlsGetAddrFtnPtr, - value.tlsIndexObject, value.threadVarsSection, value.offsetOfThreadLocalStoragePointer, - value.offsetOfMaxThreadStaticBlocks, value.offsetOfThreadStaticBlocks, value.offsetOfBaseOfThreadLocalData); -} - -void MethodContext::repGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) -{ - int key = 0; - Agnostic_GetThreadLocalStaticBlocksInfo value = LookupByKeyOrMiss(GetThreadLocalStaticBlocksInfo, key, ": key %u", key); - - DEBUG_REP(dmpGetThreadLocalStaticBlocksInfo(key, value)); - - pInfo->tlsIndex = SpmiRecordsHelper::RestoreCORINFO_CONST_LOOKUP(value.tlsIndex); - pInfo->tlsGetAddrFtnPtr = (void*)value.tlsGetAddrFtnPtr; - pInfo->tlsIndexObject = (void*)value.tlsIndexObject; - pInfo->threadVarsSection = (void*)value.threadVarsSection; - pInfo->offsetOfThreadLocalStoragePointer = value.offsetOfThreadLocalStoragePointer; - pInfo->offsetOfMaxThreadStaticBlocks = value.offsetOfMaxThreadStaticBlocks; - pInfo->offsetOfThreadStaticBlocks = value.offsetOfThreadStaticBlocks; - pInfo->offsetOfBaseOfThreadLocalData = value.offsetOfBaseOfThreadLocalData; -} - -void MethodContext::recGetThreadLocalStaticInfo_NativeAOT(CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo) -{ - if (GetThreadLocalStaticInfo_NativeAOT == nullptr) - GetThreadLocalStaticInfo_NativeAOT = new LightWeightMap(); - - Agnostic_GetThreadStaticInfo_NativeAOT value; - ZeroMemory(&value, sizeof(value)); - value.tlsRootObject = SpmiRecordsHelper::StoreAgnostic_CORINFO_CONST_LOOKUP(&pInfo->tlsRootObject); - value.tlsIndexObject = SpmiRecordsHelper::StoreAgnostic_CORINFO_CONST_LOOKUP(&pInfo->tlsIndexObject); - value.offsetOfThreadLocalStoragePointer = pInfo->offsetOfThreadLocalStoragePointer; - value.threadStaticBaseSlow = SpmiRecordsHelper::StoreAgnostic_CORINFO_CONST_LOOKUP(&pInfo->threadStaticBaseSlow); - value.tlsGetAddrFtnPtr = SpmiRecordsHelper::StoreAgnostic_CORINFO_CONST_LOOKUP(&pInfo->tlsGetAddrFtnPtr); - - DWORDLONG key = 1; - - GetThreadLocalStaticInfo_NativeAOT->Add(key, value); - DEBUG_REC(dmpGetThreadLocalStaticInfo_NativeAOT(key, result)); -} -void MethodContext::dmpGetThreadLocalStaticInfo_NativeAOT(DWORDLONG key, - const Agnostic_GetThreadStaticInfo_NativeAOT& value) -{ - printf("GetThreadLocalStaticInfo_NativeAOT key %016" PRIX64 ", tlsRootObject-%s, tlsIndexObject-%s, offsetOfThreadLocalStoragePointer-%u, " - "threadStaticBaseSlow-%s, tlsGetAddrFtnPtr-%s", - key, SpmiDumpHelper::DumpAgnostic_CORINFO_CONST_LOOKUP(value.tlsRootObject).c_str(), - SpmiDumpHelper::DumpAgnostic_CORINFO_CONST_LOOKUP(value.tlsIndexObject).c_str(), - value.offsetOfThreadLocalStoragePointer, - SpmiDumpHelper::DumpAgnostic_CORINFO_CONST_LOOKUP(value.threadStaticBaseSlow).c_str(), - SpmiDumpHelper::DumpAgnostic_CORINFO_CONST_LOOKUP(value.tlsGetAddrFtnPtr).c_str()); -} - -void MethodContext::repGetThreadLocalStaticInfo_NativeAOT(CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo) -{ - DWORDLONG key = 1; - Agnostic_GetThreadStaticInfo_NativeAOT value = - LookupByKeyOrMiss(GetThreadLocalStaticInfo_NativeAOT, key, ": key %016" PRIX64 "", key); - - DEBUG_REP(dmpGetThreadLocalStaticInfo_NativeAOT(key, value)); - - pInfo->tlsRootObject = SpmiRecordsHelper::RestoreCORINFO_CONST_LOOKUP(value.tlsRootObject); - pInfo->tlsIndexObject = SpmiRecordsHelper::RestoreCORINFO_CONST_LOOKUP(value.tlsIndexObject); - pInfo->offsetOfThreadLocalStoragePointer = value.offsetOfThreadLocalStoragePointer; - pInfo->threadStaticBaseSlow = SpmiRecordsHelper::RestoreCORINFO_CONST_LOOKUP(value.threadStaticBaseSlow); - pInfo->tlsGetAddrFtnPtr = SpmiRecordsHelper::RestoreCORINFO_CONST_LOOKUP(value.tlsGetAddrFtnPtr); -} - -void MethodContext::recEmbedMethodHandle(CORINFO_METHOD_HANDLE handle, - void** ppIndirection, - CORINFO_METHOD_HANDLE result) -{ - if (EmbedMethodHandle == nullptr) - EmbedMethodHandle = new LightWeightMap(); - - DLDL value; - if (ppIndirection == nullptr) - value.A = 0; - else - value.A = CastPointer(*ppIndirection); - value.B = CastHandle(result); - - DWORDLONG key = CastHandle(handle); - EmbedMethodHandle->Add(key, value); - DEBUG_REC(dmpEmbedMethodHandle(key, value)); -} -void MethodContext::dmpEmbedMethodHandle(DWORDLONG key, DLDL value) -{ - printf("EmbedMethodHandle key ftn-%016" PRIX64 ", value pp-%016" PRIX64 " res-%016" PRIX64 "", key, value.A, value.B); -} -CORINFO_METHOD_HANDLE MethodContext::repEmbedMethodHandle(CORINFO_METHOD_HANDLE handle, void** ppIndirection) -{ - DWORDLONG key = CastHandle(handle); - DLDL value = LookupByKeyOrMiss(EmbedMethodHandle, key, ": key %016" PRIX64 "", key); - - DEBUG_REP(dmpEmbedMethodHandle(key, value)); - - if (ppIndirection != nullptr) - *ppIndirection = (void*)value.A; - return (CORINFO_METHOD_HANDLE)value.B; -} - -void MethodContext::recGetStaticFieldContent(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects, bool result) -{ - if (GetStaticFieldContent == nullptr) - GetStaticFieldContent = new LightWeightMap(); - - DLDDD key; - ZeroMemory(&key, sizeof(key)); - key.A = CastHandle(field); - key.B = (DWORD)bufferSize; - key.C = (DWORD)ignoreMovableObjects; - key.D = (DWORD)valueOffset; - - DWORD tmpBuf = (DWORD)-1; - if (buffer != nullptr && result) - tmpBuf = (DWORD)GetStaticFieldContent->AddBuffer((uint8_t*)buffer, (uint32_t)bufferSize); - - DD value; - value.A = (DWORD)result; - value.B = (DWORD)tmpBuf; - - GetStaticFieldContent->Add(key, value); - DEBUG_REC(dmpGetStaticFieldContent(key, value)); -} -void MethodContext::dmpGetStaticFieldContent(DLDDD key, DD value) -{ - printf("GetStaticFieldContent key fld-%016" PRIX64 " bufSize-%u, ignoremovable-%u, valOffset-%u result-%u", key.A, key.B, key.C, key.D, value.A); - GetStaticFieldContent->Unlock(); -} -bool MethodContext::repGetStaticFieldContent(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects) -{ - DLDDD key; - ZeroMemory(&key, sizeof(key)); - key.A = CastHandle(field); - key.B = (DWORD)bufferSize; - key.C = (DWORD)ignoreMovableObjects; - key.D = (DWORD)valueOffset; - - DD value = LookupByKeyOrMiss(GetStaticFieldContent, key, ": key %016" PRIX64 "", key.A); - - DEBUG_REP(dmpGetStaticFieldContent(key, value)); - if (buffer != nullptr && (bool)value.A) - { - uint8_t* srcBuffer = (uint8_t*)GetStaticFieldContent->GetBuffer(value.B); - Assert(srcBuffer != nullptr); - memcpy(buffer, srcBuffer, bufferSize); - } - return (bool)value.A; -} - -void MethodContext::recGetObjectContent(CORINFO_OBJECT_HANDLE obj, uint8_t* buffer, int bufferSize, int valueOffset, bool result) -{ - if (GetObjectContent == nullptr) - GetObjectContent = new LightWeightMap(); - - DLDD key; - ZeroMemory(&key, sizeof(key)); - key.A = CastHandle(obj); - key.B = (DWORD)bufferSize; - key.C = (DWORD)valueOffset; - - DWORD tmpBuf = (DWORD)-1; - if (buffer != nullptr && result) - tmpBuf = (DWORD)GetObjectContent->AddBuffer((uint8_t*)buffer, (uint32_t)bufferSize); - - DD value; - value.A = (DWORD)result; - value.B = (DWORD)tmpBuf; - - GetObjectContent->Add(key, value); - DEBUG_REC(dmpGetObjectContent(key, value)); -} -void MethodContext::dmpGetObjectContent(DLDD key, DD value) -{ - printf("GetObjectContent key fld-%016" PRIX64 " bufSize-%u, valOffset-%u result-%u", key.A, key.B, key.C, value.A); - GetObjectContent->Unlock(); -} -bool MethodContext::repGetObjectContent(CORINFO_OBJECT_HANDLE obj, uint8_t* buffer, int bufferSize, int valueOffset) -{ - DLDD key; - ZeroMemory(&key, sizeof(key)); - key.A = CastHandle(obj); - key.B = (DWORD)bufferSize; - key.C = (DWORD)valueOffset; - - DD value = LookupByKeyOrMiss(GetObjectContent, key, ": key %016" PRIX64 "", key.A); - - DEBUG_REP(dmpGetObjectContent(key, value)); - if (buffer != nullptr && (bool)value.A) - { - uint8_t* srcBuffer = (uint8_t*)GetObjectContent->GetBuffer(value.B); - Assert(srcBuffer != nullptr); - memcpy(buffer, srcBuffer, bufferSize); - } - return (bool)value.A; -} - -void MethodContext::recGetStaticFieldCurrentClass(CORINFO_FIELD_HANDLE field, - bool* pIsSpeculative, - CORINFO_CLASS_HANDLE result) -{ - if (GetStaticFieldCurrentClass == nullptr) - GetStaticFieldCurrentClass = new LightWeightMap(); - - DLD key; - ZeroMemory(&key, sizeof(key)); - key.A = CastHandle(field); - key.B = pIsSpeculative != nullptr ? 1 : 0; - - Agnostic_GetStaticFieldCurrentClass value; - value.classHandle = CastHandle(result); - value.isSpeculative = pIsSpeculative != nullptr ? *pIsSpeculative : false; - - GetStaticFieldCurrentClass->Add(key, value); - DEBUG_REC(dmpGetStaticFieldCurrentClass(key, value)); -} -void MethodContext::dmpGetStaticFieldCurrentClass(DLD key, const Agnostic_GetStaticFieldCurrentClass& value) -{ - printf("GetStaticFieldCurrentClass key fld-%016" PRIX64 ", value clsHnd-%016" PRIX64 " isSpeculative-%u", key.A, value.classHandle, - value.isSpeculative); -} -CORINFO_CLASS_HANDLE MethodContext::repGetStaticFieldCurrentClass(CORINFO_FIELD_HANDLE field, bool* pIsSpeculative) -{ - DLD key; - ZeroMemory(&key, sizeof(key)); - key.A = CastHandle(field); - key.B = pIsSpeculative != nullptr ? 1 : 0; - - Agnostic_GetStaticFieldCurrentClass value = LookupByKeyOrMiss(GetStaticFieldCurrentClass, key, ": key %016" PRIX64 "", key); - - DEBUG_REP(dmpGetStaticFieldCurrentClass(key, value)); - - if (pIsSpeculative != nullptr) - { - *pIsSpeculative = value.isSpeculative; - } - - CORINFO_CLASS_HANDLE result = (CORINFO_CLASS_HANDLE)value.classHandle; - return result; -} - -void MethodContext::recGetClassGClayout(CORINFO_CLASS_HANDLE cls, BYTE* gcPtrs, unsigned len, unsigned result) -{ - if (GetClassGClayout == nullptr) - GetClassGClayout = new LightWeightMap(); - - Agnostic_GetClassGClayout value; - - value.gcPtrs_Index = (DWORD)GetClassGClayout->AddBuffer((unsigned char*)gcPtrs, len * sizeof(BYTE)); - value.len = (DWORD)len; - value.valCount = (DWORD)result; - - DWORDLONG key = CastHandle(cls); - GetClassGClayout->Add(key, value); - DEBUG_REC(dmpGetClassGClayout(key, value)); -} -void MethodContext::dmpGetClassGClayout(DWORDLONG key, const Agnostic_GetClassGClayout& value) -{ - printf("GetClassGCLayout key %016" PRIX64 ", value len %u cnt %u {", key, value.len, value.valCount); - if (value.gcPtrs_Index != (DWORD)-1) - { - BYTE* ptr = (BYTE*)GetClassGClayout->GetBuffer(value.gcPtrs_Index); - for (unsigned int i = 0; i < value.len; i++) - { - printf("0x%02x", ptr[i]); - if (i + 1 < value.len) - printf(","); - } - GetClassGClayout->Unlock(); - } - printf("}"); -} -unsigned MethodContext::repGetClassGClayout(CORINFO_CLASS_HANDLE cls, BYTE* gcPtrs) -{ - DWORDLONG key = CastHandle(cls); - Agnostic_GetClassGClayout value = LookupByKeyOrMiss(GetClassGClayout, key, ": key %016" PRIX64 "", key); - - DEBUG_REP(dmpGetClassGClayout(key, value)); - - unsigned int len = (unsigned int)value.len; - unsigned int index = (unsigned int)value.gcPtrs_Index; - - if (index != (unsigned int)-1) - { - BYTE* ptr = (BYTE*)GetClassGClayout->GetBuffer(index); - for (unsigned int i = 0; i < len; i++) - gcPtrs[i] = ptr[i]; - } - return (unsigned)value.valCount; -} - -void MethodContext::recGetClassAlignmentRequirement(CORINFO_CLASS_HANDLE cls, bool fDoubleAlignHint, unsigned result) -{ - if (GetClassAlignmentRequirement == nullptr) - GetClassAlignmentRequirement = new LightWeightMap(); - - DLD key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(cls); - key.B = (DWORD)fDoubleAlignHint; - - DWORD value = (DWORD)result; - GetClassAlignmentRequirement->Add(key, value); - DEBUG_REC(dmpGetClassAlignmentRequirement(key, value)); -} -void MethodContext::dmpGetClassAlignmentRequirement(DLD key, DWORD value) -{ - printf("GetClassAlignmentRequirement key %016" PRIX64 " %u, value %u", key.A, key.B, value); -} -unsigned MethodContext::repGetClassAlignmentRequirement(CORINFO_CLASS_HANDLE cls, bool fDoubleAlignHint) -{ - DLD key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(cls); - key.B = (DWORD)fDoubleAlignHint; - - DWORD value = LookupByKeyOrMiss(GetClassAlignmentRequirement, key, ": key %016" PRIX64 "", key.A); - - DEBUG_REP(dmpGetClassAlignmentRequirement(key, value)); - unsigned result = (unsigned)value; - return result; -} - -void MethodContext::recCanAccessClass(CORINFO_RESOLVED_TOKEN* pResolvedToken, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_HELPER_DESC* pAccessHelper, - CorInfoIsAccessAllowedResult result) -{ - if (CanAccessClass == nullptr) - CanAccessClass = new LightWeightMap(); - - Agnostic_CanAccessClassIn key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.ResolvedToken = SpmiRecordsHelper::StoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, CanAccessClass); - key.callerHandle = CastHandle(callerHandle); - - Agnostic_CanAccessClassOut value; - value.AccessHelper.helperNum = (DWORD)pAccessHelper->helperNum; - value.AccessHelper.numArgs = (DWORD)pAccessHelper->numArgs; - for (int i = 0; i < CORINFO_ACCESS_ALLOWED_MAX_ARGS; i++) - { - value.AccessHelper.args[i].constant = (DWORDLONG)pAccessHelper->args[i].constant; - value.AccessHelper.args[i].argType = (DWORD)pAccessHelper->args[i].argType; - } - value.result = (DWORD)result; - - CanAccessClass->Add(key, value); - DEBUG_REC(dmpCanAccessClass(key, value)); -} -void MethodContext::dmpCanAccessClass(const Agnostic_CanAccessClassIn& key, const Agnostic_CanAccessClassOut& value) -{ - printf("CanAccessClass key rt{%s}, callerHandle %016" PRIX64 "\n", - SpmiDumpHelper::DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.ResolvedToken).c_str(), key.callerHandle); - printf(", value hnum-%u na-%u {", value.AccessHelper.helperNum, value.AccessHelper.numArgs); - for (int i = 0; i < CORINFO_ACCESS_ALLOWED_MAX_ARGS; i++) - { - printf("{%016" PRIX64 " %u}", value.AccessHelper.args[i].constant, value.AccessHelper.args[i].argType); - } - printf("} res-%u", value.result); -} -CorInfoIsAccessAllowedResult MethodContext::repCanAccessClass(CORINFO_RESOLVED_TOKEN* pResolvedToken, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_HELPER_DESC* pAccessHelper) -{ - AssertMapExists(CanAccessClass, ": key %016" PRIX64 "", CastHandle(pResolvedToken->hClass)); - - Agnostic_CanAccessClassIn key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.ResolvedToken = SpmiRecordsHelper::RestoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, CanAccessClass); - key.callerHandle = CastHandle(callerHandle); - - Agnostic_CanAccessClassOut value = LookupByKeyOrMiss(CanAccessClass, key, ": key %016" PRIX64 "", CastHandle(pResolvedToken->hClass)); - - DEBUG_REP(dmpCanAccessClass(key, value)); - - pAccessHelper->helperNum = (CorInfoHelpFunc)value.AccessHelper.helperNum; - pAccessHelper->numArgs = (unsigned)value.AccessHelper.numArgs; - for (int i = 0; i < CORINFO_ACCESS_ALLOWED_MAX_ARGS; i++) - { - pAccessHelper->args[i].constant = (size_t)value.AccessHelper.args[i].constant; - pAccessHelper->args[i].argType = (CorInfoAccessAllowedHelperArgType)value.AccessHelper.args[i].argType; - } - CorInfoIsAccessAllowedResult temp = (CorInfoIsAccessAllowedResult)value.result; - return temp; -} - -void MethodContext::recGetCastingHelper(CORINFO_RESOLVED_TOKEN* pResolvedToken, bool fThrowing, CorInfoHelpFunc result) -{ - if (GetCastingHelper == nullptr) - GetCastingHelper = new LightWeightMap(); - - Agnostic_GetCastingHelper key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.hClass = CastHandle(pResolvedToken->hClass); - key.fThrowing = (DWORD)fThrowing; - - DWORD value = (DWORD)result; - GetCastingHelper->Add(key, value); - DEBUG_REC(dmpGetCastingHelper(key, value)); -} -void MethodContext::dmpGetCastingHelper(const Agnostic_GetCastingHelper& key, DWORD value) -{ - printf("GetCastingHelper key cls-%016" PRIX64 ", thw-%u, value res-%u", key.hClass, key.fThrowing, value); -} -CorInfoHelpFunc MethodContext::repGetCastingHelper(CORINFO_RESOLVED_TOKEN* pResolvedToken, bool fThrowing) -{ - Agnostic_GetCastingHelper key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.hClass = CastHandle(pResolvedToken->hClass); - key.fThrowing = (DWORD)fThrowing; - - DWORD value = LookupByKeyOrMiss(GetCastingHelper, key, ": key %016" PRIX64 "", key.hClass); - - DEBUG_REP(dmpGetCastingHelper(key, value)); - CorInfoHelpFunc result = (CorInfoHelpFunc)value; - return result; -} - -void MethodContext::recEmbedModuleHandle(CORINFO_MODULE_HANDLE handle, - void** ppIndirection, - CORINFO_MODULE_HANDLE result) -{ - if (EmbedModuleHandle == nullptr) - EmbedModuleHandle = new LightWeightMap(); - - DLDL value; - if (ppIndirection != nullptr) - value.A = CastPointer(*ppIndirection); - else - value.A = 0; - value.B = CastHandle(result); - - DWORDLONG key = CastHandle(handle); - EmbedModuleHandle->Add(key, value); - DEBUG_REC(dmpEmbedModuleHandle(key, value)); -} -void MethodContext::dmpEmbedModuleHandle(DWORDLONG key, DLDL value) -{ - printf("EmbedModuleHandle key mod-%016" PRIX64 ", value pp-%016" PRIX64 " res-%016" PRIX64 "", key, value.A, value.B); -} -CORINFO_MODULE_HANDLE MethodContext::repEmbedModuleHandle(CORINFO_MODULE_HANDLE handle, void** ppIndirection) -{ - DWORDLONG key = CastHandle(handle); - DLDL value = LookupByKeyOrMiss(EmbedModuleHandle, key, ": key %016" PRIX64 "", key); - - DEBUG_REP(dmpEmbedModuleHandle(key, value)); - - if (ppIndirection != nullptr) - *ppIndirection = (void*)value.A; - return (CORINFO_MODULE_HANDLE)value.B; -} - -const DWORDLONG CONTINUATION_TYPE_PSEUDO_CLASS_HANDLE = (DWORDLONG)0x12345678beef0000; -void MethodContext::recEmbedClassHandle(CORINFO_CLASS_HANDLE handle, void** ppIndirection, CORINFO_CLASS_HANDLE result) -{ - if (EmbedClassHandle == nullptr) - EmbedClassHandle = new LightWeightMap(); - - DLDL value; - if (ppIndirection != nullptr) - value.A = CastPointer(*ppIndirection); - else - value.A = 0; - value.B = CastHandle(result); - - DWORDLONG key = CastHandle(handle); - EmbedClassHandle->Add(key, value); - DEBUG_REC(dmpEmbedClassHandle(key, value)); -} -void MethodContext::dmpEmbedClassHandle(DWORDLONG key, DLDL value) -{ - printf("EmbedClassHandle key cls-%016" PRIX64 ", value pp-%016" PRIX64 " res-%016" PRIX64 "", key, value.A, value.B); -} -CORINFO_CLASS_HANDLE MethodContext::repEmbedClassHandle(CORINFO_CLASS_HANDLE handle, void** ppIndirection) -{ - DWORDLONG key = CastHandle(handle); - if (key == CONTINUATION_TYPE_PSEUDO_CLASS_HANDLE) - { - if ((EmbedClassHandle->GetCount() > 0) && (EmbedClassHandle->GetItem(0).A != 0)) - { - // Some other embedded handle required an indirection, so do the same for the pseudo handle - // (avoids spurious improvements in R2R scenarios) - *ppIndirection = (void*)CONTINUATION_TYPE_PSEUDO_CLASS_HANDLE; - return nullptr; - } - - *ppIndirection = nullptr; - return handle; - } - - DLDL value = LookupByKeyOrMiss(EmbedClassHandle, key, ": key %016" PRIX64 "", key); - - DEBUG_REP(dmpEmbedClassHandle(key, value)); - - *ppIndirection = (void*)value.A; - return (CORINFO_CLASS_HANDLE)value.B; -} - -void MethodContext::recPInvokeMarshalingRequired(CORINFO_METHOD_HANDLE method, - CORINFO_SIG_INFO* callSiteSig, - bool result) -{ - if (PInvokeMarshalingRequired == nullptr) - PInvokeMarshalingRequired = new LightWeightMap(); - - MethodOrSigInfoValue key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.method = CastHandle(method); - key.pSig_Index = (DWORD)PInvokeMarshalingRequired->AddBuffer((unsigned char*)callSiteSig->pSig, callSiteSig->cbSig); - key.cbSig = (DWORD)callSiteSig->cbSig; - key.scope = CastHandle(callSiteSig->scope); - - DWORD value = result ? 1 : 0; - PInvokeMarshalingRequired->Add(key, value); - DEBUG_REC(dmpPInvokeMarshalingRequired(key, value)); -} -void MethodContext::dmpPInvokeMarshalingRequired(const MethodOrSigInfoValue& key, DWORD value) -{ - printf("PInvokeMarshalingRequired key mth-%016" PRIX64 " scp-%016" PRIX64 " sig-%s, value res-%u", - key.method, key.scope, - SpmiDumpHelper::DumpPSig(key.pSig_Index, key.cbSig, PInvokeMarshalingRequired).c_str(), - value); -} -// Note the jit interface implementation seems to only care about scope and pSig from callSiteSig -bool MethodContext::repPInvokeMarshalingRequired(CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* callSiteSig) -{ - if (PInvokeMarshalingRequired == nullptr) // so when we replay Checked on Release, we throw from lwm - return true; // TODO-Cleanup: hackish... - - MethodOrSigInfoValue key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.method = CastHandle(method); - key.pSig_Index = (DWORD)PInvokeMarshalingRequired->Contains((unsigned char*)callSiteSig->pSig, callSiteSig->cbSig); - key.cbSig = (DWORD)callSiteSig->cbSig; - key.scope = CastHandle(callSiteSig->scope); - - DWORD value = LookupByKeyOrMissNoMessage(PInvokeMarshalingRequired, key); - - DEBUG_REP(dmpPInvokeMarshalingRequired(key, value)); - return value != 0; -} - -void MethodContext::recGetUnmanagedCallConv(CORINFO_METHOD_HANDLE method, - CORINFO_SIG_INFO* callSiteSig, - CorInfoCallConvExtension result, - bool suppressGCTransitionResult) -{ - if (GetUnmanagedCallConv == nullptr) - GetUnmanagedCallConv = new LightWeightMap(); - - MethodOrSigInfoValue key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.method = CastHandle(method); - if (callSiteSig != nullptr) - { - key.pSig_Index = (DWORD)GetUnmanagedCallConv->AddBuffer((unsigned char*)callSiteSig->pSig, callSiteSig->cbSig); - key.cbSig = (DWORD)callSiteSig->cbSig; - key.scope = CastHandle(callSiteSig->scope); - } - else - { - key.pSig_Index = 0; - key.cbSig = 0; - key.scope = 0; - } - - DD value; - value.A = (DWORD)result; - value.B = (DWORD)suppressGCTransitionResult; - - GetUnmanagedCallConv->Add(key, value); - DEBUG_REC(dmpGetUnmanagedCallConv(key, value)); -} -void MethodContext::dmpGetUnmanagedCallConv(const MethodOrSigInfoValue& key, DD value) -{ - printf("GetUnmanagedCallConv key mth-%016" PRIX64 " scp-%016" PRIX64 " sig-%s, value res-%u,%u", - key.method, key.scope, - SpmiDumpHelper::DumpPSig(key.pSig_Index, key.cbSig, GetUnmanagedCallConv).c_str(), - value.A, value.B); -} -// Note the jit interface implementation seems to only care about scope and pSig from callSiteSig -CorInfoCallConvExtension MethodContext::repGetUnmanagedCallConv(CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* callSiteSig, bool* pSuppressGCTransition) -{ - if (GetUnmanagedCallConv == nullptr) - { -#ifdef sparseMC - LogDebug("Sparse - repGetUnmanagedCallConv returning CorInfoCallConvExtension::Managed"); - return CorInfoCallConvExtension::Managed; -#else - LogException(EXCEPTIONCODE_MC, "Found a null GetUnmanagedCallConv. Probably missing a fatTrigger for %016" PRIX64 ".", - CastHandle(method)); -#endif - } - - MethodOrSigInfoValue key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.method = CastHandle(method); - if (callSiteSig != nullptr) - { - key.pSig_Index = (DWORD)GetUnmanagedCallConv->Contains((unsigned char*)callSiteSig->pSig, callSiteSig->cbSig); - key.cbSig = (DWORD)callSiteSig->cbSig; - key.scope = CastHandle(callSiteSig->scope); - } - else - { - key.pSig_Index = 0; - key.cbSig = 0; - key.scope = 0; - } - - DD value = LookupByKeyOrMissNoMessage(GetUnmanagedCallConv, key); - - DEBUG_REP(dmpGetUnmanagedCallConv(key, value)); - - *pSuppressGCTransition = value.B != 0; - return (CorInfoCallConvExtension)value.A; -} - -void MethodContext::recFindSig(CORINFO_MODULE_HANDLE moduleHandle, - unsigned sigTOK, - CORINFO_CONTEXT_HANDLE context, - CORINFO_SIG_INFO* sig) -{ - if (FindSig == nullptr) - FindSig = new LightWeightMap(); - - Agnostic_FindSig key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.module = CastHandle(moduleHandle); - key.sigTOK = (DWORD)sigTOK; - key.context = CastHandle(context); - - Agnostic_CORINFO_SIG_INFO value = SpmiRecordsHelper::StoreAgnostic_CORINFO_SIG_INFO(*sig, FindSig, SigInstHandleMap); - - FindSig->Add(key, value); - DEBUG_REC(dmpFindSig(key, value)); -} -void MethodContext::dmpFindSig(const Agnostic_FindSig& key, const Agnostic_CORINFO_SIG_INFO& value) -{ - printf("FindSig key module-%016" PRIX64 " sigTOK-%08X context-%016" PRIX64 "", key.module, key.sigTOK, key.context); - printf(", value-%s", - SpmiDumpHelper::DumpAgnostic_CORINFO_SIG_INFO(value, FindSig, SigInstHandleMap).c_str()); -} -void MethodContext::repFindSig(CORINFO_MODULE_HANDLE moduleHandle, - unsigned sigTOK, - CORINFO_CONTEXT_HANDLE context, - CORINFO_SIG_INFO* sig) -{ - Agnostic_FindSig key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.module = CastHandle(moduleHandle); - key.sigTOK = (DWORD)sigTOK; - key.context = CastHandle(context); - - Agnostic_CORINFO_SIG_INFO value = LookupByKeyOrMissNoMessage(FindSig, key); - - DEBUG_REP(dmpFindSig(key, value)); - - *sig = SpmiRecordsHelper::Restore_CORINFO_SIG_INFO(value, FindSig, SigInstHandleMap, cr->getOrCreateMemoryTracker()); -} - -void MethodContext::recGetEEInfo(CORINFO_EE_INFO* pEEInfoOut) -{ - if (GetEEInfo == nullptr) - GetEEInfo = new LightWeightMap(); - - Agnostic_CORINFO_EE_INFO value; - - value.inlinedCallFrameInfo.size = (DWORD)pEEInfoOut->inlinedCallFrameInfo.size; - value.inlinedCallFrameInfo.sizeWithSecretStubArg = (DWORD)pEEInfoOut->inlinedCallFrameInfo.sizeWithSecretStubArg; - value.inlinedCallFrameInfo.offsetOfFrameLink = (DWORD)pEEInfoOut->inlinedCallFrameInfo.offsetOfFrameLink; - value.inlinedCallFrameInfo.offsetOfCallSiteSP = (DWORD)pEEInfoOut->inlinedCallFrameInfo.offsetOfCallSiteSP; - value.inlinedCallFrameInfo.offsetOfCalleeSavedFP = (DWORD)pEEInfoOut->inlinedCallFrameInfo.offsetOfCalleeSavedFP; - value.inlinedCallFrameInfo.offsetOfCallTarget = (DWORD)pEEInfoOut->inlinedCallFrameInfo.offsetOfCallTarget; - value.inlinedCallFrameInfo.offsetOfReturnAddress = (DWORD)pEEInfoOut->inlinedCallFrameInfo.offsetOfReturnAddress; - value.inlinedCallFrameInfo.offsetOfSecretStubArg = (DWORD)pEEInfoOut->inlinedCallFrameInfo.offsetOfSecretStubArg; - value.inlinedCallFrameInfo.offsetOfSPAfterProlog = (DWORD)pEEInfoOut->inlinedCallFrameInfo.offsetOfSPAfterProlog; - value.offsetOfThreadFrame = (DWORD)pEEInfoOut->offsetOfThreadFrame; - value.offsetOfGCState = (DWORD)pEEInfoOut->offsetOfGCState; - value.offsetOfDelegateInstance = (DWORD)pEEInfoOut->offsetOfDelegateInstance; - value.offsetOfDelegateFirstTarget = (DWORD)pEEInfoOut->offsetOfDelegateFirstTarget; - value.sizeOfReversePInvokeFrame = (DWORD)pEEInfoOut->sizeOfReversePInvokeFrame; - value.osPageSize = (DWORD)pEEInfoOut->osPageSize; - value.maxUncheckedOffsetForNullObject = (DWORD)pEEInfoOut->maxUncheckedOffsetForNullObject; - value.targetAbi = (DWORD)pEEInfoOut->targetAbi; - value.osType = (DWORD)pEEInfoOut->osType; - - GetEEInfo->Add(0, value); - DEBUG_REC(dmpGetEEInfo(0, value)); -} -void MethodContext::dmpGetEEInfo(DWORD key, const Agnostic_CORINFO_EE_INFO& value) -{ - printf("GetEEInfo key %u, value icfi{sz-%u sz-witharg-%u ofl-%u ocsp-%u ocsfp-%u oct-%u ora-%u ossa-%u osap-%u} " - "otf-%u ogcs-%u odi-%u odft-%u srpf-%u osps-%u muono-%u tabi-%u osType-%u", - key, value.inlinedCallFrameInfo.size, value.inlinedCallFrameInfo.sizeWithSecretStubArg, - value.inlinedCallFrameInfo.offsetOfFrameLink, - value.inlinedCallFrameInfo.offsetOfCallSiteSP, value.inlinedCallFrameInfo.offsetOfCalleeSavedFP, - value.inlinedCallFrameInfo.offsetOfCallTarget, value.inlinedCallFrameInfo.offsetOfReturnAddress, - value.inlinedCallFrameInfo.offsetOfSecretStubArg, value.inlinedCallFrameInfo.offsetOfSPAfterProlog, - value.offsetOfThreadFrame, value.offsetOfGCState, value.offsetOfDelegateInstance, - value.offsetOfDelegateFirstTarget, - value.sizeOfReversePInvokeFrame, value.osPageSize, value.maxUncheckedOffsetForNullObject, value.targetAbi, - value.osType); -} -void MethodContext::repGetEEInfo(CORINFO_EE_INFO* pEEInfoOut) -{ - Agnostic_CORINFO_EE_INFO value = LookupByKeyOrMissNoMessage(GetEEInfo, 0); - - DEBUG_REP(dmpGetEEInfo(0, value)); - - pEEInfoOut->inlinedCallFrameInfo.size = (unsigned)value.inlinedCallFrameInfo.size; - pEEInfoOut->inlinedCallFrameInfo.sizeWithSecretStubArg = (unsigned)value.inlinedCallFrameInfo.sizeWithSecretStubArg; - pEEInfoOut->inlinedCallFrameInfo.offsetOfFrameLink = (unsigned)value.inlinedCallFrameInfo.offsetOfFrameLink; - pEEInfoOut->inlinedCallFrameInfo.offsetOfCallSiteSP = (unsigned)value.inlinedCallFrameInfo.offsetOfCallSiteSP; - pEEInfoOut->inlinedCallFrameInfo.offsetOfCalleeSavedFP = - (unsigned)value.inlinedCallFrameInfo.offsetOfCalleeSavedFP; - pEEInfoOut->inlinedCallFrameInfo.offsetOfCallTarget = (unsigned)value.inlinedCallFrameInfo.offsetOfCallTarget; - pEEInfoOut->inlinedCallFrameInfo.offsetOfReturnAddress = - (unsigned)value.inlinedCallFrameInfo.offsetOfReturnAddress; - pEEInfoOut->inlinedCallFrameInfo.offsetOfSecretStubArg = (unsigned)value.inlinedCallFrameInfo.offsetOfSecretStubArg; - pEEInfoOut->inlinedCallFrameInfo.offsetOfSPAfterProlog = (unsigned)value.inlinedCallFrameInfo.offsetOfSPAfterProlog; - pEEInfoOut->offsetOfThreadFrame = (unsigned)value.offsetOfThreadFrame; - pEEInfoOut->offsetOfGCState = (unsigned)value.offsetOfGCState; - pEEInfoOut->offsetOfDelegateInstance = (unsigned)value.offsetOfDelegateInstance; - pEEInfoOut->offsetOfDelegateFirstTarget = (unsigned)value.offsetOfDelegateFirstTarget; - pEEInfoOut->sizeOfReversePInvokeFrame = (unsigned)value.sizeOfReversePInvokeFrame; - pEEInfoOut->osPageSize = (size_t)value.osPageSize; - pEEInfoOut->maxUncheckedOffsetForNullObject = (size_t)value.maxUncheckedOffsetForNullObject; - pEEInfoOut->targetAbi = (CORINFO_RUNTIME_ABI)value.targetAbi; - pEEInfoOut->osType = (CORINFO_OS)value.osType; -} - -void MethodContext::recGetAsyncInfo(const CORINFO_ASYNC_INFO* pAsyncInfo) -{ - if (GetAsyncInfo == nullptr) - GetAsyncInfo = new LightWeightMap(); - - Agnostic_CORINFO_ASYNC_INFO value; - ZeroMemory(&value, sizeof(value)); - - value.continuationClsHnd = CastHandle(pAsyncInfo->continuationClsHnd); - value.continuationNextFldHnd = CastHandle(pAsyncInfo->continuationNextFldHnd); - value.continuationResumeInfoFldHnd = CastHandle(pAsyncInfo->continuationResumeInfoFldHnd); - value.continuationStateFldHnd = CastHandle(pAsyncInfo->continuationStateFldHnd); - value.continuationFlagsFldHnd = CastHandle(pAsyncInfo->continuationFlagsFldHnd); - value.captureExecutionContextMethHnd = CastHandle(pAsyncInfo->captureExecutionContextMethHnd); - value.captureContinuationContextMethHnd = CastHandle(pAsyncInfo->captureContinuationContextMethHnd); - 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); - - GetAsyncInfo->Add(0, value); - DEBUG_REC(dmpGetAsyncInfo(0, value)); -} -void MethodContext::dmpGetAsyncInfo(DWORD key, const Agnostic_CORINFO_ASYNC_INFO& value) -{ - printf("GetAsyncInfo key %u value contClsHnd-%016" PRIX64 " contNextFldHnd-%016" PRIX64 " contResumeInfoFldHnd-%016" PRIX64 - " contStateFldHnd-%016" PRIX64 " contFlagsFldHnd-%016" PRIX64, - key, value.continuationClsHnd, value.continuationNextFldHnd, value.continuationResumeInfoFldHnd, - value.continuationStateFldHnd, value.continuationFlagsFldHnd); -} -void MethodContext::repGetAsyncInfo(CORINFO_ASYNC_INFO* pAsyncInfoOut) -{ - Agnostic_CORINFO_ASYNC_INFO value = LookupByKeyOrMissNoMessage(GetAsyncInfo, 0); - pAsyncInfoOut->continuationClsHnd = (CORINFO_CLASS_HANDLE)value.continuationClsHnd; - pAsyncInfoOut->continuationNextFldHnd = (CORINFO_FIELD_HANDLE)value.continuationNextFldHnd; - pAsyncInfoOut->continuationResumeInfoFldHnd = (CORINFO_FIELD_HANDLE)value.continuationResumeInfoFldHnd; - pAsyncInfoOut->continuationStateFldHnd = (CORINFO_FIELD_HANDLE)value.continuationStateFldHnd; - pAsyncInfoOut->continuationFlagsFldHnd = (CORINFO_FIELD_HANDLE)value.continuationFlagsFldHnd; - pAsyncInfoOut->captureExecutionContextMethHnd = (CORINFO_METHOD_HANDLE)value.captureExecutionContextMethHnd; - pAsyncInfoOut->captureContinuationContextMethHnd = (CORINFO_METHOD_HANDLE)value.captureContinuationContextMethHnd; - 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)); -} - -void MethodContext::recGetWasmWellKnownGlobals(const CORINFO_WASM_WELLKNOWN_GLOBALS* pBaseGlobals) -{ - if (GetWasmWellKnownGlobals == nullptr) - GetWasmWellKnownGlobals = new LightWeightMap(); - - Agnostic_CORINFO_WASM_WELLKNOWN_GLOBALS value; - ZeroMemory(&value, sizeof(value)); - - value.stackPointer = CastHandle(pBaseGlobals->stackPointer); - value.imageBase = CastHandle(pBaseGlobals->imageBase); - value.tableBase = CastHandle(pBaseGlobals->tableBase); - value.asyncContinuation = CastHandle(pBaseGlobals->asyncContinuation); - - GetWasmWellKnownGlobals->Add(0, value); - DEBUG_REC(dmpGetWasmWellKnownGlobals(0, value)); -} -void MethodContext::dmpGetWasmWellKnownGlobals(DWORD key, const Agnostic_CORINFO_WASM_WELLKNOWN_GLOBALS& value) -{ - printf("GetWasmWellKnownGlobals key %u value stackPointer-%016" PRIX64 " imageBase-%016" PRIX64 " tableBase-%016" PRIX64 " asyncContinuation-%016" PRIX64, - key, value.stackPointer, value.imageBase, value.tableBase, value.asyncContinuation); -} -void MethodContext::repGetWasmWellKnownGlobals(CORINFO_WASM_WELLKNOWN_GLOBALS* pWellKnownGlobalsOut) -{ - Agnostic_CORINFO_WASM_WELLKNOWN_GLOBALS value = LookupByKeyOrMissNoMessage(GetWasmWellKnownGlobals, 0); - pWellKnownGlobalsOut->stackPointer = (CORINFO_WASM_GLOBAL_SYMBOL_HANDLE)value.stackPointer; - pWellKnownGlobalsOut->imageBase = (CORINFO_WASM_GLOBAL_SYMBOL_HANDLE)value.imageBase; - pWellKnownGlobalsOut->tableBase = (CORINFO_WASM_GLOBAL_SYMBOL_HANDLE)value.tableBase; - pWellKnownGlobalsOut->asyncContinuation = (CORINFO_WASM_GLOBAL_SYMBOL_HANDLE)value.asyncContinuation; - DEBUG_REP(dmpGetWasmWellKnownGlobals(0, value)); -} -void MethodContext::recGetAwaitReturnCall(CORINFO_METHOD_HANDLE callerHnd, CORINFO_CONTEXT_HANDLE* contextHandle, CORINFO_LOOKUP* instArg, CORINFO_METHOD_HANDLE methHnd) -{ - if (GetAwaitReturnCall == nullptr) - GetAwaitReturnCall = new LightWeightMap(); - - Agnostic_GetAwaitReturnCallResult value; - ZeroMemory(&value, sizeof(value)); - value.methodHnd = CastHandle(methHnd); - value.contextHandle = CastHandle(*contextHandle); - value.instArg = SpmiRecordsHelper::StoreAgnostic_CORINFO_LOOKUP(instArg); - - GetAwaitReturnCall->Add(CastHandle(callerHnd), value); - DEBUG_REC(dmpGetAwaitReturnCall(CastHandle(callerHnd), value)); -} -void MethodContext::dmpGetAwaitReturnCall(DWORDLONG key, Agnostic_GetAwaitReturnCallResult& value) -{ - printf("GetAwaitReturnCall key %016" PRIX64 " value methodHnd-%016" PRIX64 " contextHandle-%016" PRIX64 " instArg %s", - key, - value.methodHnd, - value.contextHandle, - SpmiDumpHelper::DumpAgnostic_CORINFO_LOOKUP(value.instArg).c_str()); -} -CORINFO_METHOD_HANDLE MethodContext::repGetAwaitReturnCall(CORINFO_METHOD_HANDLE callerHnd, CORINFO_CONTEXT_HANDLE* contextHandle, CORINFO_LOOKUP* instArg) -{ - const Agnostic_GetAwaitReturnCallResult& result = LookupByKeyOrMissNoMessage(GetAwaitReturnCall, CastHandle(callerHnd)); - *contextHandle = (CORINFO_CONTEXT_HANDLE)result.contextHandle; - *instArg = SpmiRecordsHelper::RestoreCORINFO_LOOKUP(result.instArg); - return (CORINFO_METHOD_HANDLE)result.methodHnd; -} - -void MethodContext::recGetAwaitAwaiterInContinuationCall(CORINFO_METHOD_HANDLE callerHnd, - CORINFO_RESOLVED_TOKEN* pResolvedToken, - bool isUnsafe, - CORINFO_CONTEXT_HANDLE* contextHandle, - CORINFO_LOOKUP* instArg, - CORINFO_METHOD_HANDLE methHnd) -{ - if (GetAwaitAwaiterInContinuationCall == nullptr) - { - GetAwaitAwaiterInContinuationCall = - new LightWeightMap(); - } - - Agnostic_GetAwaitAwaiterInContinuationCall key; - ZeroMemory(&key, sizeof(key)); - key.callerHnd = CastHandle(callerHnd); - key.ResolvedToken = - SpmiRecordsHelper::StoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, GetAwaitAwaiterInContinuationCall); - key.isUnsafe = isUnsafe; - - Agnostic_GetAwaitReturnCallResult value; - ZeroMemory(&value, sizeof(value)); - value.methodHnd = CastHandle(methHnd); - value.contextHandle = CastHandle(*contextHandle); - value.instArg = SpmiRecordsHelper::StoreAgnostic_CORINFO_LOOKUP(instArg); - - GetAwaitAwaiterInContinuationCall->Add(key, value); - DEBUG_REC(dmpGetAwaitAwaiterInContinuationCall(key, value)); -} - -void MethodContext::dmpGetAwaitAwaiterInContinuationCall( - const Agnostic_GetAwaitAwaiterInContinuationCall& key, - Agnostic_GetAwaitReturnCallResult& value) -{ - printf("GetAwaitAwaiterInContinuationCall caller-%016" PRIX64 " rt{%s} unsafe-%u " - "methodHnd-%016" PRIX64 " contextHandle-%016" PRIX64 " instArg %s", - key.callerHnd, - SpmiDumpHelper::DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.ResolvedToken).c_str(), - key.isUnsafe, - value.methodHnd, - value.contextHandle, - SpmiDumpHelper::DumpAgnostic_CORINFO_LOOKUP(value.instArg).c_str()); -} - -CORINFO_METHOD_HANDLE MethodContext::repGetAwaitAwaiterInContinuationCall( - CORINFO_METHOD_HANDLE callerHnd, - CORINFO_RESOLVED_TOKEN* pResolvedToken, - bool isUnsafe, - CORINFO_CONTEXT_HANDLE* contextHandle, - CORINFO_LOOKUP* instArg) -{ - Agnostic_GetAwaitAwaiterInContinuationCall key; - ZeroMemory(&key, sizeof(key)); - key.callerHnd = CastHandle(callerHnd); - key.ResolvedToken = - SpmiRecordsHelper::RestoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, GetAwaitAwaiterInContinuationCall); - key.isUnsafe = isUnsafe; - - Agnostic_GetAwaitReturnCallResult value = - LookupByKeyOrMissNoMessage(GetAwaitAwaiterInContinuationCall, key); - DEBUG_REP(dmpGetAwaitAwaiterInContinuationCall(key, value)); - *contextHandle = (CORINFO_CONTEXT_HANDLE)value.contextHandle; - *instArg = SpmiRecordsHelper::RestoreCORINFO_LOOKUP(value.instArg); - return (CORINFO_METHOD_HANDLE)value.methodHnd; -} - -void MethodContext::recGetGSCookie(GSCookie* pCookieVal, GSCookie** ppCookieVal) -{ - if (GetGSCookie == nullptr) - GetGSCookie = new LightWeightMap(); - - DLDL value; - - if (pCookieVal != nullptr) - value.A = (DWORDLONG)*pCookieVal; - else - value.A = 0; - - if (ppCookieVal != nullptr) - value.B = CastPointer(*ppCookieVal); - else - value.B = 0; - - GetGSCookie->Add(0, value); - DEBUG_REC(dmpGetGSCookie(0, value)); -} -void MethodContext::dmpGetGSCookie(DWORD key, DLDL value) -{ - printf("GetGSCookie key 0, value pCookieVal-%016" PRIX64 " ppCookieVal-%016" PRIX64 "", value.A, value.B); -} -void MethodContext::repGetGSCookie(GSCookie* pCookieVal, GSCookie** ppCookieVal) -{ - if (GetGSCookie == nullptr) - { - // fake the result because for the codegen it is just a constant. - if (pCookieVal != nullptr) - { - *pCookieVal = (GSCookie)0x06000000; - } - if (ppCookieVal != nullptr) - { - *ppCookieVal = (GSCookie*)0x06000001; - } - return; - } - - DLDL value = LookupByKeyOrMissNoMessage(GetGSCookie, 0); - - DEBUG_REP(dmpGetGSCookie(0, value)); - - if (pCookieVal != nullptr) - *pCookieVal = (GSCookie)value.A; - if (ppCookieVal != nullptr) - *ppCookieVal = (GSCookie*)value.B; -} - -void MethodContext::recGetOSRInfo(PatchpointInfo* patchpointInfo, unsigned* ilOffset) -{ - if (GetOSRInfo == nullptr) - { - GetOSRInfo = new LightWeightMap(); - } - - Agnostic_GetOSRInfo value; - - value.index = (DWORD)GetOSRInfo->AddBuffer((const unsigned char*) patchpointInfo, patchpointInfo->PatchpointInfoSize()); - value.ilOffset = *ilOffset; - - // use 0 for key - DWORD key = 0; - GetOSRInfo->Add(key, value); - DEBUG_REC(dmpGetOSRInfo(key, value)); -} - -void MethodContext::dmpGetOSRInfo(DWORD key, const Agnostic_GetOSRInfo& value) -{ - // todo - dump patchpoint info? - printf("GetOSRInfo key %u, value patchpointInfo-%u {...} iloffset-%u\n", - key, value.index, value.ilOffset); -} - -PatchpointInfo* MethodContext::repGetOSRInfo(unsigned* ilOffset) -{ - DWORD key = 0; - - Agnostic_GetOSRInfo value = LookupByKeyOrMissNoMessage(GetOSRInfo, key); - - DEBUG_REP(dmpGetOSRInfo(key, value)); - - *ilOffset = value.ilOffset; - return (PatchpointInfo*)GetOSRInfo->GetBuffer(value.index); -} - -void MethodContext::recGetClassModuleIdForStatics(CORINFO_CLASS_HANDLE cls, - CORINFO_MODULE_HANDLE* pModule, - void** ppIndirection, - size_t result) -{ - if (GetClassModuleIdForStatics == nullptr) - GetClassModuleIdForStatics = new LightWeightMap(); - - Agnostic_GetClassModuleIdForStatics value; - - if (pModule != nullptr) - value.Module = CastHandle(*pModule); - else - value.Module = 0; - if (ppIndirection != nullptr) - value.pIndirection = CastPointer(*ppIndirection); - else - value.pIndirection = 0; - value.result = (DWORDLONG)result; - - DWORDLONG key = CastHandle(cls); - GetClassModuleIdForStatics->Add(key, value); - DEBUG_REC(dmpGetClassModuleIdForStatics(key, value)); -} -void MethodContext::dmpGetClassModuleIdForStatics(DWORDLONG key, const Agnostic_GetClassModuleIdForStatics& value) -{ - printf("GetClassModuleIdForStatics key cls-%016" PRIX64 ", value mod-%016" PRIX64 " pp-%016" PRIX64 " res-%016" PRIX64 "", key, value.Module, - value.pIndirection, value.result); -} -size_t MethodContext::repGetClassModuleIdForStatics(CORINFO_CLASS_HANDLE cls, - CORINFO_MODULE_HANDLE* pModule, - void** ppIndirection) -{ - DWORDLONG key = CastHandle(cls); - Agnostic_GetClassModuleIdForStatics value = LookupByKeyOrMiss(GetClassModuleIdForStatics, key, ": key %016" PRIX64 "", key); - - DEBUG_REP(dmpGetClassModuleIdForStatics(key, value)); - - if (pModule != nullptr) - *pModule = (CORINFO_MODULE_HANDLE)value.Module; - if (ppIndirection != nullptr) - *ppIndirection = (void*)value.pIndirection; - return (size_t)value.result; -} - -void MethodContext::recGetIsClassInitedFlagAddress(CORINFO_CLASS_HANDLE cls, CORINFO_CONST_LOOKUP* addr, int* offset, bool result) -{ - if (GetIsClassInitedFlagAddress == nullptr) - GetIsClassInitedFlagAddress = new LightWeightMap(); - - Agnostic_GetIsClassInitedFlagAddress value; - value.addr.handle = CastHandle(addr->addr); - value.addr.accessType = (DWORD)addr->accessType; - value.offset = (DWORD)*offset; - value.result = (DWORD)result; - - DWORDLONG key = CastHandle(cls); - GetIsClassInitedFlagAddress->Add(key, value); - DEBUG_REC(dmpGetIsClassInitedFlagAddress(key, value)); -} -void MethodContext::dmpGetIsClassInitedFlagAddress(DWORDLONG key, const Agnostic_GetIsClassInitedFlagAddress& value) -{ - printf("GetIsClassInitedFlagAddress key hnd-%016" PRIX64 ", value addr-%016" PRIX64 ", result-%u", key, value.addr.handle, value.result); -} -bool MethodContext::repGetIsClassInitedFlagAddress(CORINFO_CLASS_HANDLE cls, CORINFO_CONST_LOOKUP* addr, int* offset) -{ - DWORDLONG key = CastHandle(cls); - Agnostic_GetIsClassInitedFlagAddress value = LookupByKeyOrMiss(GetIsClassInitedFlagAddress, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetIsClassInitedFlagAddress(key, value)); - - *offset = (int)value.offset; - addr->accessType = (InfoAccessType)value.addr.accessType; - addr->addr = (void*)value.addr.handle; - return (bool)value.result; -} - -void MethodContext::recGetStaticBaseAddress(CORINFO_CLASS_HANDLE cls, bool isGc, CORINFO_CONST_LOOKUP* addr, bool result) -{ - if (GetStaticBaseAddress == nullptr) - GetStaticBaseAddress = new LightWeightMap(); - - Agnostic_GetStaticBaseAddress value; - value.addr.handle = CastHandle(addr->addr); - value.addr.accessType = (DWORD)addr->accessType; - value.result = (DWORDLONG)result; - - DLD key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(cls); - key.B = (DWORD)isGc; - - GetStaticBaseAddress->Add(key, value); - DEBUG_REC(dmpGetStaticBaseAddress(key, value)); -} -void MethodContext::dmpGetStaticBaseAddress(DLD key, const Agnostic_GetStaticBaseAddress& value) -{ - printf("GetStaticBaseAddress key hnd-%016" PRIX64 ", value addr-%016" PRIX64 ", result-%u", key.A, value.addr.handle, value.result); -} -bool MethodContext::repGetStaticBaseAddress(CORINFO_CLASS_HANDLE cls, bool isGc, CORINFO_CONST_LOOKUP* addr) -{ - DLD key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(cls); - key.B = (DWORD)isGc; - - Agnostic_GetStaticBaseAddress value = LookupByKeyOrMiss(GetStaticBaseAddress, key, ": key %016" PRIX64 "", key.A); - DEBUG_REP(dmpGetStaticBaseAddress(key, value)); - - addr->accessType = (InfoAccessType)value.addr.accessType; - addr->addr = (void*)value.addr.handle; - return (bool)value.result; -} - -void MethodContext::recGetThreadTLSIndex(void** ppIndirection, DWORD result) -{ - if (GetThreadTLSIndex == nullptr) - GetThreadTLSIndex = new LightWeightMap(); - - DLD value; - - if (ppIndirection != nullptr) - value.A = CastPointer(*ppIndirection); - else - value.A = 0; - value.B = (DWORD)result; - - GetThreadTLSIndex->Add(0, value); -} -void MethodContext::dmpGetThreadTLSIndex(DWORD key, DLD value) -{ - printf("GetThreadTLSIndex key 0, value ppIndirection-%016" PRIX64 " result-%08X", value.A, value.B); -} -DWORD MethodContext::repGetThreadTLSIndex(void** ppIndirection) -{ - DLD value = LookupByKeyOrMissNoMessage(GetThreadTLSIndex, 0); - - DEBUG_REP(dmpGetThreadTLSIndex(0, value)); - - if (ppIndirection != nullptr) - *ppIndirection = (void*)value.A; - return (DWORD)value.B; -} - -void MethodContext::recGetAddrOfCaptureThreadGlobal(void** ppIndirection, int32_t* result) -{ - if (GetAddrOfCaptureThreadGlobal == nullptr) - GetAddrOfCaptureThreadGlobal = new LightWeightMap(); - - DLDL value; - - if (ppIndirection != nullptr) - value.A = CastPointer(*ppIndirection); - else - value.A = 0; - value.B = CastPointer(result); - - GetAddrOfCaptureThreadGlobal->Add(0, value); - DEBUG_REC(dmpGetAddrOfCaptureThreadGlobal(0, value)); -} -void MethodContext::dmpGetAddrOfCaptureThreadGlobal(DWORD key, DLDL value) -{ - printf("GetAddrOfCaptureThreadGlobal key %u, value ppi-%016" PRIX64 " res-%016" PRIX64 "", key, value.A, value.B); -} -int32_t* MethodContext::repGetAddrOfCaptureThreadGlobal(void** ppIndirection) -{ - if ((GetAddrOfCaptureThreadGlobal == nullptr) || (GetAddrOfCaptureThreadGlobal->GetIndex((DWORD)0) == -1)) - { -#ifdef sparseMC - LogDebug("Sparse - repGetAddrOfCaptureThreadGlobal returning nullptr and 0xCAFE0001"); - if (ppIndirection != nullptr) - *ppIndirection = nullptr; - return (int32_t*)(size_t)0xCAFE0001; -#else - LogException(EXCEPTIONCODE_MC, "Didn't find anything for GetAddrOfCaptureThreadGlobal", ""); -#endif - } - - DLDL value = GetAddrOfCaptureThreadGlobal->Get(0); - DEBUG_REP(dmpGetAddrOfCaptureThreadGlobal(0, value)); - - if (ppIndirection != nullptr) - *ppIndirection = (void*)value.A; - return (int32_t*)value.B; -} - -void MethodContext::recGetClassStaticDynamicInfo(CORINFO_CLASS_HANDLE cls, void* result) -{ - if (GetClassStaticDynamicInfo == nullptr) - GetClassStaticDynamicInfo = new LightWeightMap(); - - DLD value; - - value.A = CastPointer(result); - value.B = 0; - - DWORDLONG key = CastHandle(cls); - GetClassStaticDynamicInfo->Add(key, value); - DEBUG_REC(dmpGetClassStaticDynamicInfo(key, value)); -} -void MethodContext::dmpGetClassStaticDynamicInfo(DWORDLONG key, DLD value) -{ - printf("GetClassStaticDynamicInfo key cls-%016" PRIX64 ", value pp-%016" PRIX64 " res-%u", key, value.A, value.B); -} -void* MethodContext::repGetClassStaticDynamicInfo(CORINFO_CLASS_HANDLE cls) -{ - DWORDLONG key = CastHandle(cls); - DLD value = LookupByKeyOrMiss(GetClassStaticDynamicInfo, key, ": key %016" PRIX64 "", key); - - DEBUG_REP(dmpGetClassStaticDynamicInfo(key, value)); - - return (void*)value.A; -} - -void MethodContext::recGetClassThreadStaticDynamicInfo(CORINFO_CLASS_HANDLE cls, void* result) -{ - if (GetClassThreadStaticDynamicInfo == nullptr) - GetClassThreadStaticDynamicInfo = new LightWeightMap(); - - DLD value; - - value.A = CastPointer(result); - value.B = 0; - - DWORDLONG key = CastHandle(cls); - GetClassThreadStaticDynamicInfo->Add(key, value); - DEBUG_REC(dmpGetClassThreadStaticDynamicInfo(key, value)); -} -void MethodContext::dmpGetClassThreadStaticDynamicInfo(DWORDLONG key, DLD value) -{ - printf("GetClassThreadStaticDynamicInfo key cls-%016" PRIX64 ", value pp-%016" PRIX64 " res-%u", key, value.A, value.B); -} -void* MethodContext::repGetClassThreadStaticDynamicInfo(CORINFO_CLASS_HANDLE cls) -{ - DWORDLONG key = CastHandle(cls); - DLD value = LookupByKeyOrMiss(GetClassThreadStaticDynamicInfo, key, ": key %016" PRIX64 "", key); - - DEBUG_REP(dmpGetClassThreadStaticDynamicInfo(key, value)); - - return (void*)value.A; -} - -void MethodContext::recGetLocationOfThisType(CORINFO_METHOD_HANDLE context, CORINFO_LOOKUP_KIND* result) -{ - if (GetLocationOfThisType == nullptr) - GetLocationOfThisType = new LightWeightMap(); - - Agnostic_CORINFO_LOOKUP_KIND value = SpmiRecordsHelper::CreateAgnostic_CORINFO_LOOKUP_KIND(result); - - DWORDLONG key = CastHandle(context); - GetLocationOfThisType->Add(key, value); - DEBUG_REC(dmpGetLocationOfThisType(key, value)); -} -void MethodContext::dmpGetLocationOfThisType(DWORDLONG key, const Agnostic_CORINFO_LOOKUP_KIND& value) -{ - printf("GetLocationOfThisType key ftn-%016" PRIX64 ", value %s", key, - SpmiDumpHelper::DumpAgnostic_CORINFO_LOOKUP_KIND(value).c_str()); -} -void MethodContext::repGetLocationOfThisType(CORINFO_METHOD_HANDLE context, CORINFO_LOOKUP_KIND* pLookupKind) -{ - DWORDLONG key = CastHandle(context); - Agnostic_CORINFO_LOOKUP_KIND value = LookupByKeyOrMiss(GetLocationOfThisType, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetLocationOfThisType(key, value)); - *pLookupKind = SpmiRecordsHelper::RestoreCORINFO_LOOKUP_KIND(value); -} - -void MethodContext::recGetDelegateCtor(CORINFO_METHOD_HANDLE methHnd, - CORINFO_CLASS_HANDLE clsHnd, - CORINFO_METHOD_HANDLE targetMethodHnd, - DelegateCtorArgs* pCtorData, - CORINFO_METHOD_HANDLE result) -{ - if (GetDelegateCtor == nullptr) - GetDelegateCtor = new LightWeightMap(); - - Agnostic_GetDelegateCtorIn key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.methHnd = CastHandle(methHnd); - key.clsHnd = CastHandle(clsHnd); - key.targetMethodHnd = CastHandle(targetMethodHnd); - - Agnostic_GetDelegateCtorOut value; - value.CtorData.pMethod = CastPointer(pCtorData->pMethod); - value.CtorData.pArg3 = CastPointer(pCtorData->pArg3); - value.CtorData.pArg4 = CastPointer(pCtorData->pArg4); - value.CtorData.pArg5 = CastPointer(pCtorData->pArg5); - value.result = CastHandle(result); - - GetDelegateCtor->Add(key, value); - DEBUG_REC(dmpGetDelegateCtor(key, value)); -} -void MethodContext::dmpGetDelegateCtor(const Agnostic_GetDelegateCtorIn& key, const Agnostic_GetDelegateCtorOut& value) -{ - printf("GetDelegateCtor key ftn-%016" PRIX64 " cls-%016" PRIX64 " tftn-%016" PRIX64 ", value pm-%016" PRIX64 " a3-%016" PRIX64 " a4-%016" PRIX64 " " - "a5-%016" PRIX64 " res-%016" PRIX64 "", - key.methHnd, key.clsHnd, key.targetMethodHnd, value.CtorData.pMethod, value.CtorData.pArg3, - value.CtorData.pArg4, value.CtorData.pArg5, value.result); -} -CORINFO_METHOD_HANDLE MethodContext::repGetDelegateCtor(CORINFO_METHOD_HANDLE methHnd, - CORINFO_CLASS_HANDLE clsHnd, - CORINFO_METHOD_HANDLE targetMethodHnd, - DelegateCtorArgs* pCtorData) -{ - Agnostic_GetDelegateCtorIn key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.methHnd = CastHandle(methHnd); - key.clsHnd = CastHandle(clsHnd); - key.targetMethodHnd = CastHandle(targetMethodHnd); - - Agnostic_GetDelegateCtorOut value = LookupByKeyOrMiss(GetDelegateCtor, key, ": key %016" PRIX64 "", key.methHnd); - - DEBUG_REP(dmpGetDelegateCtor(key, value)); - - pCtorData->pMethod = (void*)value.CtorData.pMethod; - pCtorData->pArg3 = (void*)value.CtorData.pArg3; - pCtorData->pArg4 = (void*)value.CtorData.pArg4; - pCtorData->pArg5 = (void*)value.CtorData.pArg5; - return (CORINFO_METHOD_HANDLE)value.result; -} - -void MethodContext::recGetFunctionFixedEntryPoint(CORINFO_METHOD_HANDLE ftn, CORINFO_CONST_LOOKUP* pResult) -{ - if (GetFunctionFixedEntryPoint == nullptr) - GetFunctionFixedEntryPoint = new LightWeightMap(); - - Agnostic_CORINFO_CONST_LOOKUP value = SpmiRecordsHelper::StoreAgnostic_CORINFO_CONST_LOOKUP(pResult); - - DWORDLONG key = CastHandle(ftn); - GetFunctionFixedEntryPoint->Add(key, value); - DEBUG_REC(dmpGetFunctionFixedEntryPoint(key, value)); -} -void MethodContext::dmpGetFunctionFixedEntryPoint(DWORDLONG key, const Agnostic_CORINFO_CONST_LOOKUP& value) -{ - printf("GetFunctionFixedEntryPoint key ftn-%016" PRIX64 ", value %s", key, - SpmiDumpHelper::DumpAgnostic_CORINFO_CONST_LOOKUP(value).c_str()); -} -void MethodContext::repGetFunctionFixedEntryPoint(CORINFO_METHOD_HANDLE ftn, bool isUnsafeFunctionPointer, CORINFO_CONST_LOOKUP* pResult) -{ - // The isUnsafeFunctionPointer has no impact on the resulting value. - // It helps produce side-effects in the runtime only. - DWORDLONG key = CastHandle(ftn); - Agnostic_CORINFO_CONST_LOOKUP value = LookupByKeyOrMiss(GetFunctionFixedEntryPoint, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetFunctionFixedEntryPoint(key, value)); - *pResult = SpmiRecordsHelper::RestoreCORINFO_CONST_LOOKUP(value); -} - -void MethodContext::recGetFieldInClass(CORINFO_CLASS_HANDLE clsHnd, INT num, CORINFO_FIELD_HANDLE result) -{ - if (GetFieldInClass == nullptr) - GetFieldInClass = new LightWeightMap(); - - DLD key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(clsHnd); - key.B = (DWORD)num; - - DWORDLONG value = CastHandle(result); - GetFieldInClass->Add(key, value); - DEBUG_REC(dmpGetFieldInClass(key, value)); -} -void MethodContext::dmpGetFieldInClass(DLD key, DWORDLONG value) -{ - printf("GetFieldInClass key cls-%016" PRIX64 " ind-%u, value %016" PRIX64 "", key.A, key.B, value); -} -CORINFO_FIELD_HANDLE MethodContext::repGetFieldInClass(CORINFO_CLASS_HANDLE clsHnd, INT num) -{ - DLD key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(clsHnd); - key.B = (DWORD)num; - - DWORDLONG value = LookupByKeyOrMiss(GetFieldInClass, key, ": key %016" PRIX64 "", key.A); - - DEBUG_REP(dmpGetFieldInClass(key, value)); - CORINFO_FIELD_HANDLE result = (CORINFO_FIELD_HANDLE)value; - return result; -} - -void MethodContext::recGetTypeLayout(GetTypeLayoutResult result, CORINFO_CLASS_HANDLE typeHnd, CORINFO_TYPE_LAYOUT_NODE* nodes, size_t numNodes) -{ - if (GetTypeLayout == nullptr) - GetTypeLayout = new LightWeightMap(); - - DWORDLONG key = CastHandle(typeHnd); - - int index = GetTypeLayout->GetIndex(key); - if (index != -1) - { - // If we already have this then just skip. - Agnostic_GetTypeLayoutResult existing = GetTypeLayout->GetItem(index); - if ((existing.result != (DWORD)GetTypeLayoutResult::Partial) || - (result == GetTypeLayoutResult::Failure) || - (numNodes <= existing.numNodes)) - { - // No new data to add - return; - } - - // Otherwise fall through and update the map with more information. - } - - Agnostic_GetTypeLayoutResult value; - ZeroMemory(&value, sizeof(value)); - - value.result = (DWORD)result; - if (result == GetTypeLayoutResult::Failure) - { - value.nodesBuffer = UINT_MAX; - } - else - { - Agnostic_CORINFO_TYPE_LAYOUT_NODE* agnosticFields = new Agnostic_CORINFO_TYPE_LAYOUT_NODE[numNodes]; - for (size_t i = 0; i < numNodes; i++) - { - agnosticFields[i] = SpmiRecordsHelper::StoreAgnostic_CORINFO_TYPE_LAYOUT_NODE(nodes[i]); - } - - value.nodesBuffer = GetTypeLayout->AddBuffer((unsigned char*)agnosticFields, (unsigned int)(sizeof(Agnostic_CORINFO_TYPE_LAYOUT_NODE) * numNodes)); - value.numNodes = (DWORD)numNodes; - - delete[] agnosticFields; - } - - if (index != -1) - { - GetTypeLayout->Update(index, value); - } - else - { - GetTypeLayout->Add(key, value); - } -} -void MethodContext::dmpGetTypeLayout(DWORDLONG key, const Agnostic_GetTypeLayoutResult& value) -{ - printf("GetTypeLayout key type-%016" PRIX64 " value result=%d numNodes=%d", key, (DWORD)value.result, value.numNodes); - if (value.numNodes > 0) - { - Agnostic_CORINFO_TYPE_LAYOUT_NODE* nodes = reinterpret_cast(GetTypeLayout->GetBuffer(value.nodesBuffer)); - size_t index = 0; - dmpTypeLayoutTree(nodes, value.numNodes, &index, 1); - } -} -void MethodContext::dmpTypeLayoutTree(const Agnostic_CORINFO_TYPE_LAYOUT_NODE* nodes, size_t maxNodes, size_t* index, size_t indent) -{ - for (size_t i = 0; i < indent; i++) - { - printf(" "); - } - - const Agnostic_CORINFO_TYPE_LAYOUT_NODE* node = &nodes[*index]; - printf("%zu: parent %u offset %u size %u type %s numFields %u hasSignificantPadding %s simdTypeHnd %016" PRIX64 " diagFieldHnd %016" PRIX64, - *index, - node->parent, - node->offset, - node->size, - toString((CorInfoType)node->type), - node->numFields, - node->hasSignificantPadding ? "yes" : "no", - node->simdTypeHnd, - node->diagFieldHnd); - - (*index)++; - for (size_t i = 0; i < node->numFields; i++) - { - if (i >= maxNodes) - break; - - dmpTypeLayoutTree(nodes, maxNodes, index, indent + 1); - } -} -GetTypeLayoutResult MethodContext::repGetTypeLayout(CORINFO_CLASS_HANDLE typeHnd, CORINFO_TYPE_LAYOUT_NODE* nodes, size_t* numNodes) -{ - DWORDLONG key = CastHandle(typeHnd); - Agnostic_GetTypeLayoutResult value = LookupByKeyOrMiss(GetTypeLayout, key, ": key type-%016" PRIX64, key); - - GetTypeLayoutResult result = (GetTypeLayoutResult)value.result; - if (result == GetTypeLayoutResult::Failure) - { - return result; - } - - Agnostic_CORINFO_TYPE_LAYOUT_NODE* valueFields = (Agnostic_CORINFO_TYPE_LAYOUT_NODE*)GetTypeLayout->GetBuffer(value.nodesBuffer); - size_t nodesToWrite = min((size_t)value.numNodes, *numNodes); - for (size_t i = 0; i < nodesToWrite; i++) - { - nodes[i] = SpmiRecordsHelper::RestoreCORINFO_TYPE_LAYOUT_NODE(valueFields[i]); - } - - *numNodes = nodesToWrite; - return (result == GetTypeLayoutResult::Partial) || (value.numNodes > *numNodes) ? GetTypeLayoutResult::Partial : GetTypeLayoutResult::Success; -} - -void MethodContext::recGetFieldType(CORINFO_FIELD_HANDLE field, - CORINFO_CLASS_HANDLE* structType, - CORINFO_CLASS_HANDLE fieldOwnerHint, - CorInfoType result) -{ - if (GetFieldType == nullptr) - GetFieldType = new LightWeightMap(); - - DLDL key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(field); - key.B = CastHandle(fieldOwnerHint); - - DLD value; - value.B = (DWORD)result; - if (structType == nullptr) - { - value.A = 0; - } - else - { - value.A = CastHandle(*structType); - - // If we had a previous call with null 'structType', we will not have captured the - // class handle (we use only 'field' and 'fieldOwnerHint' as keys). - // Update the value in that case. - unsigned index = GetFieldType->GetIndex(key); - if ((index != (unsigned)-1) && (GetFieldType->GetItem(index).A == 0)) - { - GetFieldType->Update(index, value); - DEBUG_REC(dmpGetFieldType(key, value)); - return; - } - } - GetFieldType->Add(key, value); - DEBUG_REC(dmpGetFieldType(key, value)); -} -void MethodContext::dmpGetFieldType(DLDL key, DLD value) -{ - printf("GetFieldType key fld-%016" PRIX64 " cls-%016" PRIX64 ", value ch-%016" PRIX64 " cit-%u(%s)", key.A, key.B, value.A, value.B, - toString((CorInfoType)value.B)); -} -CorInfoType MethodContext::repGetFieldType(CORINFO_FIELD_HANDLE field, - CORINFO_CLASS_HANDLE* structType, - CORINFO_CLASS_HANDLE fieldOwnerHint) -{ - DLDL key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(field); - key.B = CastHandle(fieldOwnerHint); - - DLD value = LookupByKeyOrMiss(GetFieldType, key, ": key %016" PRIX64 "", key.A); - - DEBUG_REP(dmpGetFieldType(key, value)); - - if (structType != nullptr) - *structType = (CORINFO_CLASS_HANDLE)value.A; - return (CorInfoType)value.B; -} - -void MethodContext::recSatisfiesMethodConstraints(CORINFO_CLASS_HANDLE parent, - CORINFO_METHOD_HANDLE method, - bool result) -{ - if (SatisfiesMethodConstraints == nullptr) - SatisfiesMethodConstraints = new LightWeightMap(); - - DLDL key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(parent); - key.B = CastHandle(method); - - DWORD value = result ? 1 : 0; - SatisfiesMethodConstraints->Add(key, value); - DEBUG_REC(dmpSatisfiesMethodConstraints(key, value)); -} -void MethodContext::dmpSatisfiesMethodConstraints(DLDL key, DWORD value) -{ - printf("SatisfiesMethodConstraints key cls-%016" PRIX64 " ftn-%016" PRIX64 ", value res-%u", key.A, key.B, value); -} -bool MethodContext::repSatisfiesMethodConstraints(CORINFO_CLASS_HANDLE parent, CORINFO_METHOD_HANDLE method) -{ - DLDL key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(parent); - key.B = CastHandle(method); - - DWORD value = LookupByKeyOrMissNoMessage(SatisfiesMethodConstraints, key); - - DEBUG_REP(dmpSatisfiesMethodConstraints(key, value)); - return value != 0; -} - -void MethodContext::recGetStringLiteral(CORINFO_MODULE_HANDLE module, unsigned metaTOK, char16_t* buffer, int bufferSize, int startIndex, int length) -{ - if (GetStringLiteral == nullptr) - GetStringLiteral = new LightWeightMap(); - - DLDDD key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(module); - key.B = (DWORD)metaTOK; - key.C = (DWORD)bufferSize; - key.D = (DWORD)startIndex; - - DWORD strBuf = (DWORD)-1; - if (buffer != nullptr && length != -1) - { - int bufferRealSize = min(length, bufferSize) * sizeof(char16_t); - strBuf = (DWORD)GetStringLiteral->AddBuffer((unsigned char*)buffer, (unsigned int)bufferRealSize); - } - - DD value; - value.A = (DWORD)length; - value.B = (DWORD)strBuf; - - GetStringLiteral->Add(key, value); - DEBUG_REC(dmpGetStringLiteral(key, value)); -} - -void MethodContext::dmpGetStringLiteral(DLDDD key, DD value) -{ - printf("GetStringLiteral key mod-%016" PRIX64 " tok-%08X, bufSize-%u, startIndex-%u, len-%u", key.A, key.B, key.C, key.D, value.A); - GetStringLiteral->Unlock(); -} - -int MethodContext::repGetStringLiteral(CORINFO_MODULE_HANDLE module, unsigned metaTOK, char16_t* buffer, int bufferSize, int startIndex) -{ - DLDDD key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(module); - key.B = (DWORD)metaTOK; - key.C = (DWORD)bufferSize; - key.D = (DWORD)startIndex; - - DD value = LookupByKeyOrMiss(GetStringLiteral, key, ": key handle-%016" PRIX64 " token-%X bufferSize-%d startIndex-%d", key.A, key.B, key.C, key.D); - - DEBUG_REP(dmpGetStringLiteral(key, value)); - int srcBufferLength = (int)value.A; - if (buffer != nullptr && srcBufferLength > 0) - { - char16_t* srcBuffer = (char16_t*)GetStringLiteral->GetBuffer(value.B); - Assert(srcBuffer != nullptr); - memcpy(buffer, srcBuffer, min(srcBufferLength, bufferSize) * sizeof(char16_t)); - } - return srcBufferLength; -} - -void MethodContext::recCanCast(CORINFO_CLASS_HANDLE child, CORINFO_CLASS_HANDLE parent, bool result) -{ - if (CanCast == nullptr) - CanCast = new LightWeightMap(); - - DLDL key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(child); - key.B = CastHandle(parent); - - DWORD value = result ? 1 : 0; - CanCast->Add(key, value); - DEBUG_REC(dmpCanCast(key, value)); -} -void MethodContext::dmpCanCast(DLDL key, DWORD value) -{ - printf("CanCast key chd-%016" PRIX64 " par-%016" PRIX64 ", value res-%u", key.A, key.B, value); -} -bool MethodContext::repCanCast(CORINFO_CLASS_HANDLE child, CORINFO_CLASS_HANDLE parent) -{ - DLDL key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(child); - key.B = CastHandle(parent); - - DWORD value = LookupByKeyOrMiss(CanCast, key, ": key %016" PRIX64 " %016" PRIX64 "", key.A, key.B); - - DEBUG_REP(dmpCanCast(key, value)); - return value != 0; -} - -void MethodContext::recGetChildType(CORINFO_CLASS_HANDLE clsHnd, CORINFO_CLASS_HANDLE* clsRet, CorInfoType result) -{ - if (GetChildType == nullptr) - GetChildType = new LightWeightMap(); - - DLD value; - value.A = CastHandle(*clsRet); - value.B = (DWORD)result; - - DWORDLONG key = CastHandle(clsHnd); - GetChildType->Add(key, value); - DEBUG_REC(dmpGetChildType(key, value)); -} -void MethodContext::dmpGetChildType(DWORDLONG key, DLD value) -{ - printf("GetChildType key cls-%016" PRIX64 ", value clsr-%016" PRIX64 " cit-%u(%s)", key, value.A, value.B, - toString((CorInfoType)value.B)); -} -CorInfoType MethodContext::repGetChildType(CORINFO_CLASS_HANDLE clsHnd, CORINFO_CLASS_HANDLE* clsRet) -{ - DWORDLONG key = CastHandle(clsHnd); - DLD value = LookupByKeyOrMiss(GetChildType, key, ": key %016" PRIX64 "", key); - - DEBUG_REP(dmpGetChildType(key, value)); - - *clsRet = (CORINFO_CLASS_HANDLE)value.A; - return (CorInfoType)value.B; -} - -void MethodContext::recGetArrayInitializationData(CORINFO_FIELD_HANDLE field, DWORD size, void* result) -{ - if (GetArrayInitializationData == nullptr) - GetArrayInitializationData = new LightWeightMap(); - - DLD key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(field); - key.B = (DWORD)size; - - DWORDLONG value = CastPointer(result); - GetArrayInitializationData->Add(key, value); - DEBUG_REC(dmpGetArrayInitializationData(key, value)); -} -void MethodContext::dmpGetArrayInitializationData(DLD key, DWORDLONG value) -{ - printf("GetArrayInitializationData key field-%016" PRIX64 " size-%08X, value result-%016" PRIX64 "", key.A, key.B, value); -} -void* MethodContext::repGetArrayInitializationData(CORINFO_FIELD_HANDLE field, DWORD size) -{ - DLD key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(field); - key.B = (DWORD)size; - - DWORDLONG value = LookupByKeyOrMissNoMessage(GetArrayInitializationData, key); - - DEBUG_REP(dmpGetArrayInitializationData(key, value)); - void* result = (void*)value; - return result; -} - -void MethodContext::recGetAddressOfPInvokeTarget(CORINFO_METHOD_HANDLE method, CORINFO_CONST_LOOKUP* pLookup) -{ - if (GetAddressOfPInvokeTarget == nullptr) - GetAddressOfPInvokeTarget = new LightWeightMap(); - - DLD value; - value.A = CastPointer(pLookup->addr); - value.B = (DWORD)pLookup->accessType; - - DWORDLONG key = CastHandle(method); - GetAddressOfPInvokeTarget->Add(key, value); - DEBUG_REC(dmpGetAddressOfPInvokeTarget(key, value)); -} -void MethodContext::dmpGetAddressOfPInvokeTarget(DWORDLONG key, DLD value) -{ - printf("GetAddressOfPInvokeTarget key ftn-%016" PRIX64 ", value addr-%016" PRIX64 " at-%u", key, value.A, value.B); -} -void MethodContext::repGetAddressOfPInvokeTarget(CORINFO_METHOD_HANDLE method, CORINFO_CONST_LOOKUP* pLookup) -{ - DWORDLONG key = CastHandle(method); - DLD value = LookupByKeyOrMiss(GetAddressOfPInvokeTarget, key, ": key %016" PRIX64 "", key); - - DEBUG_REP(dmpGetAddressOfPInvokeTarget(key, value)); - - pLookup->addr = (void*)value.A; - pLookup->accessType = (InfoAccessType)value.B; -} - -void MethodContext::recGetMethodHash(CORINFO_METHOD_HANDLE ftn, unsigned result) -{ - if (GetMethodHash == nullptr) - GetMethodHash = new LightWeightMap(); - - DWORDLONG key = CastHandle(ftn); - DWORD value = (DWORD)result; - GetMethodHash->Add(key, value); - DEBUG_REC(dmpGetMethodHash(key, value)); -} -void MethodContext::dmpGetMethodHash(DWORDLONG key, DWORD value) -{ - printf("GetMethodHash key %016" PRIX64 ", value %u", key, value); -} -unsigned MethodContext::repGetMethodHash(CORINFO_METHOD_HANDLE ftn) -{ - DWORDLONG key = CastHandle(ftn); - unsigned result = 0x43; - if (GetMethodHash != nullptr) - if (GetMethodHash->GetIndex(key) >= 0) - result = GetMethodHash->Get(key); - DEBUG_REP(dmpGetMethodHash(key, (DWORD)result)); - return result; -} - -void MethodContext::recCanTailCall(CORINFO_METHOD_HANDLE callerHnd, - CORINFO_METHOD_HANDLE declaredCalleeHnd, - CORINFO_METHOD_HANDLE exactCalleeHnd, - bool fIsTailPrefix, - bool result) -{ - if (CanTailCall == nullptr) - CanTailCall = new LightWeightMap(); - - Agnostic_CanTailCall key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.callerHnd = CastHandle(callerHnd); - key.declaredCalleeHnd = CastHandle(declaredCalleeHnd); - key.exactCalleeHnd = CastHandle(exactCalleeHnd); - key.fIsTailPrefix = (DWORD)fIsTailPrefix; - - DWORD value = result ? 1 : 0; - CanTailCall->Add(key, value); - DEBUG_REC(dmpCanTailCall(key, value)); -} -void MethodContext::dmpCanTailCall(const Agnostic_CanTailCall& key, DWORD value) -{ - printf("CanTailCall key clr-%016" PRIX64 " dcle-%016" PRIX64 " ecle-%016" PRIX64 " pfx-%u, value res-%u", key.callerHnd, - key.declaredCalleeHnd, key.exactCalleeHnd, key.fIsTailPrefix, value); -} -bool MethodContext::repCanTailCall(CORINFO_METHOD_HANDLE callerHnd, - CORINFO_METHOD_HANDLE declaredCalleeHnd, - CORINFO_METHOD_HANDLE exactCalleeHnd, - bool fIsTailPrefix) -{ - Agnostic_CanTailCall key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.callerHnd = CastHandle(callerHnd); - key.declaredCalleeHnd = CastHandle(declaredCalleeHnd); - key.exactCalleeHnd = CastHandle(exactCalleeHnd); - key.fIsTailPrefix = (DWORD)fIsTailPrefix; - - DWORD value = LookupByKeyOrMiss(CanTailCall, key, ": key %016" PRIX64 "", key.callerHnd); - - DEBUG_REP(dmpCanTailCall(key, value)); - return value != 0; -} - -void MethodContext::recIsDelegateCreationAllowed(CORINFO_CLASS_HANDLE delegateHnd, - CORINFO_METHOD_HANDLE calleeHnd, - bool result) -{ - if (IsDelegateCreationAllowed == nullptr) - IsDelegateCreationAllowed = new LightWeightMap(); - - DLDL key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(delegateHnd); - key.B = CastHandle(calleeHnd); - - DWORD value = result ? 1 : 0; - IsDelegateCreationAllowed->Add(key, value); - DEBUG_REC(dmpIsDelegateCreationAllowed(key, value)); -} -void MethodContext::dmpIsDelegateCreationAllowed(DLDL key, DWORD value) -{ - printf("IsDelegateCreationAllowed key delegateHnd-%016" PRIX64 " calleeHnd-%016" PRIX64 " result-%08X", key.A, key.B, value); -} -bool MethodContext::repIsDelegateCreationAllowed(CORINFO_CLASS_HANDLE delegateHnd, CORINFO_METHOD_HANDLE calleeHnd) -{ - DLDL key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(delegateHnd); - key.B = CastHandle(calleeHnd); - - DWORD value = LookupByKeyOrMissNoMessage(IsDelegateCreationAllowed, key); - - DEBUG_REP(dmpIsDelegateCreationAllowed(key, value)); - return value != 0; -} - -void MethodContext::recFindCallSiteSig(CORINFO_MODULE_HANDLE module, - unsigned methTOK, - CORINFO_CONTEXT_HANDLE context, - CORINFO_SIG_INFO* sig) -{ - if (FindCallSiteSig == nullptr) - FindCallSiteSig = new LightWeightMap(); - - Agnostic_FindCallSiteSig key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.module = CastHandle(module); - key.methTok = (DWORD)methTOK; - key.context = CastHandle(context); - - Agnostic_CORINFO_SIG_INFO value = SpmiRecordsHelper::StoreAgnostic_CORINFO_SIG_INFO(*sig, FindCallSiteSig, SigInstHandleMap); - - FindCallSiteSig->Add(key, value); - DEBUG_REC(dmpFindCallSiteSig(key, value)); -} -void MethodContext::dmpFindCallSiteSig(const Agnostic_FindCallSiteSig& key, const Agnostic_CORINFO_SIG_INFO& value) -{ - printf("dmpFindCallSiteSig key module-%016" PRIX64 " methTok-%08X context-%016" PRIX64 "", key.module, key.methTok, key.context); - printf(", value-%s", - SpmiDumpHelper::DumpAgnostic_CORINFO_SIG_INFO(value, FindCallSiteSig, SigInstHandleMap).c_str()); -} -void MethodContext::repFindCallSiteSig(CORINFO_MODULE_HANDLE module, - unsigned methTOK, - CORINFO_CONTEXT_HANDLE context, - CORINFO_SIG_INFO* sig) -{ - Agnostic_FindCallSiteSig key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.module = CastHandle(module); - key.methTok = (DWORD)methTOK; - key.context = CastHandle(context); - - Agnostic_CORINFO_SIG_INFO value = LookupByKeyOrMiss(FindCallSiteSig, key, ": key %08X", key.methTok); - - DEBUG_REP(dmpFindCallSiteSig(key, value)); - - *sig = SpmiRecordsHelper::Restore_CORINFO_SIG_INFO(value, FindCallSiteSig, SigInstHandleMap, cr->getOrCreateMemoryTracker()); -} - -void MethodContext::recGetVarArgsHandle(CORINFO_SIG_INFO* pSig, CORINFO_METHOD_HANDLE methHnd, void** ppIndirection, CORINFO_VARARGS_HANDLE result) -{ - if (GetVarArgsHandle == nullptr) - GetVarArgsHandle = new LightWeightMap(); - - GetVarArgsHandleValue key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.cbSig = (DWORD)pSig->cbSig; - key.pSig_Index = (DWORD)GetVarArgsHandle->AddBuffer((unsigned char*)pSig->pSig, pSig->cbSig); - key.scope = CastHandle(pSig->scope); - key.token = (DWORD)pSig->token; - key.methHnd = CastHandle(methHnd); - - DLDL value; - if (ppIndirection != nullptr) - value.A = CastPointer(*ppIndirection); - else - value.A = 0; - value.B = CastHandle(result); - - GetVarArgsHandle->Add(key, value); - DEBUG_REC(dmpGetVarArgsHandle(key, value)); -} -void MethodContext::dmpGetVarArgsHandle(const GetVarArgsHandleValue& key, DLDL value) -{ - printf("GetVarArgsHandle key sig-%s scope-%016" PRIX64 " token-%08X methHnd-%016" PRIX64 "", - SpmiDumpHelper::DumpPSig(key.pSig_Index, key.cbSig, GetVarArgsHandle).c_str(), - key.scope, key.token, key.methHnd); - printf(", value ppIndirection-%016" PRIX64 " result-%016" PRIX64 "", value.A, value.B); -} -CORINFO_VARARGS_HANDLE MethodContext::repGetVarArgsHandle(CORINFO_SIG_INFO* pSig, CORINFO_METHOD_HANDLE methHnd, void** ppIndirection) -{ - GetVarArgsHandleValue key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.cbSig = (DWORD)pSig->cbSig; - key.pSig_Index = (DWORD)GetVarArgsHandle->Contains((unsigned char*)pSig->pSig, pSig->cbSig); - key.scope = CastHandle(pSig->scope); - key.token = (DWORD)pSig->token; - key.methHnd = CastHandle(methHnd); - - DLDL value = LookupByKeyOrMissNoMessage(GetVarArgsHandle, key); - - DEBUG_REP(dmpGetVarArgsHandle(key, value)); - - if (ppIndirection != nullptr) - *ppIndirection = (void*)value.A; - return (CORINFO_VARARGS_HANDLE)value.B; -} - -void MethodContext::recGetFieldThreadLocalStoreID(CORINFO_FIELD_HANDLE field, void** ppIndirection, DWORD result) -{ - if (GetFieldThreadLocalStoreID == nullptr) - GetFieldThreadLocalStoreID = new LightWeightMap(); - - DLD value; - - if (ppIndirection != nullptr) - value.A = CastPointer(*ppIndirection); - else - value.A = 0; - value.B = (DWORD)result; - - DWORDLONG key = CastHandle(field); - GetFieldThreadLocalStoreID->Add(key, value); - DEBUG_REC(dmpGetFieldThreadLocalStoreID(key, value)); -} -void MethodContext::dmpGetFieldThreadLocalStoreID(DWORDLONG key, DLD value) -{ - printf("GetFieldThreadLocalStoreID key field-%016" PRIX64 ", value ppIndirection-%016" PRIX64 " result-%08X", key, value.A, - value.B); -} -DWORD MethodContext::repGetFieldThreadLocalStoreID(CORINFO_FIELD_HANDLE field, void** ppIndirection) -{ - DWORDLONG key = CastHandle(field); - DLD value = LookupByKeyOrMiss(GetFieldThreadLocalStoreID, key, ": key %016" PRIX64 "", key); - - DEBUG_REP(dmpGetFieldThreadLocalStoreID(key, value)); - - if (ppIndirection != nullptr) - *ppIndirection = (void*)value.A; - return (DWORD)value.B; -} - -void MethodContext::recAllocPgoInstrumentationBySchema( - CORINFO_METHOD_HANDLE ftnHnd, - ICorJitInfo::PgoInstrumentationSchema* pSchema, - UINT32 countSchemaItems, - BYTE** pInstrumentationData, - HRESULT result) -{ - if (AllocPgoInstrumentationBySchema == nullptr) - AllocPgoInstrumentationBySchema = new LightWeightMap(); - - Agnostic_AllocPgoInstrumentationBySchema value; - - // PGO schema data poses a couple of challenges from SPMI's perspective: - // - // First of, the schema requested from the JIT can reasonably be considered - // a compile result that might change with different JIT versions and/or - // environment variables set. So that means SPMI should be able to handle - // seeing a different schema from recording time. - // - // On the other hand, the code generated by the JIT will refer to addresses - // based on pInstrumentationData and the offsets this function assigns in - // pSchema. That means this function should be consistent with the recorded - // EE in how it does layout, to ensure replay is going to match recording - // time. - // - // To handle these issues we store the recorded result of layout for the - // schema and use that if the JIT's requested schema matches it. Otherwise - // we use our own layout algorithm for the schema. This layout algorithm is - // probably not going to match the EE's algorithm exactly, but that's not - // problematic since a different schema likely means there are going to be - // diffs anyway. - - value.instrumentationDataAddress = CastPointer(*pInstrumentationData); - - // For the schema, note that we record *after* calling the VM API. Thus, it has already filled in the `Offset` fields. - // We save the "IN" parts to verify against the replayed call. - value.countSchemaItems = countSchemaItems; - Agnostic_PgoInstrumentationSchema* agnosticSchema = (Agnostic_PgoInstrumentationSchema*)malloc(sizeof(Agnostic_PgoInstrumentationSchema) * countSchemaItems); - for (UINT32 i = 0; i < countSchemaItems; i++) - { - agnosticSchema[i].Offset = (DWORDLONG)pSchema[i].Offset; - agnosticSchema[i].InstrumentationKind = (DWORD)pSchema[i].InstrumentationKind; - agnosticSchema[i].ILOffset = (DWORD)pSchema[i].ILOffset; - agnosticSchema[i].Count = (DWORD)pSchema[i].Count; - agnosticSchema[i].Other = (DWORD)pSchema[i].Other; - } - value.schema_index = AllocPgoInstrumentationBySchema->AddBuffer((unsigned char*)agnosticSchema, sizeof(Agnostic_PgoInstrumentationSchema) * countSchemaItems); - free(agnosticSchema); - value.result = (DWORD)result; - - // Even though `countSchemaItems` and (most of) the `pSchema` array are IN parameters, they do not contribute to the lookup key; - // the `ftnHnd` is the sole key, and the schema passed in for the function is expected to be the same every time the same function - // handle is used. - DWORDLONG key = CastHandle(ftnHnd); - AllocPgoInstrumentationBySchema->Add(key, value); - DEBUG_REC(dmpAllocPgoInstrumentationBySchema(key, value)); -} - -void MethodContext::dmpAllocPgoInstrumentationBySchema(DWORDLONG key, const Agnostic_AllocPgoInstrumentationBySchema& value) -{ - printf("AllocPgoInstrumentationBySchema key ftn-%016" PRIX64 ", value res-%08X addr-%016" PRIX64 " cnt-%u schema{\n", - key, value.result, value.instrumentationDataAddress, value.countSchemaItems); - - if (value.countSchemaItems > 0) - { - Agnostic_PgoInstrumentationSchema* pBuf = - (Agnostic_PgoInstrumentationSchema*)AllocPgoInstrumentationBySchema->GetBuffer(value.schema_index); - - printf("\n"); - for (DWORD i = 0; i < value.countSchemaItems; i++) - { - printf(" %u-{Offset %016" PRIX64 " ILOffset %u Kind %u(0x%x) Count %u Other %u}\n", - i, pBuf[i].Offset, pBuf[i].ILOffset, pBuf[i].InstrumentationKind, pBuf[i].InstrumentationKind, pBuf[i].Count, pBuf[i].Other); - } - AllocPgoInstrumentationBySchema->Unlock(); - } - printf("}"); -} - - -// The following are from which we can't include, with -// a few SPMI alterations (related to "target pointers"). -static ICorJitInfo::PgoInstrumentationKind operator&(ICorJitInfo::PgoInstrumentationKind a, ICorJitInfo::PgoInstrumentationKind b) -{ - return static_cast(static_cast(a) & static_cast(b)); -} - -static unsigned InstrumentationKindToSize(ICorJitInfo::PgoInstrumentationKind kind) -{ - switch(kind & ICorJitInfo::PgoInstrumentationKind::MarshalMask) - { - case ICorJitInfo::PgoInstrumentationKind::None: - return 0; - case ICorJitInfo::PgoInstrumentationKind::FourByte: - return 4; - case ICorJitInfo::PgoInstrumentationKind::EightByte: - return 8; - case ICorJitInfo::PgoInstrumentationKind::TypeHandle: - case ICorJitInfo::PgoInstrumentationKind::MethodHandle: - return static_cast(SpmiTargetPointerSize()); - default: - LogError("Unexpected pgo schema data size (kind = %d)", kind); - return 0; - } -} - -static unsigned InstrumentationKindToAlignment(ICorJitInfo::PgoInstrumentationKind kind) -{ - switch(kind & ICorJitInfo::PgoInstrumentationKind::AlignMask) - { - case ICorJitInfo::PgoInstrumentationKind::Align4Byte: - return 4; - case ICorJitInfo::PgoInstrumentationKind::Align8Byte: - return 8; - case ICorJitInfo::PgoInstrumentationKind::AlignPointer: - return static_cast(SpmiTargetPointerSize()); - default: - return InstrumentationKindToSize(kind); - } -} - -// End of pseudo-include - -HRESULT MethodContext::repAllocPgoInstrumentationBySchema( - CORINFO_METHOD_HANDLE ftnHnd, - ICorJitInfo::PgoInstrumentationSchema* pSchema, - UINT32 countSchemaItems, - BYTE** pInstrumentationData) -{ - HRESULT result; - if (repAllocPgoInstrumentationBySchemaRecorded(ftnHnd, pSchema, countSchemaItems, pInstrumentationData, &result)) - { - // Matching case: return same layout as recorded EE. - return result; - } - - // Do our own layout. - unsigned maxAlignment = 1; - unsigned offset = 0; - for (UINT32 i = 0; i < countSchemaItems; i++) - { - unsigned size = InstrumentationKindToSize(pSchema[i].InstrumentationKind) * pSchema[i].Count; - if (size != 0) - { - unsigned alignment = InstrumentationKindToAlignment(pSchema[i].InstrumentationKind); - maxAlignment = max(maxAlignment, alignment); - offset = AlignUp(offset, alignment); - pSchema[i].Offset = offset; - } - - offset += size; - } - - // We assume JIT does not write or read from this buffer, only generate - // code that uses it. - *pInstrumentationData = (BYTE*)intptr_t(AlignDown(0x12345678u, maxAlignment)); - return S_OK; -} - -// Allocate PGO instrumentation by schema in the same way that the original EE did if the schema matches. -// See comment in recAllocPgoInstrumentationBySchema. -// The schema may be partially allocated even if this function returns false. -bool MethodContext::repAllocPgoInstrumentationBySchemaRecorded( - CORINFO_METHOD_HANDLE ftnHnd, - ICorJitInfo::PgoInstrumentationSchema* pSchema, - UINT32 countSchemaItems, - BYTE** pInstrumentationData, - HRESULT* result) -{ - if (AllocPgoInstrumentationBySchema == nullptr) - return false; - - DWORDLONG key = CastHandle(ftnHnd); - int index = AllocPgoInstrumentationBySchema->GetIndex(key); - if (index == -1) - return false; - - Agnostic_AllocPgoInstrumentationBySchema value = AllocPgoInstrumentationBySchema->GetItem(index); - DEBUG_REP(dmpAllocPgoInstrumentationBySchema(key, value)); - - if (value.countSchemaItems != countSchemaItems) - return false; - - Agnostic_PgoInstrumentationSchema* pAgnosticSchema = (Agnostic_PgoInstrumentationSchema*)AllocPgoInstrumentationBySchema->GetBuffer(value.schema_index); - for (UINT32 iSchema = 0; iSchema < value.countSchemaItems; iSchema++) - { - // Everything but `Offset` field is an IN argument, so verify it against what we stored (since we didn't use these - // IN arguments as part of the key). - - if ((ICorJitInfo::PgoInstrumentationKind)pAgnosticSchema[iSchema].InstrumentationKind != pSchema[iSchema].InstrumentationKind) - return false; - - if ((int32_t)pAgnosticSchema[iSchema].ILOffset != pSchema[iSchema].ILOffset) - return false; - - if ((int32_t)pAgnosticSchema[iSchema].Count != pSchema[iSchema].Count) - return false; - - if ((int32_t)pAgnosticSchema[iSchema].Other != pSchema[iSchema].Other) - return false; - - pSchema[iSchema].Offset = (size_t)pAgnosticSchema[iSchema].Offset; - } - - // We assume JIT does not write or read from this buffer, only generate - // code that uses it. - *pInstrumentationData = (BYTE*)value.instrumentationDataAddress; - *result = value.result; - return true; -} - -void MethodContext::recGetPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftnHnd, - ICorJitInfo::PgoInstrumentationSchema** pSchema, - UINT32* pCountSchemaItems, - BYTE** pInstrumentationData, - ICorJitInfo::PgoSource* pPgoSource, - bool* pDynamicPgo, - HRESULT result) -{ - if (GetPgoInstrumentationResults == nullptr) - GetPgoInstrumentationResults = new LightWeightMap(); - - Agnostic_GetPgoInstrumentationResults value; - - value.countSchemaItems = *pCountSchemaItems; - - ICorJitInfo::PgoInstrumentationSchema* pInSchema = *pSchema; - Agnostic_PgoInstrumentationSchema* agnosticSchema = (Agnostic_PgoInstrumentationSchema*)malloc(sizeof(Agnostic_PgoInstrumentationSchema) * (*pCountSchemaItems)); - size_t maxOffset = 0; - for (UINT32 i = 0; i < (*pCountSchemaItems); i++) - { - agnosticSchema[i].Offset = (DWORDLONG)pInSchema[i].Offset; - agnosticSchema[i].InstrumentationKind = (DWORD)pInSchema[i].InstrumentationKind; - agnosticSchema[i].ILOffset = (DWORD)pInSchema[i].ILOffset; - agnosticSchema[i].Count = (DWORD)pInSchema[i].Count; - agnosticSchema[i].Other = (DWORD)pInSchema[i].Other; - - unsigned const dataSize = InstrumentationKindToSize(pInSchema[i].InstrumentationKind); - maxOffset = max(maxOffset, pInSchema[i].Offset + pInSchema[i].Count * dataSize); - } - value.schema_index = GetPgoInstrumentationResults->AddBuffer((unsigned char*)agnosticSchema, sizeof(Agnostic_PgoInstrumentationSchema) * (*pCountSchemaItems)); - free(agnosticSchema); - - value.data_index = GetPgoInstrumentationResults->AddBuffer((unsigned char*)*pInstrumentationData, (unsigned)maxOffset); - value.dataByteCount = (unsigned)maxOffset; - value.result = (DWORD)result; - value.pgoSource = (DWORD)*pPgoSource; - value.dynamicPgo = (DWORD)*pDynamicPgo; - - DWORDLONG key = CastHandle(ftnHnd); - GetPgoInstrumentationResults->Add(key, value); - DEBUG_REC(dmpGetPgoInstrumentationResults(key, value)); -} -void MethodContext::dmpGetPgoInstrumentationResults(DWORDLONG key, const Agnostic_GetPgoInstrumentationResults& value) -{ - printf("GetPgoInstrumentationResults key ftn-%016" PRIX64 ", value res-%08X schemaCnt-%u profileBufSize-%u source-%u dynamic-%u schema{", - key, value.result, value.countSchemaItems, value.dataByteCount, value.pgoSource, value.dynamicPgo); - - if (value.countSchemaItems > 0) - { - Agnostic_PgoInstrumentationSchema* pBuf = - (Agnostic_PgoInstrumentationSchema*)GetPgoInstrumentationResults->GetBuffer(value.schema_index); - - BYTE* pInstrumentationData = (BYTE*)GetPgoInstrumentationResults->GetBuffer(value.data_index); - - printf("\n"); - for (DWORD i = 0; i < value.countSchemaItems; i++) - { - printf(" %u-{Offset %016" PRIX64 " ILOffset %u Kind %u(0x%x) Count %u Other %u Data ", - i, pBuf[i].Offset, pBuf[i].ILOffset, pBuf[i].InstrumentationKind, pBuf[i].InstrumentationKind, pBuf[i].Count, pBuf[i].Other); - - switch((ICorJitInfo::PgoInstrumentationKind)pBuf[i].InstrumentationKind) - { - case ICorJitInfo::PgoInstrumentationKind::BasicBlockIntCount: - printf("B %u", *(unsigned*)(pInstrumentationData + pBuf[i].Offset)); - break; - case ICorJitInfo::PgoInstrumentationKind::BasicBlockLongCount: - printf("B %" PRIu64 "", *(uint64_t*)(pInstrumentationData + pBuf[i].Offset)); - break; - case ICorJitInfo::PgoInstrumentationKind::EdgeIntCount: - printf("E %u", *(unsigned*)(pInstrumentationData + pBuf[i].Offset)); - break; - case ICorJitInfo::PgoInstrumentationKind::EdgeLongCount: - printf("E %" PRIu64 "", *(uint64_t*)(pInstrumentationData + pBuf[i].Offset)); - break; - case ICorJitInfo::PgoInstrumentationKind::HandleHistogramIntCount: - printf("T %u", *(unsigned*)(pInstrumentationData + pBuf[i].Offset)); - break; - case ICorJitInfo::PgoInstrumentationKind::HandleHistogramLongCount: - printf("T %" PRIu64 "", *(uint64_t*)(pInstrumentationData + pBuf[i].Offset)); - break; - case ICorJitInfo::PgoInstrumentationKind::HandleHistogramTypes: - case ICorJitInfo::PgoInstrumentationKind::HandleHistogramMethods: - for (unsigned int j = 0; j < pBuf[i].Count; j++) - { - printf("[%u] %016" PRIX64 " ", j, CastHandle(*(uintptr_t*)(pInstrumentationData + pBuf[i].Offset + j * sizeof(uintptr_t)))); - } - break; - case ICorJitInfo::PgoInstrumentationKind::ValueHistogramIntCount: - printf("V %u", *(unsigned*)(pInstrumentationData + pBuf[i].Offset)); - break; - case ICorJitInfo::PgoInstrumentationKind::ValueHistogramLongCount: - printf("V %" PRIu64 "", *(uint64_t*)(pInstrumentationData + pBuf[i].Offset)); - break; - case ICorJitInfo::PgoInstrumentationKind::ValueHistogram: - for (unsigned int j = 0; j < pBuf[i].Count; j++) - { - printf("[%u] %08X ", j, *(uint32_t*)(pInstrumentationData + pBuf[i].Offset + j * sizeof(uint32_t))); - } - break; - case ICorJitInfo::PgoInstrumentationKind::GetLikelyClass: - case ICorJitInfo::PgoInstrumentationKind::GetLikelyMethod: - { - // (N)umber, (L)ikelihood, (H)andle - printf("N %u L %u H %016" PRIX64 "", (unsigned)(pBuf[i].Other >> 8), (unsigned)(pBuf[i].Other & 0xFF), CastHandle(*(uintptr_t*)(pInstrumentationData + pBuf[i].Offset))); - } - break; - default: - printf("?"); - break; - } - - printf("}\n"); - } - GetPgoInstrumentationResults->Unlock(); - } - printf("} data_index-%u", value.data_index); -} -HRESULT MethodContext::repGetPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftnHnd, - ICorJitInfo::PgoInstrumentationSchema** pSchema, - UINT32* pCountSchemaItems, - BYTE** pInstrumentationData, - ICorJitInfo::PgoSource* pPgoSource, - bool* pDynamicPgo) -{ - DWORDLONG key = CastHandle(ftnHnd); - Agnostic_GetPgoInstrumentationResults tempValue = LookupByKeyOrMiss(GetPgoInstrumentationResults, key, ": key %016" PRIX64 "", key); - - DEBUG_REP(dmpGetPgoInstrumentationResults(key, tempValue)); - - *pCountSchemaItems = (UINT32)tempValue.countSchemaItems; - *pInstrumentationData = (BYTE*)GetPgoInstrumentationResults->GetBuffer(tempValue.data_index); - *pPgoSource = (ICorJitInfo::PgoSource)tempValue.pgoSource; - *pDynamicPgo = (bool)tempValue.dynamicPgo; - - ICorJitInfo::PgoInstrumentationSchema* pOutSchema = (ICorJitInfo::PgoInstrumentationSchema*)AllocJitTempBuffer(tempValue.countSchemaItems * sizeof(ICorJitInfo::PgoInstrumentationSchema)); - - Agnostic_PgoInstrumentationSchema* pAgnosticSchema = (Agnostic_PgoInstrumentationSchema*)GetPgoInstrumentationResults->GetBuffer(tempValue.schema_index); - for (UINT32 iSchema = 0; iSchema < tempValue.countSchemaItems; iSchema++) - { - pOutSchema[iSchema].Offset = (size_t)pAgnosticSchema[iSchema].Offset; - pOutSchema[iSchema].InstrumentationKind = (ICorJitInfo::PgoInstrumentationKind)pAgnosticSchema[iSchema].InstrumentationKind; - pOutSchema[iSchema].ILOffset = (int32_t)pAgnosticSchema[iSchema].ILOffset; - pOutSchema[iSchema].Count = (int32_t)pAgnosticSchema[iSchema].Count; - pOutSchema[iSchema].Other = (int32_t)pAgnosticSchema[iSchema].Other; - } - - *pSchema = pOutSchema; - - HRESULT result = (HRESULT)tempValue.result; - return result; -} - -void MethodContext::recIsMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2, bool result) -{ - if (IsMoreSpecificType == nullptr) - IsMoreSpecificType = new LightWeightMap(); - - DLDL key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(cls1); - key.B = CastHandle(cls2); - - DWORD value = result ? 1 : 0; - IsMoreSpecificType->Add(key, value); - DEBUG_REC(dmpIsMoreSpecificType(key, value)); -} -void MethodContext::dmpIsMoreSpecificType(DLDL key, DWORD value) -{ - printf("IsMoreSpecificType key cls1-%016" PRIX64 " cls2-%016" PRIX64 ", value %u", key.A, key.B, value); -} -bool MethodContext::repIsMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2) -{ - DLDL key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(cls1); - key.B = CastHandle(cls2); - - DWORD value = LookupByKeyOrMiss(IsMoreSpecificType, key, ": key %016" PRIX64 " %016" PRIX64 "", key.A, key.B); - - DEBUG_REP(dmpIsMoreSpecificType(key, value)); - return value != 0; -} - -void MethodContext::recIsExactType(CORINFO_CLASS_HANDLE cls, bool result) -{ - if (IsExactType == nullptr) - IsExactType = new LightWeightMap(); - - DWORDLONG key = CastHandle(cls); - DWORD value = result ? 1 : 0; - IsExactType->Add(key, value); - DEBUG_REC(dmpIsExactType(key, value)); -} -void MethodContext::dmpIsExactType(DWORDLONG key, DWORD value) -{ - printf("IsExactType key cls-%016" PRIX64 ", value res-%u", key, value); -} -bool MethodContext::repIsExactType(CORINFO_CLASS_HANDLE cls) -{ - DWORDLONG key = CastHandle(cls); - DWORD value = LookupByKeyOrMiss(IsExactType, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpIsExactType(key, value)); - return value != 0; -} - -void MethodContext::recIsGenericType(CORINFO_CLASS_HANDLE cls, TypeCompareState result) -{ - if (IsGenericType == nullptr) - IsGenericType = new LightWeightMap(); - - DWORDLONG key = CastHandle(cls); - DWORD value = (DWORD)result; - IsGenericType->Add(key, value); - DEBUG_REC(dmpIsGenericType(key, value)); -} -void MethodContext::dmpIsGenericType(DWORDLONG key, DWORD value) -{ - printf("IsGenericType key cls-%016" PRIX64 ", value res-%d", key, value); -} -TypeCompareState MethodContext::repIsGenericType(CORINFO_CLASS_HANDLE cls) -{ - DWORDLONG key = CastHandle(cls); - DWORD value = LookupByKeyOrMiss(IsGenericType, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpIsGenericType(key, value)); - return (TypeCompareState)value; -} - -void MethodContext::recIsNullableType(CORINFO_CLASS_HANDLE cls, TypeCompareState result) -{ - if (IsNullableType == nullptr) - IsNullableType = new LightWeightMap(); - - DWORDLONG key = CastHandle(cls); - DWORD value = (DWORD)result; - IsNullableType->Add(key, value); - DEBUG_REC(dmpIsNullableType(key, value)); -} -void MethodContext::dmpIsNullableType(DWORDLONG key, DWORD value) -{ - printf("IsNullableType key cls-%016" PRIX64 ", value res-%d", key, value); -} -TypeCompareState MethodContext::repIsNullableType(CORINFO_CLASS_HANDLE cls) -{ - DWORDLONG key = CastHandle(cls); - DWORD value = LookupByKeyOrMiss(IsNullableType, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpIsNullableType(key, value)); - return (TypeCompareState)value; -} - -void MethodContext::recIsEnum(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE underlyingType, TypeCompareState result) -{ - if (IsEnum == nullptr) - IsEnum = new LightWeightMap(); - - DWORDLONG key = CastHandle(cls); - - DLD value; - ZeroMemory(&value, sizeof(value)); - value.A = CastHandle(underlyingType); - value.B = (DWORD)result; - - IsEnum->Add(key, value); - DEBUG_REC(dmpIsEnum(key, value)); -} -void MethodContext::dmpIsEnum(DWORDLONG key, DLD value) -{ - printf("IsEnum key cls-%016" PRIX64 ", value underlyingType-%016" PRIX64 " result-%u", key, value.A, value.B); -} -TypeCompareState MethodContext::repIsEnum(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE* underlyingType) -{ - DWORDLONG key = CastHandle(cls); - - DLD value = LookupByKeyOrMiss(IsEnum, key, ": key %016" PRIX64 "", key); - - DEBUG_REP(dmpIsEnum(key, value)); - if (underlyingType != nullptr) - *underlyingType = (CORINFO_CLASS_HANDLE)value.A; - return (TypeCompareState)value.B; -} - -void MethodContext::recGetCookieForInterpreterCalliSig(CORINFO_SIG_INFO* szMetaSig, LPVOID result) -{ - if (GetCookieForInterpreterCalliSig == nullptr) - GetCookieForInterpreterCalliSig = new LightWeightMap(); - - GetCookieForInterpreterCalliSigValue key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.cbSig = (DWORD)szMetaSig->cbSig; - key.pSig_Index = (DWORD)GetCookieForInterpreterCalliSig->AddBuffer((unsigned char*)szMetaSig->pSig, szMetaSig->cbSig); - key.scope = CastHandle(szMetaSig->scope); - key.token = (DWORD)szMetaSig->token; - - DLDL value; - value.A = CastPointer(result); - - GetCookieForInterpreterCalliSig->Add(key, value); - DEBUG_REC(dmpGetCookieForInterpreterCalliSig(key, value)); -} - -void MethodContext::dmpGetCookieForInterpreterCalliSig(const GetCookieForInterpreterCalliSigValue& key, DLDL value) -{ - printf("GetCookieForInterpreterCalliSig NYI"); -} -LPVOID MethodContext::repGetCookieForInterpreterCalliSig(CORINFO_SIG_INFO* szMetaSig) -{ - AssertMapExistsNoMessage(GetCookieForInterpreterCalliSig); - - GetCookieForInterpreterCalliSigValue key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.cbSig = (DWORD)szMetaSig->cbSig; - key.pSig_Index = (DWORD)GetCookieForInterpreterCalliSig->Contains((unsigned char*)szMetaSig->pSig, szMetaSig->cbSig); - key.scope = CastHandle(szMetaSig->scope); - key.token = (DWORD)szMetaSig->token; - - DLDL value = LookupByKeyOrMissNoMessage(GetCookieForInterpreterCalliSig, key); - - DEBUG_REP(dmpGetCookieForInterpreterCalliSig(key, value)); - - return (LPVOID)value.A; -} - -void MethodContext::recErrorList(const char* error) -{ - if (ErrorList == nullptr) - ErrorList = new DenseLightWeightMap(); - - DWORD temp = (DWORD)-1; - - if (error != nullptr) - temp = (DWORD)ErrorList->AddBuffer((unsigned char*)error, (DWORD)strlen(error) + 1); - - ErrorList->Append(temp); -} -void MethodContext::dmpErrorList(DWORD key, DWORD value) -{ - printf("ErrorList NYI"); -} - -void MethodContext::recGetProfilingHandle(bool* pbHookFunction, void** pProfilerHandle, bool* pbIndirectedHandles) -{ - if (GetProfilingHandle == nullptr) - GetProfilingHandle = new LightWeightMap(); - - Agnostic_GetProfilingHandle value; - ZeroMemory(&value, sizeof(value)); // Zero value including any struct padding - value.bHookFunction = (DWORD)*pbHookFunction; - value.ProfilerHandle = CastPointer(*pProfilerHandle); - value.bIndirectedHandles = (DWORD)*pbIndirectedHandles; - GetProfilingHandle->Add(0, value); - DEBUG_REC(dmpGetProfilingHandle(0, value)); -} -void MethodContext::dmpGetProfilingHandle(DWORD key, const Agnostic_GetProfilingHandle& value) -{ - printf("GetProfilingHandle key %u, value bHookFtn-%u profHnd-%016" PRIX64 " bIndHnd-%u", key, value.bHookFunction, - value.ProfilerHandle, value.bIndirectedHandles); -} -void MethodContext::repGetProfilingHandle(bool* pbHookFunction, void** pProfilerHandle, bool* pbIndirectedHandles) -{ - Agnostic_GetProfilingHandle value = LookupByKeyOrMissNoMessage(GetProfilingHandle, 0); - - DEBUG_REP(dmpGetProfilingHandle(0, value)); - - *pbHookFunction = value.bHookFunction != 0; - *pProfilerHandle = (void*)value.ProfilerHandle; - *pbIndirectedHandles = value.bIndirectedHandles != 0; -} - -void MethodContext::recEmbedFieldHandle(CORINFO_FIELD_HANDLE handle, void** ppIndirection, CORINFO_FIELD_HANDLE result) -{ - if (EmbedFieldHandle == nullptr) - EmbedFieldHandle = new LightWeightMap(); - - DLDL value; - if (ppIndirection != nullptr) - value.A = CastPointer(*ppIndirection); - else - value.A = 0; - value.B = CastHandle(result); - - DWORDLONG key = CastHandle(handle); - EmbedFieldHandle->Add(key, value); - DEBUG_REC(dmpEmbedFieldHandle(key, value)); -} -void MethodContext::dmpEmbedFieldHandle(DWORDLONG key, DLDL value) -{ - printf("EmbedFieldHandle NYI"); -} -CORINFO_FIELD_HANDLE MethodContext::repEmbedFieldHandle(CORINFO_FIELD_HANDLE handle, void** ppIndirection) -{ - DWORDLONG key = CastHandle(handle); - DLDL value = LookupByKeyOrMiss(EmbedFieldHandle, key, ": key %016" PRIX64 "", key); - - DEBUG_REP(dmpEmbedFieldHandle(key, value)); - - if (ppIndirection != nullptr) - *ppIndirection = (void*)value.A; - return (CORINFO_FIELD_HANDLE)value.B; -} - -void MethodContext::recCompareTypesForCast(CORINFO_CLASS_HANDLE fromClass, - CORINFO_CLASS_HANDLE toClass, - TypeCompareState result) -{ - if (CompareTypesForCast == nullptr) - CompareTypesForCast = new LightWeightMap(); - - DLDL key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(fromClass); - key.B = CastHandle(toClass); - - DWORD value = (DWORD)result; - CompareTypesForCast->Add(key, value); - DEBUG_REC(dmpCompareTypesForCast(key, value)); -} -void MethodContext::dmpCompareTypesForCast(DLDL key, DWORD value) -{ - printf("CompareTypesForCast key fromClass=%016" PRIX64 ", toClass=%016" PRIx64 ", result=%d", key.A, key.B, value); -} -TypeCompareState MethodContext::repCompareTypesForCast(CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass) -{ - DLDL key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(fromClass); - key.B = CastHandle(toClass); - - DWORD value = LookupByKeyOrMiss(CompareTypesForCast, key, ": key %016" PRIX64 " %016" PRIX64 "", key.A, key.B); - - DEBUG_REP(dmpCompareTypesForCast(key, value)); - TypeCompareState result = (TypeCompareState)value; - return result; -} - -void MethodContext::recCompareTypesForEquality(CORINFO_CLASS_HANDLE cls1, - CORINFO_CLASS_HANDLE cls2, - TypeCompareState result) -{ - if (CompareTypesForEquality == nullptr) - CompareTypesForEquality = new LightWeightMap(); - - DLDL key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(cls1); - key.B = CastHandle(cls2); - - DWORD value = (DWORD)result; - CompareTypesForEquality->Add(key, value); - DEBUG_REC(dmpCompareTypesForEquality(key, value)); -} -void MethodContext::dmpCompareTypesForEquality(DLDL key, DWORD value) -{ - printf("CompareTypesForEquality key cls1=%016" PRIX64 ", cls2=%016" PRIx64 ", result=%d", key.A, key.B, value); -} -TypeCompareState MethodContext::repCompareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2) -{ - DLDL key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(cls1); - key.B = CastHandle(cls2); - - DWORD value = LookupByKeyOrMiss(CompareTypesForEquality, key, ": key %016" PRIX64 " %016" PRIX64 "", key.A, key.B); - - DEBUG_REP(dmpCompareTypesForEquality(key, value)); - TypeCompareState result = (TypeCompareState)value; - return result; -} - -void MethodContext::recGetSystemVAmd64PassStructInRegisterDescriptor( - CORINFO_CLASS_HANDLE structHnd, - SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr, - bool result) -{ - if (GetSystemVAmd64PassStructInRegisterDescriptor == nullptr) - GetSystemVAmd64PassStructInRegisterDescriptor = - new LightWeightMap(); - - DWORDLONG key; - Agnostic_GetSystemVAmd64PassStructInRegisterDescriptor value; - - key = CastHandle(structHnd); - - value.passedInRegisters = (DWORD)structPassInRegDescPtr->passedInRegisters; - value.eightByteCount = (DWORD)structPassInRegDescPtr->eightByteCount; - for (int i = 0; i < CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS; i++) - { - value.eightByteClassifications[i] = (DWORD)structPassInRegDescPtr->eightByteClassifications[i]; - value.eightByteSizes[i] = (DWORD)structPassInRegDescPtr->eightByteSizes[i]; - value.eightByteOffsets[i] = (DWORD)structPassInRegDescPtr->eightByteOffsets[i]; - } - value.result = result ? 1 : 0; - - GetSystemVAmd64PassStructInRegisterDescriptor->Add(key, value); - DEBUG_REC(dmpGetSystemVAmd64PassStructInRegisterDescriptor(key, value)); -} -void MethodContext::dmpGetSystemVAmd64PassStructInRegisterDescriptor( - DWORDLONG key, const Agnostic_GetSystemVAmd64PassStructInRegisterDescriptor& value) -{ - printf("GetSystemVAmd64PassStructInRegisterDescriptor key structHnd-%016" PRIX64 ", value passInReg-%u 8bCount-%u", key, - value.passedInRegisters, value.eightByteCount); - for (int i = 0; i < CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS; i++) - { - printf(" 8bClass[%u]-%u 8bSz[%u]-%u 8bOff[%u]-%u", i, value.eightByteClassifications[i], i, - value.eightByteSizes[i], i, value.eightByteOffsets[i]); - } - printf(" result %u", value.result); -} -bool MethodContext::repGetSystemVAmd64PassStructInRegisterDescriptor( - CORINFO_CLASS_HANDLE structHnd, SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr) -{ - DWORDLONG key = CastHandle(structHnd); - - Agnostic_GetSystemVAmd64PassStructInRegisterDescriptor value; - value = LookupByKeyOrMiss(GetSystemVAmd64PassStructInRegisterDescriptor, key, ": key %016" PRIX64 "", key); - - DEBUG_REP(dmpGetSystemVAmd64PassStructInRegisterDescriptor(key, value)); - - structPassInRegDescPtr->passedInRegisters = value.passedInRegisters ? true : false; - structPassInRegDescPtr->eightByteCount = (uint8_t)value.eightByteCount; - for (int i = 0; i < CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS; i++) - { - structPassInRegDescPtr->eightByteClassifications[i] = - (SystemVClassificationType)value.eightByteClassifications[i]; - structPassInRegDescPtr->eightByteSizes[i] = (uint8_t)value.eightByteSizes[i]; - structPassInRegDescPtr->eightByteOffsets[i] = (uint8_t)value.eightByteOffsets[i]; - } - - return value.result ? true : false; -} - -void MethodContext::recGetSwiftLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_SWIFT_LOWERING* pLowering) -{ - if (GetSwiftLowering == nullptr) - GetSwiftLowering = new LightWeightMap(); - - DWORDLONG key = CastHandle(structHnd); - - Agnostic_GetSwiftLowering value; - ZeroMemory(&value, sizeof(value)); - value.byReference = pLowering->byReference ? 1 : 0; - if (!pLowering->byReference) - { - value.numLoweredElements = static_cast(pLowering->numLoweredElements); - for (size_t i = 0; i < pLowering->numLoweredElements; i++) - { - value.loweredElements[i] = static_cast(pLowering->loweredElements[i]); - value.offsets[i] = pLowering->offsets[i]; - } - } - - GetSwiftLowering->Add(key, value); - DEBUG_REC(dmpGetSwiftLowering(key, value)); -} -void MethodContext::dmpGetSwiftLowering( - DWORDLONG key, const Agnostic_GetSwiftLowering& value) -{ - printf("GetSwiftLowering key structHnd-%016" PRIX64 ", value byReference-%u numLoweredElements-%u", key, - value.byReference, value.numLoweredElements); - if (!value.byReference) - { - for (size_t i = 0; i < value.numLoweredElements; i++) - { - printf(" [%zu] %u", i, value.loweredElements[i]); - } - } -} -void MethodContext::repGetSwiftLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_SWIFT_LOWERING* pLowering) -{ - DWORDLONG key = CastHandle(structHnd); - Agnostic_GetSwiftLowering value = LookupByKeyOrMiss(GetSwiftLowering, key, ": key %016" PRIX64 "", key); - - DEBUG_REP(dmpGetSwiftLowering(key, value)); - - pLowering->byReference = value.byReference != 0; - pLowering->numLoweredElements = value.numLoweredElements; - - for (size_t i = 0; i < pLowering->numLoweredElements; i++) - { - pLowering->loweredElements[i] = static_cast(value.loweredElements[i]); - pLowering->offsets[i] = value.offsets[i]; - } -} - -void MethodContext::recGetFpStructLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_FPSTRUCT_LOWERING* pLowering) -{ - if (GetFpStructLowering == nullptr) - GetFpStructLowering = new LightWeightMap(); - - DWORDLONG key = CastHandle(structHnd); - - Agnostic_GetFpStructLowering value; - ZeroMemory(&value, sizeof(value)); - value.byIntegerCallConv = pLowering->byIntegerCallConv ? 1 : 0; - if (!pLowering->byIntegerCallConv) - { - value.numLoweredElements = static_cast(pLowering->numLoweredElements); - for (size_t i = 0; i < pLowering->numLoweredElements; i++) - { - value.loweredElements[i] = static_cast(pLowering->loweredElements[i]); - value.offsets[i] = pLowering->offsets[i]; - } - } - - GetFpStructLowering->Add(key, value); - DEBUG_REC(dmpGetFpStructLowering(key, value)); -} -void MethodContext::dmpGetFpStructLowering( - DWORDLONG key, const Agnostic_GetFpStructLowering& value) -{ - printf("GetFpStructLowering key structHnd-%016" PRIX64 ", value byIntegerCallConv-%u numLoweredElements-%u", key, - value.byIntegerCallConv, value.numLoweredElements); - if (!value.byIntegerCallConv) - { - for (size_t i = 0; i < value.numLoweredElements; i++) - { - printf(" [%zu] %u", i, value.loweredElements[i]); - } - } -} -void MethodContext::repGetFpStructLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_FPSTRUCT_LOWERING* pLowering) -{ - DWORDLONG key = CastHandle(structHnd); - Agnostic_GetFpStructLowering value = LookupByKeyOrMiss(GetFpStructLowering, key, ": key %016" PRIX64 "", key); - - DEBUG_REP(dmpGetFpStructLowering(key, value)); - - pLowering->byIntegerCallConv = value.byIntegerCallConv != 0; - pLowering->numLoweredElements = value.numLoweredElements; - - for (size_t i = 0; i < pLowering->numLoweredElements; i++) - { - pLowering->loweredElements[i] = static_cast(value.loweredElements[i]); - pLowering->offsets[i] = value.offsets[i]; - } -} - -void MethodContext::recGetWasmLowering(CORINFO_CLASS_HANDLE structHnd, CorInfoWasmType value) -{ - if (GetWasmLowering == nullptr) - GetWasmLowering = new LightWeightMap(); - DWORDLONG key = CastHandle(structHnd); - GetWasmLowering->Add(key, (DWORD) value); - DEBUG_REC(dmpGetWasmLowering(key, value)); -} -void MethodContext::dmpGetWasmLowering(DWORDLONG key, DWORD value) -{ - printf("GetWasmLowering key structHnd-%016" PRIX64 ", value %d ", key, value); -} -CorInfoWasmType MethodContext::repGetWasmLowering(CORINFO_CLASS_HANDLE structHnd) -{ - DWORDLONG key = CastHandle(structHnd); - DWORD value = LookupByKeyOrMiss(GetWasmLowering, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetWasmLowering(key, value)); - return (CorInfoWasmType) value; -} - -void MethodContext::recGetRelocTypeHint(void* target, CorInfoReloc result) -{ - if (GetRelocTypeHint == nullptr) - GetRelocTypeHint = new LightWeightMap(); - - DWORDLONG key = CastPointer(target); - DWORD value = (DWORD)result; - GetRelocTypeHint->Add(key, value); - DEBUG_REC(dmpGetRelocTypeHint(key, value)); -} -void MethodContext::dmpGetRelocTypeHint(DWORDLONG key, DWORD value) -{ - printf("GetRelocTypeHint key tgt-%016" PRIX64 ", value hint-%u", key, value); -} -CorInfoReloc MethodContext::repGetRelocTypeHint(void* target) -{ - DWORDLONG key = CastPointer(target); - - if ((GetRelocTypeHint == nullptr) || (GetRelocTypeHint->GetIndex(key) == -1)) - { -#ifdef sparseMC - LogDebug("Sparse - repGetRelocTypeHint yielding fake answer..."); - return CorInfoReloc::NONE; -#else - LogException(EXCEPTIONCODE_MC, "Didn't find %016" PRIX64 "", key); -#endif - } - - int index = GetRelocTypeHint->GetIndex(key); - CorInfoReloc retVal; - if (index == -1) - { - retVal = CorInfoReloc::RELATIVE32; - } - else - { - retVal = (CorInfoReloc)GetRelocTypeHint->Get(key); - } - - DEBUG_REP(dmpGetRelocTypeHint(key, (DWORD)retVal)); - return retVal; -} - -void MethodContext::recGetAddressAlignment(void* address, uint32_t result) -{ - if (GetAddressAlignment == nullptr) - GetAddressAlignment = new LightWeightMap(); - - DWORDLONG key = CastPointer(address); - DWORD value = (DWORD)result; - GetAddressAlignment->Add(key, value); - DEBUG_REC(dmpGetAddressAlignment(key, value)); -} -void MethodContext::dmpGetAddressAlignment(DWORDLONG key, DWORD value) -{ - printf("GetAddressAlignment key addr-%016" PRIX64 ", value align-%u", key, value); -} -uint32_t MethodContext::repGetAddressAlignment(void* address) -{ - DWORDLONG key = CastPointer(address); - - if ((GetAddressAlignment == nullptr) || (GetAddressAlignment->GetIndex(key) == -1)) - { -#ifdef sparseMC - LogDebug("Sparse - repGetAddressAlignment yielding fake answer..."); - return 1; -#else - LogException(EXCEPTIONCODE_MC, "Didn't find %016" PRIX64 "", key); -#endif - } - - DWORD value = GetAddressAlignment->Get(key); - DEBUG_REP(dmpGetAddressAlignment(key, value)); - return (uint32_t)value; -} - -void MethodContext::recGetExpectedTargetArchitecture(DWORD result) -{ - if (GetExpectedTargetArchitecture == nullptr) - GetExpectedTargetArchitecture = new LightWeightMap(); - - DWORD key = 0; // There is only ever a single entry to this map - GetExpectedTargetArchitecture->Add(key, result); - DEBUG_REC(dmpGetExpectedTargetArchitecture(key, result)); -} -void MethodContext::dmpGetExpectedTargetArchitecture(DWORD key, DWORD result) -{ - printf("GetExpectedTargetArchitecture key %u, res %u", key, result); -} -DWORD MethodContext::repGetExpectedTargetArchitecture() -{ - DWORD key = 0; - - DWORD value = LookupByKeyOrMiss(GetExpectedTargetArchitecture, key, ": key %08X", key); - - DEBUG_REP(dmpGetExpectedTargetArchitecture(key, value)); - return value; -} - -void MethodContext::recDoesFieldBelongToClass(CORINFO_FIELD_HANDLE fld, CORINFO_CLASS_HANDLE cls, bool result) -{ - if (DoesFieldBelongToClass == nullptr) - DoesFieldBelongToClass = new LightWeightMap(); - - DLDL key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(fld); - key.B = CastHandle(cls); - - DWORD value = (DWORD)result; - DoesFieldBelongToClass->Add(key, value); - DEBUG_REC(dmpDoesFieldBelongToClass(key, result)); -} - -void MethodContext::dmpDoesFieldBelongToClass(DLDL key, bool value) -{ - printf("DoesFieldBelongToClass key fld=%016" PRIX64 ", cls=%016" PRIx64 ", result=%d", key.A, key.B, value); -} - -bool MethodContext::repDoesFieldBelongToClass(CORINFO_FIELD_HANDLE fld, CORINFO_CLASS_HANDLE cls) -{ - DLDL key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(fld); - key.B = CastHandle(cls); - - DWORD value = LookupByKeyOrMiss(DoesFieldBelongToClass, key, ": key %016" PRIX64 " %016" PRIX64 "", key.A, key.B); - - DEBUG_REP(dmpDoesFieldBelongToClass(key, value)); - return value != 0; -} - -void MethodContext::recGetClassNameFromMetadata(CORINFO_CLASS_HANDLE cls, char* className, const char** namespaceName) -{ - if (GetClassNameFromMetadata == nullptr) - GetClassNameFromMetadata = new LightWeightMap(); - - DLD key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.A = CastHandle(cls); - key.B = (namespaceName != nullptr); - - DD value; - if (className != nullptr) - value.A = GetClassNameFromMetadata->AddBuffer((unsigned char*)className, (DWORD)strlen(className) + 1); - else - value.A = (DWORD)-1; - - if ((namespaceName != nullptr) && (*namespaceName != nullptr)) - value.B = - GetClassNameFromMetadata->AddBuffer((unsigned char*)*namespaceName, (DWORD)strlen(*namespaceName) + 1); - else - value.B = (DWORD)-1; - - GetClassNameFromMetadata->Add(key, value); - DEBUG_REC(dmpGetClassNameFromMetadata(key, value)); -} - -void MethodContext::dmpGetClassNameFromMetadata(DLD key, DD value) -{ - unsigned char* className = (unsigned char*)GetClassNameFromMetadata->GetBuffer(value.A); - unsigned char* namespaceName = (unsigned char*)GetClassNameFromMetadata->GetBuffer(value.B); - printf("GetClassNameFromMetadata key - classNonNull-%" PRIu64 " namespaceNonNull-%u, value " - "class-'%s', namespace-'%s'", - key.A, key.B, className, namespaceName); - GetClassNameFromMetadata->Unlock(); -} - -const char* MethodContext::repGetClassNameFromMetadata(CORINFO_CLASS_HANDLE cls, const char** namespaceName) -{ - const char* result = nullptr; - DLD key; - ZeroMemory(&key, sizeof(key)); - key.A = CastHandle(cls); - key.B = (namespaceName != nullptr); - - DD value = LookupByKeyOrMiss(GetClassNameFromMetadata, key, " : key cls-%016" PRIX64 " hasNs-%u", key.A, key.B); - DEBUG_REP(dmpGetClassNameFromMetadata(key, value)); - - result = (const char*)GetClassNameFromMetadata->GetBuffer(value.A); - - if (namespaceName != nullptr) - { - *namespaceName = (const char*)GetClassNameFromMetadata->GetBuffer(value.B); - } - return result; -} - -void MethodContext::recGetTypeInstantiationArgument(CORINFO_CLASS_HANDLE cls, - unsigned index, - CORINFO_CLASS_HANDLE result) -{ - if (GetTypeInstantiationArgument == nullptr) - GetTypeInstantiationArgument = new LightWeightMap(); - - DLD key; - ZeroMemory(&key, sizeof(key)); - key.A = CastHandle(cls); - key.B = index; - DWORDLONG value = CastHandle(result); - GetTypeInstantiationArgument->Add(key, value); - DEBUG_REC(dmpGetTypeInstantiationArgument(key, value)); -} -void MethodContext::dmpGetTypeInstantiationArgument(DLD key, DWORDLONG value) -{ - printf("GetTypeInstantiationArgument key - classNonNull-%" PRIu64 ", index-%u, value NonNull-%" PRIu64 "", key.A, key.B, value); - GetTypeInstantiationArgument->Unlock(); -} -CORINFO_CLASS_HANDLE MethodContext::repGetTypeInstantiationArgument(CORINFO_CLASS_HANDLE cls, unsigned index) -{ - DLD key; - ZeroMemory(&key, sizeof(key)); - key.A = CastHandle(cls); - key.B = index; - - DWORDLONG value = LookupByKeyOrMissNoMessage(GetTypeInstantiationArgument, key); - DEBUG_REP(dmpGetTypeInstantiationArgument(key, value)); - return (CORINFO_CLASS_HANDLE)value; -} - -void MethodContext::recGetMethodInstantiationArgument(CORINFO_METHOD_HANDLE ftn, - unsigned index, - CORINFO_CLASS_HANDLE result) -{ - if (GetMethodInstantiationArgument == nullptr) - GetMethodInstantiationArgument = new LightWeightMap(); - - DLD key; - ZeroMemory(&key, sizeof(key)); - key.A = CastHandle(ftn); - key.B = index; - DWORDLONG value = CastHandle(result); - GetMethodInstantiationArgument->Add(key, value); - DEBUG_REC(dmpGetMethodInstantiationArgument(key, value)); -} -void MethodContext::dmpGetMethodInstantiationArgument(DLD key, DWORDLONG value) -{ - printf("GetMethodInstantiationArgument key - methodNonNull-%" PRIu64 ", index-%u, value NonNull-%" PRIu64 "", key.A, key.B, value); - GetMethodInstantiationArgument->Unlock(); -} -CORINFO_CLASS_HANDLE MethodContext::repGetMethodInstantiationArgument(CORINFO_METHOD_HANDLE ftn, unsigned index) -{ - DLD key; - ZeroMemory(&key, sizeof(key)); - key.A = CastHandle(ftn); - key.B = index; - - DWORDLONG value = LookupByKeyOrMissNoMessage(GetMethodInstantiationArgument, key); - DEBUG_REP(dmpGetMethodInstantiationArgument(key, value)); - return (CORINFO_CLASS_HANDLE)value; -} - -void MethodContext::recPrint( - const char* name, - LightWeightMap*& map, - DWORDLONG handle, - char* buffer, - size_t bufferSize, - size_t* pRequiredBufferSize, - size_t bytesWritten) -{ - if (map == nullptr) - map = new LightWeightMap(); - - // Required size of a buffer that contains all data and null terminator. - UINT requiredBufferSize = UINT_MAX; - if (pRequiredBufferSize != nullptr) - { - requiredBufferSize = (UINT)(*pRequiredBufferSize); - } - else if (bytesWritten + 1 < bufferSize) - { - requiredBufferSize = (UINT)(bytesWritten + 1); - } - - Agnostic_PrintResult res; - int index = map->GetIndex(handle); - if (index != -1) - { - // Merge with existing entry - - res = map->GetItem(index); - - if (requiredBufferSize != UINT_MAX) - { - res.requiredBufferSize = requiredBufferSize; - } - - if (bytesWritten > res.stringBufferSize) - { - // Always stored without null terminator. - res.stringBuffer = map->AddBuffer((unsigned char*)buffer, static_cast(bytesWritten)); - res.stringBufferSize = (UINT)bytesWritten; - } - - map->Update(index, res); - - DEBUG_REC(dmpPrint(name, map, handle, res)); - return; - } - - if (buffer != nullptr) - { - res.stringBuffer = map->AddBuffer((unsigned char*)buffer, static_cast(bytesWritten)); - } - else - { - res.stringBuffer = UINT_MAX; - } - - res.stringBufferSize = (UINT)bytesWritten; - res.requiredBufferSize = requiredBufferSize; - - map->Add(handle, res); - DEBUG_REC(dmpPrint(name, map, handle, res)); -} - -void MethodContext::dmpPrint( - const char* name, - LightWeightMapBuffer* buffer, - DWORDLONG key, - const Agnostic_PrintResult& value) -{ - printf("%s key hnd-%016" PRIX64 ", stringBufferSize-%u, requiredBufferSize-%u", name, key, value.stringBufferSize, value.requiredBufferSize); - buffer->Unlock(); -} - -size_t MethodContext::repPrint( - const char* name, - LightWeightMap*& map, - DWORDLONG handle, - char* buffer, - size_t bufferSize, - size_t* pRequiredBufferSize) -{ - Agnostic_PrintResult res = LookupByKeyOrMiss(map, handle, ": map %s key %016" PRIx64 "", name, handle); - DEBUG_REP(dmpPrint(name, buffer, handle, res)); - - if (pRequiredBufferSize != nullptr) - { - if (res.requiredBufferSize == UINT_MAX) - { - LogException(EXCEPTIONCODE_MC, "SuperPMI assertion failed (missing requiredBufferSize for %s key %016" PRIx64 ")", name, handle); - } - - *pRequiredBufferSize = res.requiredBufferSize; - } - - // requiredBufferSize is with null terminator, but buffer is stored without - // null terminator. Determine if we have enough data to answer the query - // losslessly. - // Note that requiredBufferSize is always set by recording side if we had - // enough information to determine it. - bool haveFullBuffer = (res.requiredBufferSize != UINT_MAX) && ((res.stringBufferSize + 1) >= res.requiredBufferSize); - if (!haveFullBuffer && (bufferSize > static_cast(res.stringBufferSize) + 1)) - { - LogException(EXCEPTIONCODE_MC, "SuperPMI assertion failed (not enough buffer data for %s key %016" PRIx64 ")", name, handle); - } - - size_t bytesWritten = 0; - if ((buffer != nullptr) && (bufferSize > 0)) - { - bytesWritten = min(bufferSize - 1, (size_t)res.stringBufferSize); - if (bytesWritten > 0) - { - // The "full buffer" check above ensures this given that - // res.stringBuffer == UINT_MAX implies res.stringBufferSize == 0. - Assert(res.stringBuffer != UINT_MAX); - char* storedBuffer = (char*)map->GetBuffer(res.stringBuffer); - memcpy(buffer, storedBuffer, bytesWritten); - } - buffer[bytesWritten] = '\0'; - } - - return bytesWritten; -} - -void MethodContext::recPrintObjectDescription(CORINFO_OBJECT_HANDLE handle, char* buffer, size_t bufferSize, size_t* pRequiredBufferSize, size_t bytesWritten) -{ - recPrint("PrintObjectDescription", PrintObjectDescription, CastHandle(handle), buffer, bufferSize, pRequiredBufferSize, bytesWritten); -} -void MethodContext::dmpPrintObjectDescription(DWORDLONG key, const Agnostic_PrintResult& value) -{ - dmpPrint("PrintObjectDescription", PrintObjectDescription, key, value); -} -size_t MethodContext::repPrintObjectDescription(CORINFO_OBJECT_HANDLE handle, char* buffer, size_t bufferSize, size_t* pRequiredBufferSize) -{ - return repPrint("PrintObjectDescription", PrintObjectDescription, CastHandle(handle), buffer, bufferSize, pRequiredBufferSize); -} - -void MethodContext::recPrintClassName(CORINFO_CLASS_HANDLE cls, char* buffer, size_t bufferSize, size_t* pRequiredBufferSize, size_t bytesWritten) -{ - recPrint("PrintClassName", PrintClassName, CastHandle(cls), buffer, bufferSize, pRequiredBufferSize, bytesWritten); -} -void MethodContext::dmpPrintClassName(DWORDLONG key, const Agnostic_PrintResult& value) -{ - dmpPrint("PrintClassName", PrintClassName, key, value); -} -size_t MethodContext::repPrintClassName(CORINFO_CLASS_HANDLE cls, char* buffer, size_t bufferSize, size_t* pRequiredBufferSize) -{ - return repPrint("PrintClassName", PrintClassName, CastHandle(cls), buffer, bufferSize, pRequiredBufferSize); -} - -void MethodContext::recPrintFieldName(CORINFO_FIELD_HANDLE fld, char* buffer, size_t bufferSize, size_t* pRequiredBufferSize, size_t bytesWritten) -{ - recPrint("PrintFieldName", PrintFieldName, CastHandle(fld), buffer, bufferSize, pRequiredBufferSize, bytesWritten); -} -void MethodContext::dmpPrintFieldName(DWORDLONG key, const Agnostic_PrintResult& value) -{ - dmpPrint("PrintFieldName", PrintFieldName, key, value); -} -size_t MethodContext::repPrintFieldName(CORINFO_FIELD_HANDLE fld, char* buffer, size_t bufferSize, size_t* pRequiredBufferSize) -{ - return repPrint("PrintFieldName", PrintFieldName, CastHandle(fld), buffer, bufferSize, pRequiredBufferSize); -} - -void MethodContext::recPrintMethodName(CORINFO_METHOD_HANDLE meth, char* buffer, size_t bufferSize, size_t* pRequiredBufferSize, size_t bytesWritten) -{ - recPrint("PrintMethodName", PrintMethodName, CastHandle(meth), buffer, bufferSize, pRequiredBufferSize, bytesWritten); -} -void MethodContext::dmpPrintMethodName(DWORDLONG key, const Agnostic_PrintResult& value) -{ - dmpPrint("PrintMethodName", PrintMethodName, key, value); -} -size_t MethodContext::repPrintMethodName(CORINFO_METHOD_HANDLE meth, char* buffer, size_t bufferSize, size_t* pRequiredBufferSize) -{ - return repPrint("PrintMethodName", PrintMethodName, CastHandle(meth), buffer, bufferSize, pRequiredBufferSize); -} - -void MethodContext::recGetTailCallHelpers( - CORINFO_RESOLVED_TOKEN* callToken, - CORINFO_SIG_INFO* sig, - CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, - CORINFO_TAILCALL_HELPERS* pResult) -{ - if (GetTailCallHelpers == nullptr) - GetTailCallHelpers = new LightWeightMap(); - - Agnostic_GetTailCallHelpers key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.callToken = SpmiRecordsHelper::StoreAgnostic_CORINFO_RESOLVED_TOKEN(callToken, GetTailCallHelpers); - key.sig = SpmiRecordsHelper::StoreAgnostic_CORINFO_SIG_INFO(*sig, GetTailCallHelpers, SigInstHandleMap); - key.flags = (DWORD)flags; - - Agnostic_CORINFO_TAILCALL_HELPERS value; - ZeroMemory(&value, sizeof(value)); - value.result = pResult != nullptr; - if (pResult != nullptr) - { - value.flags = (DWORD)pResult->flags; - value.hStoreArgs = CastHandle(pResult->hStoreArgs); - value.hCallTarget = CastHandle(pResult->hCallTarget); - value.hDispatcher = CastHandle(pResult->hDispatcher); - } - - GetTailCallHelpers->Add(key, value); - DEBUG_REC(dmpGetTailCallHelpers(key, value)); -} - -void MethodContext::dmpGetTailCallHelpers(const Agnostic_GetTailCallHelpers& key, const Agnostic_CORINFO_TAILCALL_HELPERS& value) -{ - printf("GetTailCallHelpers key callToken-%s sig-%s flg-%08X", - SpmiDumpHelper::DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.callToken).c_str(), - SpmiDumpHelper::DumpAgnostic_CORINFO_SIG_INFO(key.sig, GetTailCallHelpers, SigInstHandleMap).c_str(), - key.flags); - printf(", value result-%s flg-%08X hStoreArgs-%016" PRIX64 " hCallTarget-%016" PRIX64 " hDispatcher-%016" PRIX64 "", - value.result ? "true" : "false", - value.flags, - value.hStoreArgs, - value.hCallTarget, - value.hDispatcher); -} - -bool MethodContext::repGetTailCallHelpers( - CORINFO_RESOLVED_TOKEN* callToken, - CORINFO_SIG_INFO* sig, - CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, - CORINFO_TAILCALL_HELPERS* pResult) -{ - AssertMapExistsNoMessage(GetTailCallHelpers); - - Agnostic_GetTailCallHelpers key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.callToken = SpmiRecordsHelper::RestoreAgnostic_CORINFO_RESOLVED_TOKEN(callToken, GetTailCallHelpers); - key.sig = SpmiRecordsHelper::RestoreAgnostic_CORINFO_SIG_INFO(*sig, GetTailCallHelpers, SigInstHandleMap); - key.flags = (DWORD)flags; - - Agnostic_CORINFO_TAILCALL_HELPERS value = LookupByKeyOrMissNoMessage(GetTailCallHelpers, key); - - DEBUG_REP(dmpGetTailCallHelpers(key, value)); - - if (!value.result) - return false; - - pResult->flags = (CORINFO_TAILCALL_HELPERS_FLAGS)value.flags; - pResult->hStoreArgs = (CORINFO_METHOD_HANDLE)value.hStoreArgs; - pResult->hCallTarget = (CORINFO_METHOD_HANDLE)value.hCallTarget; - pResult->hDispatcher = (CORINFO_METHOD_HANDLE)value.hDispatcher; - return true; -} - - -void MethodContext::recGetAsyncResumptionStub(CORINFO_METHOD_HANDLE hnd, void* entryPoint) -{ - if (GetAsyncResumptionStub == nullptr) - GetAsyncResumptionStub = new LightWeightMap(); - - DLDL result; - result.A = CastHandle(hnd); - result.B = CastPointer(entryPoint); - GetAsyncResumptionStub->Add(0, result); - DEBUG_REC(dmpGetAsyncResumptionStub(CastHandle(hnd), CastPointer(entryPoint))); -} -void MethodContext::dmpGetAsyncResumptionStub(DWORD key, const DLDL& value) -{ - printf("GetAsyncResumptionStub key-%u, hnd-%016" PRIX64 ", entrypoint-%016" PRIX64, key, value.A, value.B); -} -CORINFO_METHOD_HANDLE MethodContext::repGetAsyncResumptionStub(void** entryPoint) -{ - DLDL value = LookupByKeyOrMissNoMessage(GetAsyncResumptionStub, 0); - *entryPoint = (void*)value.B; - return (CORINFO_METHOD_HANDLE)value.A; -} - -void MethodContext::recGetContinuationType(size_t dataSize, - bool* objRefs, - size_t objRefsSize, - CORINFO_CLASS_HANDLE result) -{ - if (GetContinuationType == nullptr) - { - GetContinuationType = new LightWeightMap(); - } - - Agnostic_GetContinuationTypeIn key; - ZeroMemory(&key, sizeof(key)); - key.dataSize = (DWORDLONG)dataSize; - key.objRefs = GetContinuationType->AddBuffer((unsigned char*)objRefs, (unsigned)objRefsSize); - key.objRefsSize = (DWORD)objRefsSize; - - DWORDLONG value = CastHandle(result); - - GetContinuationType->Add(key, value); - DEBUG_REC(dmpGetContinuationType(key, value)); -} - -void MethodContext::dmpGetContinuationType(const Agnostic_GetContinuationTypeIn& key, DWORDLONG value) -{ - printf("GetContinuationType dataSize-%016" PRIX64 ", objRefs-%u, handle-%016" PRIX64, - key.dataSize, key.objRefs, value); -} - -CORINFO_CLASS_HANDLE MethodContext::repGetContinuationType(size_t dataSize, - bool* objRefs, - size_t objRefsSize) -{ - AssertMapExistsNoMessage(GetContinuationType); - - Agnostic_GetContinuationTypeIn key; - ZeroMemory(&key, sizeof(key)); - key.dataSize = (DWORDLONG)dataSize; - key.objRefs = (DWORD)GetContinuationType->Contains((unsigned char*)objRefs, (unsigned)objRefsSize); - key.objRefsSize = (DWORD)objRefsSize; - - DWORDLONG value; - int index = GetContinuationType->GetIndex(key); - if (index == -1) - { - // This handle is more or less opaque, we can tolerate a miss here and - // just fake up handle. Otherwise SPMI will be useless for - // any async change that results in changes in live state. - value = CONTINUATION_TYPE_PSEUDO_CLASS_HANDLE; - } - else - { - value = GetContinuationType->GetItem(index); - } - - DEBUG_REP(dmpGetContinuationType(key, value)); - - return (CORINFO_CLASS_HANDLE)value; -} - -void MethodContext::recUpdateEntryPointForTailCall( - const CORINFO_CONST_LOOKUP& origEntryPoint, - const CORINFO_CONST_LOOKUP& newEntryPoint) -{ - if (UpdateEntryPointForTailCall == nullptr) - UpdateEntryPointForTailCall = new LightWeightMap(); - - Agnostic_CORINFO_CONST_LOOKUP key = SpmiRecordsHelper::StoreAgnostic_CORINFO_CONST_LOOKUP(&origEntryPoint); - Agnostic_CORINFO_CONST_LOOKUP value = SpmiRecordsHelper::StoreAgnostic_CORINFO_CONST_LOOKUP(&newEntryPoint); - UpdateEntryPointForTailCall->Add(key, value); - DEBUG_REC(dmpUpdateEntryPointForTailCall(key, value)); -} - -void MethodContext::dmpUpdateEntryPointForTailCall( - const Agnostic_CORINFO_CONST_LOOKUP& origEntryPoint, - const Agnostic_CORINFO_CONST_LOOKUP& newEntryPoint) -{ - printf("UpdateEntryPointForTailcall orig=%s new=%s", - SpmiDumpHelper::DumpAgnostic_CORINFO_CONST_LOOKUP(origEntryPoint).c_str(), - SpmiDumpHelper::DumpAgnostic_CORINFO_CONST_LOOKUP(newEntryPoint).c_str()); -} - -void MethodContext::repUpdateEntryPointForTailCall(CORINFO_CONST_LOOKUP* entryPoint) -{ - AssertMapExistsNoMessage(UpdateEntryPointForTailCall); - - Agnostic_CORINFO_CONST_LOOKUP key = SpmiRecordsHelper::StoreAgnostic_CORINFO_CONST_LOOKUP(entryPoint); - Agnostic_CORINFO_CONST_LOOKUP value = LookupByKeyOrMissNoMessage(UpdateEntryPointForTailCall, key); - - DEBUG_REP(dmpUpdateEntryPointForTailCall(key, value)); - - *entryPoint = SpmiRecordsHelper::RestoreCORINFO_CONST_LOOKUP(value); -} - -void MethodContext::recGetMethodDefFromMethod(CORINFO_METHOD_HANDLE hMethod, mdMethodDef result) -{ - if (GetMethodDefFromMethod == nullptr) - GetMethodDefFromMethod = new LightWeightMap(); - - DWORDLONG key = CastHandle(hMethod); - DWORD value = (DWORD)result; - GetMethodDefFromMethod->Add(key, value); - DEBUG_REC(dmpGetMethodDefFromMethod(key, value)); -} -void MethodContext::dmpGetMethodDefFromMethod(DWORDLONG key, DWORD value) -{ - printf("GetMethodDefFromMethod key ftn-%016" PRIX64 ", value res-%u", key, value); -} -mdMethodDef MethodContext::repGetMethodDefFromMethod(CORINFO_METHOD_HANDLE hMethod) -{ - // Since this is diagnostic, fake up a result if one wasn't recorded. - if (GetMethodDefFromMethod == nullptr) - return (mdMethodDef)0x06000000; - - DWORDLONG key = CastHandle(hMethod); - - int index = GetMethodDefFromMethod->GetIndex(key); - if (index < 0) - return (mdMethodDef)0x06000001; - - DWORD value = GetMethodDefFromMethod->Get(key); - DEBUG_REP(dmpGetMethodDefFromMethod(key, value)); - return (mdMethodDef)value; -} - -void MethodContext::recCheckMethodModifier(CORINFO_METHOD_HANDLE hMethod, LPCSTR modifier, bool fOptional, bool result) -{ - if (CheckMethodModifier == nullptr) - CheckMethodModifier = new LightWeightMap(); - - Agnostic_CheckMethodModifier key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.hMethod = CastHandle(hMethod); - // If the input matches something already in the buffer, just re-use that slot.. easier than searching for a soft - // key on rep. - if (modifier != nullptr) - key.modifier = - (DWORD)CheckMethodModifier->AddBuffer((unsigned char*)modifier, (unsigned int)strlen(modifier) + 1); - else - key.modifier = (DWORD)-1; - - key.fOptional = (DWORD)fOptional; - - DWORD value = result ? 1 : 0; - CheckMethodModifier->Add(key, value); - DEBUG_REC(dmpCheckMethodModifier(key, value)); -} -void MethodContext::dmpCheckMethodModifier(const Agnostic_CheckMethodModifier& key, DWORD value) -{ - printf("CheckMethodModifier key, ftn-%016" PRIX64 " mod-'%s' opt-%u, value res-%u", key.hMethod, - (unsigned char*)CheckMethodModifier->GetBuffer(key.modifier), key.fOptional, value); - CheckMethodModifier->Unlock(); -} -bool MethodContext::repCheckMethodModifier(CORINFO_METHOD_HANDLE hMethod, LPCSTR modifier, bool fOptional) -{ - Agnostic_CheckMethodModifier key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.hMethod = CastHandle(hMethod); - if (modifier != nullptr) - key.modifier = - (DWORD)CheckMethodModifier->Contains((unsigned char*)modifier, (unsigned int)strlen(modifier) + 1); - else - key.modifier = (DWORD)-1; - - key.fOptional = (DWORD)fOptional; - - DWORD value = LookupByKeyOrMissNoMessage(CheckMethodModifier, key); - - DEBUG_REP(dmpCheckMethodModifier(key, value)); - return value != 0; -} - -void MethodContext::recGetArrayRank(CORINFO_CLASS_HANDLE cls, unsigned result) -{ - if (GetArrayRank == nullptr) - GetArrayRank = new LightWeightMap(); - - DWORDLONG key = CastHandle(cls); - DWORD value = (DWORD)result; - GetArrayRank->Add(key, value); - DEBUG_REC(dmpGetArrayRank(key, value)); -} -void MethodContext::dmpGetArrayRank(DWORDLONG key, DWORD value) -{ - printf("GetArrayRank key %016" PRIX64 ", value %u", key, value); -} -unsigned MethodContext::repGetArrayRank(CORINFO_CLASS_HANDLE cls) -{ - DWORDLONG key = CastHandle(cls); - DWORD value = LookupByKeyOrMiss(GetArrayRank, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetArrayRank(key, value)); - unsigned result = (unsigned)value; - return result; -} - -void MethodContext::recGetArrayIntrinsicID(CORINFO_METHOD_HANDLE hMethod, CorInfoArrayIntrinsic result) -{ - if (GetArrayIntrinsicID == nullptr) - GetArrayIntrinsicID = new LightWeightMap(); - - DWORDLONG key = CastHandle(hMethod); - DWORD value = (DWORD)result; - GetArrayIntrinsicID->Add(key, value); - DEBUG_REC(dmpGetArrayIntrinsicID(key, value)); -} -void MethodContext::dmpGetArrayIntrinsicID(DWORDLONG key, DWORD value) -{ - printf("GetArrayIntrinsicID key %016" PRIX64 ", value %u", key, value); -} -CorInfoArrayIntrinsic MethodContext::repGetArrayIntrinsicID(CORINFO_METHOD_HANDLE hMethod) -{ - DWORDLONG key = CastHandle(hMethod); - DWORD value = LookupByKeyOrMiss(GetArrayIntrinsicID, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetArrayIntrinsicID(key, value)); - CorInfoArrayIntrinsic result = (CorInfoArrayIntrinsic)value; - return result; -} - -void MethodContext::recIsFieldStatic(CORINFO_FIELD_HANDLE fhld, bool result) -{ - if (IsFieldStatic == nullptr) - IsFieldStatic = new LightWeightMap(); - - DWORDLONG key = CastHandle(fhld); - DWORD value = result ? 1 : 0; - IsFieldStatic->Add(key, value); - DEBUG_REC(dmpIsFieldStatic(key, value)); -} -void MethodContext::dmpIsFieldStatic(DWORDLONG key, DWORD value) -{ - printf("IsFieldStatic key %016" PRIX64 ", value %u", key, value); -} -bool MethodContext::repIsFieldStatic(CORINFO_FIELD_HANDLE fhld) -{ - DWORDLONG key = CastHandle(fhld); - DWORD value = LookupByKeyOrMiss(IsFieldStatic, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpIsFieldStatic(key, value)); - return value != 0; -} - -void MethodContext::recGetArrayOrStringLength(CORINFO_OBJECT_HANDLE objHandle, int result) -{ - if (GetArrayOrStringLength == nullptr) - GetArrayOrStringLength = new LightWeightMap(); - - DWORDLONG key = CastHandle(objHandle); - DWORD value = (DWORD)result; - GetArrayOrStringLength->Add(key, value); - DEBUG_REC(dmpGetArrayOrStringLength(key, value)); -} -void MethodContext::dmpGetArrayOrStringLength(DWORDLONG key, DWORD value) -{ - printf("GetArrayOrStringLength key %016" PRIX64 ", value %u", key, value); -} -int MethodContext::repGetArrayOrStringLength(CORINFO_OBJECT_HANDLE objHandle) -{ - DWORDLONG key = CastHandle(objHandle); - DWORD value = LookupByKeyOrMiss(GetArrayOrStringLength, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetArrayOrStringLength(key, value)); - return (int)value; -} - -void MethodContext::recGetIntConfigValue(const char* name, int defaultValue, int result) -{ - if (GetIntConfigValue == nullptr) - GetIntConfigValue = new LightWeightMap(); - - AssertCodeMsg(name != nullptr, EXCEPTIONCODE_MC, "Name can not be nullptr"); - - Agnostic_ConfigIntInfo key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - - DWORD index = - (DWORD)GetIntConfigValue->AddBuffer((unsigned char*)name, sizeof(char) * ((unsigned int)strlen(name) + 1)); - - key.nameIndex = index; - key.defaultValue = defaultValue; - - GetIntConfigValue->Add(key, result); - DEBUG_REC(dmpGetIntConfigValue(key, result)); -} - -void MethodContext::dmpGetIntConfigValue(const Agnostic_ConfigIntInfo& key, int value) -{ - const char* name = (const char*)GetIntConfigValue->GetBuffer(key.nameIndex); - printf("GetIntConfigValue name %s, default value %d, value %d", name, key.defaultValue, value); - GetIntConfigValue->Unlock(); -} - -int MethodContext::repGetIntConfigValue(const char* name, int defaultValue) -{ - if (ignoreStoredConfig) - return defaultValue; - - if (GetIntConfigValue == nullptr) - return defaultValue; - - AssertCodeMsg(name != nullptr, EXCEPTIONCODE_MC, "Name can not be nullptr"); - - Agnostic_ConfigIntInfo key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - - size_t nameLenInBytes = sizeof(char) * (strlen(name) + 1); - int nameIndex = GetIntConfigValue->Contains((unsigned char*)name, (unsigned int)nameLenInBytes); - if (nameIndex == -1) // config name not in map - return defaultValue; - - key.nameIndex = (DWORD)nameIndex; - key.defaultValue = defaultValue; - - int index = GetIntConfigValue->GetIndex(key); - if (index == -1) - { - // default value has changed - return defaultValue; - } - - DWORD value = GetIntConfigValue->GetItem(index); - DEBUG_REP(dmpGetIntConfigValue(key, value)); - return (int)value; -} - -void MethodContext::recGetStringConfigValue(const char* name, const char* result) -{ - if (GetStringConfigValue == nullptr) - GetStringConfigValue = new LightWeightMap(); - - AssertCodeMsg(name != nullptr, EXCEPTIONCODE_MC, "Name can not be nullptr"); - - DWORD nameIndex = (DWORD)GetStringConfigValue->AddBuffer((unsigned char*)name, - sizeof(char) * ((unsigned int)strlen(name) + 1)); - - DWORD resultIndex = (DWORD)-1; - if (result != nullptr) - resultIndex = (DWORD)GetStringConfigValue->AddBuffer((unsigned char*)result, - sizeof(char) * ((unsigned int)strlen(result) + 1)); - - GetStringConfigValue->Add(nameIndex, resultIndex); - DEBUG_REC(dmpGetStringConfigValue(nameIndex, resultIndex)); -} - -void MethodContext::dmpGetStringConfigValue(DWORD nameIndex, DWORD resultIndex) -{ - const char* name = (const char*)GetStringConfigValue->GetBuffer(nameIndex); - const char* result = (const char*)GetStringConfigValue->GetBuffer(resultIndex); - printf("GetStringConfigValue name %s, result %s", name, result); - GetStringConfigValue->Unlock(); -} - -const char* MethodContext::repGetStringConfigValue(const char* name) -{ - if (ignoreStoredConfig) - return nullptr; - - if (GetStringConfigValue == nullptr) - return nullptr; - - AssertCodeMsg(name != nullptr, EXCEPTIONCODE_MC, "Name can not be nullptr"); - - size_t nameLenInBytes = sizeof(char) * (strlen(name) + 1); - int nameIndex = GetStringConfigValue->Contains((unsigned char*)name, (unsigned int)nameLenInBytes); - if (nameIndex == -1) // config name not in map - return nullptr; - - int resultIndex = LookupByKeyOrMissNoMessage(GetStringConfigValue, nameIndex); - - const char* value = (const char*)GetStringConfigValue->GetBuffer(resultIndex); - - DEBUG_REP(dmpGetStringConfigValue(nameIndex, (DWORD)resultIndex)); - return value; -} - -void MethodContext::recGetSpecialCopyHelper(CORINFO_CLASS_HANDLE type, CORINFO_METHOD_HANDLE helper) -{ - if (GetSpecialCopyHelper == nullptr) - GetSpecialCopyHelper = new LightWeightMap(); - - DWORDLONG key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key = CastHandle(type); - - DWORDLONG value = CastHandle(helper); - GetSpecialCopyHelper->Add(key, value); - DEBUG_REC(dmpGetSpecialCopyHelper(key, value)); -} - -void MethodContext::dmpGetSpecialCopyHelper(DWORDLONG key, DWORDLONG value) -{ - printf("getSpecialCopyHelper key %016" PRIX64 ", value %016" PRIX64 "", key, value); -} - -CORINFO_METHOD_HANDLE MethodContext::repGetSpecialCopyHelper(CORINFO_CLASS_HANDLE type) -{ - DWORDLONG key = CastHandle(type); - DWORDLONG value = LookupByKeyOrMiss(GetSpecialCopyHelper, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetSpecialCopyHelper(key, value)); - return (CORINFO_METHOD_HANDLE)value; -} - -void MethodContext::recGetWasmTypeSymbol(CorInfoWasmType* types, size_t typesSize, CORINFO_WASM_TYPE_SYMBOL_HANDLE result) -{ - if (GetWasmTypeSymbol == nullptr) - GetWasmTypeSymbol = new LightWeightMap(); - - Agnostic_GetWasmTypeSymbol key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.types = (DWORD)GetWasmTypeSymbol->AddBuffer((unsigned char*)types, (unsigned)(sizeof(CorInfoWasmType) * typesSize)); - key.typesSize = (DWORD)typesSize; - - DWORDLONG value = CastHandle(result); - GetWasmTypeSymbol->Add(key, value); - DEBUG_REC(dmpGetWasmTypeSymbol(key, value)); -} - -void MethodContext::dmpGetWasmTypeSymbol(const Agnostic_GetWasmTypeSymbol& key, DWORDLONG value) -{ - printf("getWasmTypeSymbol types %u, typesSize %u, value %016" PRIX64 "", key.types, key.typesSize, value); -} - -CORINFO_WASM_TYPE_SYMBOL_HANDLE MethodContext::repGetWasmTypeSymbol(CorInfoWasmType* types, size_t typesSize) -{ - if (GetWasmTypeSymbol == nullptr) - { - // Fake up a result so we can cross-replay onto wasm - return (CORINFO_WASM_TYPE_SYMBOL_HANDLE)0xbadcab; - } - - AssertMapExistsNoMessage(GetWasmTypeSymbol); - - Agnostic_GetWasmTypeSymbol key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.types = (DWORD)GetWasmTypeSymbol->Contains((unsigned char*)types, (unsigned)(sizeof(CorInfoWasmType) * typesSize)); - key.typesSize = (DWORD)typesSize; - - DWORDLONG value = LookupByKeyOrMiss(GetWasmTypeSymbol, key, ": types %u, typesSize %u", key.types, key.typesSize); - DEBUG_REP(dmpGetWasmTypeSymbol(key, value)); - return (CORINFO_WASM_TYPE_SYMBOL_HANDLE)value; -} - -void MethodContext::dmpSigInstHandleMap(DWORD key, DWORDLONG value) -{ - printf("SigInstHandleMap key %u, value %016" PRIX64 "", key, value); -} - -int MethodContext::dumpMethodIdentityInfoToBuffer(char* buff, int len, bool ignoreMethodName /* = false */, CORINFO_METHOD_INFO* optInfo /* = nullptr */, unsigned optFlags /* = 0 */) -{ - if (len < METHOD_IDENTITY_INFO_SIZE) - return -1; - - // Obtain the Method Info structure for this method - CORINFO_METHOD_INFO info; - CORINFO_METHOD_INFO* pInfo = nullptr; - unsigned flags = 0; - - if (optInfo != nullptr) - { - // Use the info we've already retrieved from repCompileMethod(). - pInfo = optInfo; - flags = optFlags; - } - else - { - CORINFO_OS os; - repCompileMethod(&info, &flags, &os); - pInfo = &info; - } - - // Obtain the jit flags and ISA flags. - CORJIT_FLAGS corJitFlags; - repGetJitFlags(&corJitFlags, sizeof(corJitFlags)); - - char* obuff = buff; - - // Add the Method Signature. Be careful about potentially huge method signatures; truncate if necessary. - const char* methodFullName = CallUtils::GetMethodFullName(this, pInfo->ftn, pInfo->args, ignoreMethodName); - int t = _snprintf_s(buff, len - METHOD_IDENTITY_INFO_NON_NAME_RESERVE, _TRUNCATE, "%s -- ", methodFullName); - if (t == -1) - { - // We truncated the name string, meaning we wrote exactly `len - METHOD_IDENTITY_INFO_NON_NAME_RESERVE` characters - // (including the terminating null). We advance the buffer pointer by this amount, not including that terminating null. - t = len - METHOD_IDENTITY_INFO_NON_NAME_RESERVE - 1; - } - buff += t; - len -= t; - - // Add Calling convention information, CorInfoOptions, CorInfoRegionKind, jit flags, and ISA flags. - t = sprintf_s(buff, len, "CallingConvention: %d, CorInfoOptions: %d, CorInfoRegionKind: %d, JitFlags %016" PRIx64 ", ISA Flags", pInfo->args.callConv, - pInfo->options, pInfo->regionKind, corJitFlags.GetFlagsRaw()); - buff += t; - len -= t; - - uint64_t *raw = corJitFlags.GetInstructionSetFlagsRaw(); - const int flagsFieldCount = corJitFlags.GetInstructionFlagsFieldCount(); - for (int i = flagsFieldCount - 1; i >= 0; i--) - { - t = sprintf_s(buff, len, " %016" PRIX64 "", raw[i]); - buff += t; - len -= t; - } - - // Hash the IL Code for this method and append it to the ID info - char ilHash[MM3_HASH_BUFFER_SIZE]; - dumpHashToBuffer(pInfo->ILCode, pInfo->ILCodeSize, ilHash, MM3_HASH_BUFFER_SIZE); - t = sprintf_s(buff, len, " ILCode Hash: %s", ilHash); - buff += t; - len -= t; - - // Fingerprint the root method PGO data (if any) and append it to the ID info. - // - if ((GetPgoInstrumentationResults != nullptr) && - (GetPgoInstrumentationResults->GetIndex(CastHandle(pInfo->ftn)) != -1)) - { - ICorJitInfo::PgoInstrumentationSchema* schema = nullptr; - UINT32 schemaCount = 0; - BYTE* schemaData = nullptr; - ICorJitInfo::PgoSource pgoSource = ICorJitInfo::PgoSource::Unknown; - bool dynamicPgo = false; - HRESULT pgoHR = repGetPgoInstrumentationResults(pInfo->ftn, &schema, &schemaCount, &schemaData, &pgoSource, &dynamicPgo); - - size_t minOffset = (size_t) ~0; - size_t maxOffset = 0; - uint64_t totalCount = 0; - - if (SUCCEEDED(pgoHR)) - { - // Locate the range of the data. - // - for (UINT32 i = 0; i < schemaCount; i++) - { - size_t start = schema[i].Offset; - size_t end; - switch (schema[i].InstrumentationKind) - { - case ICorJitInfo::PgoInstrumentationKind::BasicBlockIntCount: - case ICorJitInfo::PgoInstrumentationKind::EdgeIntCount: - totalCount += *(uint32_t*)(schemaData + schema[i].Offset); - end = start + 4; - break; - case ICorJitInfo::PgoInstrumentationKind::BasicBlockLongCount: - case ICorJitInfo::PgoInstrumentationKind::EdgeLongCount: - totalCount += *(uint64_t*)(schemaData + schema[i].Offset); - end = start + 8; - break; - default: - continue; - } - - if (start < minOffset) - { - minOffset = start; - } - - if (end > maxOffset) - { - maxOffset = end; - } - } - - // Hash the counter values. - // - if (minOffset < maxOffset) - { - char pgoHash[MM3_HASH_BUFFER_SIZE]; - dumpHashToBuffer(schemaData + minOffset, (int)(maxOffset - minOffset), pgoHash, - MM3_HASH_BUFFER_SIZE); - - t = sprintf_s(buff, len, " Pgo Counters %u, Count %" PRIu64 ", Hash: %s", schemaCount, totalCount, pgoHash); - buff += t; - len -= t; - } - } - } - - return (int)(buff - obuff); -} - -int MethodContext::dumpMethodHashToBuffer(char* buff, int len, bool ignoreMethodName /* = false */, CORINFO_METHOD_INFO* optInfo /* = nullptr */, unsigned optFlags /* = 0 */) -{ - char bufferIdentityInfo[METHOD_IDENTITY_INFO_SIZE]; - - int cbLen = dumpMethodIdentityInfoToBuffer(bufferIdentityInfo, METHOD_IDENTITY_INFO_SIZE, ignoreMethodName, optInfo, optFlags); - - if (cbLen < 0) - return cbLen; - - cbLen = dumpHashToBuffer((BYTE*)bufferIdentityInfo, cbLen, buff, len); - - return cbLen; -} - -int MethodContext::dumpHashToBuffer(BYTE* pBuffer, int bufLen, char* hash, int hashLen) -{ - return Hash::HashBuffer(pBuffer, bufLen, hash, hashLen); -} - -bool MethodContext::hasPgoData(bool& hasEdgeProfile, bool& hasClassProfile, bool& hasMethodProfile, bool& hasLikelyClass, bool& hasLikelyMethod, ICorJitInfo::PgoSource& pgoSource) -{ - hasEdgeProfile = false; - hasClassProfile = false; - hasMethodProfile = false; - hasLikelyClass = false; - hasLikelyMethod = false; - - // Obtain the Method Info structure for this method - CORINFO_METHOD_INFO info; - unsigned flags = 0; - CORINFO_OS os; - repCompileMethod(&info, &flags, &os); - - if ((GetPgoInstrumentationResults != nullptr) && - (GetPgoInstrumentationResults->GetIndex(CastHandle(info.ftn)) != -1)) - { - ICorJitInfo::PgoInstrumentationSchema* schema = nullptr; - UINT32 schemaCount = 0; - BYTE* schemaData = nullptr; - bool dynamicPgo; - HRESULT pgoHR = repGetPgoInstrumentationResults(info.ftn, &schema, &schemaCount, &schemaData, &pgoSource, &dynamicPgo); - - if (SUCCEEDED(pgoHR)) - { - for (UINT32 i = 0; i < schemaCount; i++) - { - hasEdgeProfile |= (schema[i].InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::EdgeIntCount); - hasEdgeProfile |= (schema[i].InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::EdgeLongCount); - hasClassProfile |= (schema[i].InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::HandleHistogramTypes); - hasMethodProfile |= (schema[i].InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::HandleHistogramMethods); - hasLikelyClass |= (schema[i].InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::GetLikelyClass); - hasLikelyMethod |= (schema[i].InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::GetLikelyMethod); - - if (hasEdgeProfile && hasClassProfile && hasLikelyClass && hasLikelyMethod) - { - break; - } - } - - return true; - } - } - - return false; -} - -MethodContext::Environment MethodContext::cloneEnvironment() -{ - MethodContext::Environment env; - if (GetIntConfigValue != nullptr) - { - env.getIntConfigValue = new LightWeightMap(*GetIntConfigValue); - } - if (GetStringConfigValue != nullptr) - { - env.getStringConfigValue = new LightWeightMap(*GetStringConfigValue); - } - return env; -} - -// Check that there is a difference between the current environment variables maps and the prevEnv. -bool MethodContext::WasEnvironmentChanged(const Environment& prevEnv) -{ - if (!IsEnvironmentHeaderEqual(prevEnv)) - { - return true; - } - if (!IsEnvironmentContentEqual(prevEnv)) - { - return true; - } - return false; -} - -// Check that environment maps headers are equal to the prevEnv maps headers. -bool MethodContext::IsEnvironmentHeaderEqual(const Environment& prevEnv) -{ - if (!AreLWMHeadersEqual(prevEnv.getIntConfigValue, GetIntConfigValue)) - { - return false; - } - if (!AreLWMHeadersEqual(prevEnv.getStringConfigValue, GetStringConfigValue)) - { - return false; - } - return true; -} - -// Check that environment maps content is equal to the prevEnv content. -bool MethodContext::IsEnvironmentContentEqual(const Environment& prevEnv) -{ - if (!IsIntConfigContentEqual(prevEnv.getIntConfigValue, GetIntConfigValue)) - { - return false; - } - if (!IsStringContentEqual(prevEnv.getStringConfigValue, GetStringConfigValue)) - { - return false; - } - return true; -} - -// Check pointers to be both initizlized or null and number of keys to be equal. -template -bool MethodContext::AreLWMHeadersEqual(LightWeightMap* prev, LightWeightMap* curr) -{ - if (prev == nullptr && curr == nullptr) - { - return true; - } - if (prev != nullptr && curr != nullptr) - { - if (prev->GetCount() == curr->GetCount()) - { - return true; - } - } - return false; -} - -bool MethodContext::IsIntConfigContentEqual(LightWeightMap* prev, - LightWeightMap* curr) -{ - if (prev != nullptr && curr != nullptr) - { - if (prev->GetCount() != curr->GetCount()) - { - return false; - } - - for (unsigned i = 0; i < prev->GetCount(); ++i) - { - DWORD currValue = curr->GetItem(i); - DWORD prevValue = prev->GetItem(i); - if (currValue != prevValue) - { - return false; - } - - Agnostic_ConfigIntInfo currKey = curr->GetKey(i); - Agnostic_ConfigIntInfo prevKey = prev->GetKey(i); - - if (currKey.defaultValue != prevKey.defaultValue) - { - return false; - } - - DWORD currNameIndex = currKey.nameIndex; - LPCSTR currName = (LPCSTR)curr->GetBuffer(currNameIndex); - DWORD prevNameIndex = prevKey.nameIndex; - LPCSTR prevName = (LPCSTR)prev->GetBuffer(currNameIndex); - if (strcmp(currName, prevName) != 0) - { - return false; - } - } - return true; - } - else - { - return (prev == curr); - } -} - -bool MethodContext::IsStringContentEqual(LightWeightMap* prev, LightWeightMap* curr) -{ - if (prev != nullptr && curr != nullptr) - { - if (prev->GetCount() != curr->GetCount()) - { - return false; - } - - for (unsigned i = 0; i < curr->GetCount(); ++i) - { - DWORD currKeyIndex = curr->GetKey(i); - LPCSTR currKey = (LPCSTR)curr->GetBuffer(currKeyIndex); - DWORD prevKeyIndex = prev->GetKey(i); - LPCSTR prevKey = (LPCSTR)prev->GetBuffer(prevKeyIndex); - if (strcmp(currKey, prevKey) != 0) - { - return false; - } - - DWORD currValueIndex = curr->GetItem(i); - LPCSTR currValue = (LPCSTR)curr->GetBuffer(currValueIndex); - DWORD prevValueIndex = prev->GetItem(i); - LPCSTR prevValue = (LPCSTR)prev->GetBuffer(prevValueIndex); - if (strcmp(currValue, prevValue) != 0) - { - return false; - } - } - return true; - } - else - { - return (prev == curr); - } -} - -void MethodContext::recCanValueClassInstancePointerEscape(CORINFO_METHOD_HANDLE ftn, bool result) -{ - if (CanValueClassInstancePointerEscape == nullptr) - CanValueClassInstancePointerEscape = new LightWeightMap(); - - DWORDLONG key = CastHandle(ftn); - DWORD value = result ? 1 : 0; - CanValueClassInstancePointerEscape->Add(key, value); - DEBUG_REC(dmpCanValueClassInstancePointerEscape(key, value)); -} -void MethodContext::dmpCanValueClassInstancePointerEscape(DWORDLONG key, DWORD value) -{ - printf("CanValueClassInstancePointerEscape key ftn-%016" PRIX64 ", value res-%u", key, value); -} -bool MethodContext::repCanValueClassInstancePointerEscape(CORINFO_METHOD_HANDLE ftn) -{ - DWORDLONG key = CastHandle(ftn); - DWORD value = LookupByKeyOrMiss(CanValueClassInstancePointerEscape, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpCanValueClassInstancePointerEscape(key, value)); - return value != 0; -} - -bool g_debugRec = false; -bool g_debugRep = false; - -void SetDebugDumpVariables() -{ - static WCHAR* g_debugRecStr = nullptr; - static WCHAR* g_debugRepStr = nullptr; - if (g_debugRecStr == nullptr) - { - g_debugRecStr = GetEnvironmentVariableWithDefaultW(W("SuperPMIShimDebugRec"), W("0")); - } - if (g_debugRepStr == nullptr) - { - g_debugRepStr = GetEnvironmentVariableWithDefaultW(W("SuperPMIShimDebugRep"), W("0")); - } - - if (0 == u16_strcmp(g_debugRecStr, W("1"))) - { - g_debugRec = true; - } - if (0 == u16_strcmp(g_debugRepStr, W("1"))) - { - g_debugRep = true; - } -} diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h deleted file mode 100644 index 08c742551f0b27..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ /dev/null @@ -1,1257 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// MethodContext.h - Primary structure to store all the EE-JIT details required to replay creation of a method -// CompileResult contains the stuff generated by a compilation -//---------------------------------------------------------- -#ifndef _MethodContext -#define _MethodContext - -#include "runtimedetails.h" -#include "compileresult.h" -#include "lightweightmap.h" -#include "errorhandling.h" -#include "hash.h" -#include "agnostic.h" -#include - -extern bool g_debugRec; -extern bool g_debugRep; - -#if 0 -// Enable these to get verbose logging during record or playback. -#define DEBUG_REC(x) \ - if (g_debugRec) { \ - printf("rec"); \ - x; \ - printf("\n"); \ - } - -#define DEBUG_REP(x) \ - if (g_debugRep) { \ - printf("rep"); \ - x; \ - printf("\n"); \ - } -#else -#define DEBUG_REC(x) -#define DEBUG_REP(x) -#endif - -// Helper function for dumping. -const char* toString(CorInfoType cit); - -#define METHOD_IDENTITY_INFO_SIZE 0x10000 // We assume that the METHOD_IDENTITY_INFO_SIZE will not exceed 64KB -#define METHOD_IDENTITY_INFO_NON_NAME_RESERVE 0x400 // Reserve 1KB of METHOD_IDENTITY_INFO_SIZE for everything except for the method name. - -// Special "jit flags" for noting some method context features - -enum EXTRA_JIT_FLAGS -{ - HAS_PGO = 63, - HAS_EDGE_PROFILE = 62, - HAS_CLASS_PROFILE = 61, - HAS_LIKELY_CLASS = 60, - HAS_STATIC_PROFILE = 59, - HAS_DYNAMIC_PROFILE = 58, - HAS_METHOD_PROFILE = 57, - HAS_LIKELY_METHOD = 56, -}; - -class MethodContext -{ - friend class CompileResult; - -public: - MethodContext(); - -private: - void MethodInitHelper(unsigned char* buff, unsigned int totalLen, bool readCompileResults); - void MethodInitHelperFile(HANDLE hFile, bool readCompileResults); - - bool Initialize(int mcIndex, unsigned char* buff, DWORD size, bool readCompileResults); - bool Initialize(int mcIndex, HANDLE hFile, bool readCompileResults); - - int dumpHashToBuffer(BYTE* pBuffer, int bufLen, char* buff, int len); - -public: - static bool Initialize(int mcIndex, unsigned char* buff, DWORD size, bool readCompileResults, /* OUT */ MethodContext** ppmc); - static bool Initialize(int mcIndex, HANDLE hFile, bool readCompileResults, /* OUT */ MethodContext** ppmc); - ~MethodContext(); - void Destroy(); - - void setIgnoreStoredConfig() - { - ignoreStoredConfig = true; - } - - bool Equal(MethodContext* other); - unsigned int saveToFile(HANDLE hFile); - unsigned int calculateFileSize(); - unsigned int calculateRawFileSize(); - - // dumpToConsole: If mcNumber is not -1, display the method context number before the dumped info. - // If simple is `true`, don't display the function name/arguments in the header. - void dumpToConsole(int mcNumber = -1, bool simple = false); - - int dumpStatToBuffer(char* buff, int len); - static int dumpStatTitleToBuffer(char* buff, int len); - int methodSize; - - int dumpMethodIdentityInfoToBuffer(char* buff, int len, bool ignoreMethodName = false, CORINFO_METHOD_INFO* optInfo = nullptr, unsigned optFlags = 0); - int dumpMethodHashToBuffer(char* buff, int len, bool ignoreMethodName = false, CORINFO_METHOD_INFO* optInfo = nullptr, unsigned optFlags = 0); - - bool hasPgoData(bool& hasEdgeProfile, bool& hasClassProfile, bool& hasMethodProfile, bool& hasLikelyClass, bool& hasLikelyMethod, ICorJitInfo::PgoSource& pgoSource); - - void recGlobalContext(const MethodContext& other); - - void recCompileMethod(CORINFO_METHOD_INFO* info, unsigned flags, CORINFO_OS os); - void dmpCompileMethod(DWORD key, const Agnostic_CompileMethod& value); - void repCompileMethod(CORINFO_METHOD_INFO* info, unsigned* flags, CORINFO_OS* os); - - void recGetMethodClass(CORINFO_METHOD_HANDLE methodHandle, CORINFO_CLASS_HANDLE classHandle); - void dmpGetMethodClass(DWORDLONG key, DWORDLONG value); - CORINFO_CLASS_HANDLE repGetMethodClass(CORINFO_METHOD_HANDLE methodHandle); - - void recGetClassAttribs(CORINFO_CLASS_HANDLE classHandle, DWORD attribs); - void dmpGetClassAttribs(DWORDLONG key, DWORD value); - DWORD repGetClassAttribs(CORINFO_CLASS_HANDLE classHandle); - - void recIsIntrinsic(CORINFO_METHOD_HANDLE ftn, bool result); - void dmpIsIntrinsic(DWORDLONG key, DWORD value); - bool repIsIntrinsic(CORINFO_METHOD_HANDLE ftn); - - void recCanValueClassInstancePointerEscape(CORINFO_METHOD_HANDLE ftn, bool result); - void dmpCanValueClassInstancePointerEscape(DWORDLONG key, DWORD value); - bool repCanValueClassInstancePointerEscape(CORINFO_METHOD_HANDLE ftn); - - void recNotifyMethodInfoUsage(CORINFO_METHOD_HANDLE ftn, bool result); - void dmpNotifyMethodInfoUsage(DWORDLONG key, DWORD value); - bool repNotifyMethodInfoUsage(CORINFO_METHOD_HANDLE ftn); - - void recNotifyInstructionSetUsage(CORINFO_InstructionSet instructionSet, bool supported, bool preserveNegativeDependency, bool result); - void dmpNotifyInstructionSetUsage(DD key, DWORD supported); - bool repNotifyInstructionSetUsage(CORINFO_InstructionSet instructionSet, bool supported, bool preserveNegativeDependency); - - void recGetMethodAttribs(CORINFO_METHOD_HANDLE methodHandle, DWORD attribs); - void dmpGetMethodAttribs(DWORDLONG key, DWORD value); - DWORD repGetMethodAttribs(CORINFO_METHOD_HANDLE methodHandle); - - void recGetClassAssemblyName(CORINFO_CLASS_HANDLE cls, const char* assemblyName); - void dmpGetClassAssemblyName(DWORDLONG key, DWORD value); - const char* repGetClassAssemblyName(CORINFO_CLASS_HANDLE cls); - - void recGetVars(CORINFO_METHOD_HANDLE ftn, ULONG32* cVars, ICorDebugInfo::ILVarInfo** vars, bool* extendOthers); - void dmpGetVars(DWORDLONG key, const Agnostic_GetVars& value); - void repGetVars(CORINFO_METHOD_HANDLE ftn, ULONG32* cVars, ICorDebugInfo::ILVarInfo** vars, bool* extendOthers); - - void recGetBoundaries(CORINFO_METHOD_HANDLE ftn, - unsigned int* cILOffsets, - uint32_t** pILOffsets, - ICorDebugInfo::BoundaryTypes* implicitBoundaries); - void dmpGetBoundaries(DWORDLONG key, const Agnostic_GetBoundaries& value); - void repGetBoundaries(CORINFO_METHOD_HANDLE ftn, - unsigned int* cILOffsets, - uint32_t** pILOffsets, - ICorDebugInfo::BoundaryTypes* implicitBoundaries); - - void recInitClass(CORINFO_FIELD_HANDLE field, - CORINFO_METHOD_HANDLE method, - CORINFO_CONTEXT_HANDLE context, - CorInfoInitClassResult result); - void dmpInitClass(const Agnostic_InitClass& key, DWORD value); - CorInfoInitClassResult repInitClass(CORINFO_FIELD_HANDLE field, - CORINFO_METHOD_HANDLE method, - CORINFO_CONTEXT_HANDLE context); - - void recGetMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftn, - char* methodname, - const char** moduleName, - const char** namespaceName, - const char** enclosingClassNames, - size_t maxEnclosingClassNames); - void dmpGetMethodNameFromMetadata(Agnostic_CORINFO_METHODNAME_TOKENin key, Agnostic_CORINFO_METHODNAME_TOKENout value); - const char* repGetMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftn, - const char** className, - const char** namespaceName, - const char** enclosingClassNames, - size_t maxEnclosingClassNames); - - void recGetJitFlags(CORJIT_FLAGS* jitFlags, DWORD sizeInBytes, DWORD result); - void dmpGetJitFlags(DWORD key, DD value); - DWORD repGetJitFlags(CORJIT_FLAGS* jitFlags, DWORD sizeInBytes); - - void recCanInline(CORINFO_METHOD_HANDLE callerHnd, - CORINFO_METHOD_HANDLE calleeHnd, - CorInfoInline response, - DWORD exceptionCode); - void dmpCanInline(DLDL key, const Agnostic_CanInline& value); - CorInfoInline repCanInline(CORINFO_METHOD_HANDLE callerHnd, - CORINFO_METHOD_HANDLE calleeHnd, - DWORD* exceptionCode); - - void recResolveToken(CORINFO_RESOLVED_TOKEN* pResolvedToken, DWORD exceptionCode); - void dmpResolveToken(const Agnostic_CORINFO_RESOLVED_TOKENin& key, const ResolveTokenValue& value); - void repResolveToken(CORINFO_RESOLVED_TOKEN* pResolvedToken, DWORD* exceptionCode); - - void recGetCallInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, - CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_CALLINFO_FLAGS flags, - CORINFO_CALL_INFO* pResult, - DWORD exceptionCode); - void dmpGetCallInfo(const Agnostic_GetCallInfo& key, const Agnostic_CORINFO_CALL_INFO& value); - void repGetCallInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, - CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_CALLINFO_FLAGS flags, - CORINFO_CALL_INFO* pResult, - DWORD* exceptionCode); - void repGetCallInfoFromMethodHandle(CORINFO_METHOD_HANDLE methodHandle, CORINFO_CALL_INFO* pResult); - - void recAsCorInfoType(CORINFO_CLASS_HANDLE cls, CorInfoType result); - void dmpAsCorInfoType(DWORDLONG key, DWORD value); - CorInfoType repAsCorInfoType(CORINFO_CLASS_HANDLE cls); - - void recIsValueClass(CORINFO_CLASS_HANDLE cls, bool result); - void dmpIsValueClass(DWORDLONG key, DWORD value); - bool repIsValueClass(CORINFO_CLASS_HANDLE cls); - - void recIsByRefLike(CORINFO_CLASS_HANDLE cls, bool result); - void dmpIsByRefLike(DWORDLONG key, DWORD value); - bool repIsByRefLike(CORINFO_CLASS_HANDLE cls); - - void recIsSharedInst(CORINFO_CLASS_HANDLE cls, bool result); - void dmpIsSharedInst(DWORDLONG key, DWORD value); - bool repIsSharedInst(CORINFO_CLASS_HANDLE cls); - - void recGetClassSize(CORINFO_CLASS_HANDLE cls, unsigned result); - void dmpGetClassSize(DWORDLONG key, DWORD val); - unsigned repGetClassSize(CORINFO_CLASS_HANDLE cls); - - void recGetHeapClassSize(CORINFO_CLASS_HANDLE cls, unsigned result); - void dmpGetHeapClassSize(DWORDLONG key, DWORD val); - unsigned repGetHeapClassSize(CORINFO_CLASS_HANDLE cls); - - void recCanAllocateOnStack(CORINFO_CLASS_HANDLE cls, bool result); - void dmpCanAllocateOnStack(DWORDLONG key, DWORD val); - bool repCanAllocateOnStack(CORINFO_CLASS_HANDLE cls); - - void recGetClassNumInstanceFields(CORINFO_CLASS_HANDLE cls, unsigned result); - void dmpGetClassNumInstanceFields(DWORDLONG key, DWORD value); - unsigned repGetClassNumInstanceFields(CORINFO_CLASS_HANDLE cls); - - void recGetNewArrHelper(CORINFO_CLASS_HANDLE arrayCls, CorInfoHelpFunc result); - void dmpGetNewArrHelper(DWORDLONG key, DWORD value); - CorInfoHelpFunc repGetNewArrHelper(CORINFO_CLASS_HANDLE arrayCls); - - void recGetSharedCCtorHelper(CORINFO_CLASS_HANDLE clsHnd, CorInfoHelpFunc result); - void dmpGetSharedCCtorHelper(DWORDLONG key, DWORD value); - CorInfoHelpFunc repGetSharedCCtorHelper(CORINFO_CLASS_HANDLE clsHnd); - - void recGetTypeForBox(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE result); - void dmpGetTypeForBox(DWORDLONG key, DWORDLONG value); - CORINFO_CLASS_HANDLE repGetTypeForBox(CORINFO_CLASS_HANDLE cls); - - void recGetBoxHelper(CORINFO_CLASS_HANDLE cls, CorInfoHelpFunc result); - void dmpGetBoxHelper(DWORDLONG key, DWORD value); - CorInfoHelpFunc repGetBoxHelper(CORINFO_CLASS_HANDLE cls); - - void recGetBuiltinClass(CorInfoClassId classId, CORINFO_CLASS_HANDLE result); - void dmpGetBuiltinClass(DWORD key, DWORDLONG value); - CORINFO_CLASS_HANDLE repGetBuiltinClass(CorInfoClassId classId); - - void recGetTypeForPrimitiveValueClass(CORINFO_CLASS_HANDLE cls, CorInfoType result); - void dmpGetTypeForPrimitiveValueClass(DWORDLONG key, DWORD value); - CorInfoType repGetTypeForPrimitiveValueClass(CORINFO_CLASS_HANDLE cls); - - void recGetTypeForPrimitiveNumericClass(CORINFO_CLASS_HANDLE cls, CorInfoType result); - void dmpGetTypeForPrimitiveNumericClass(DWORDLONG key, DWORD value); - CorInfoType repGetTypeForPrimitiveNumericClass(CORINFO_CLASS_HANDLE cls); - - void recGetParentType(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE result); - void dmpGetParentType(DWORDLONG key, DWORDLONG value); - CORINFO_CLASS_HANDLE repGetParentType(CORINFO_CLASS_HANDLE cls); - - void recIsSDArray(CORINFO_CLASS_HANDLE cls, bool result); - void dmpIsSDArray(DWORDLONG key, DWORD value); - bool repIsSDArray(CORINFO_CLASS_HANDLE cls); - - void recExpandRawHandleIntrinsic(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_HANDLE callerHandle, CORINFO_GENERICHANDLE_RESULT* pResult); - void dmpExpandRawHandleIntrinsic(const Agnostic_ExpandRawHandleIntrinsic& key, const Agnostic_CORINFO_GENERICHANDLE_RESULT& result); - void repExpandRawHandleIntrinsic(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_HANDLE callerHandle, CORINFO_GENERICHANDLE_RESULT* pResult); - - void recIsIntrinsicType(CORINFO_CLASS_HANDLE cls, bool result); - void dmpIsIntrinsicType(DWORDLONG key, DWORD value); - bool repIsIntrinsicType(CORINFO_CLASS_HANDLE cls); - - void recGetFieldClass(CORINFO_FIELD_HANDLE field, CORINFO_CLASS_HANDLE result); - void dmpGetFieldClass(DWORDLONG key, DWORDLONG value); - CORINFO_CLASS_HANDLE repGetFieldClass(CORINFO_FIELD_HANDLE field); - - void recGetFieldOffset(CORINFO_FIELD_HANDLE field, unsigned result); - void dmpGetFieldOffset(DWORDLONG key, DWORD value); - unsigned repGetFieldOffset(CORINFO_FIELD_HANDLE field); - - void recGetUnBoxHelper(CORINFO_CLASS_HANDLE cls, CorInfoHelpFunc result); - void dmpGetUnBoxHelper(DWORDLONG key, DWORD value); - CorInfoHelpFunc repGetUnBoxHelper(CORINFO_CLASS_HANDLE cls); - - void recGetRuntimeTypePointer(CORINFO_CLASS_HANDLE cls, CORINFO_OBJECT_HANDLE result); - void dmpGetRuntimeTypePointer(DWORDLONG key, DWORDLONG value); - CORINFO_OBJECT_HANDLE repGetRuntimeTypePointer(CORINFO_CLASS_HANDLE cls); - - void recIsObjectImmutable(CORINFO_OBJECT_HANDLE objPtr, bool result); - void dmpIsObjectImmutable(DWORDLONG key, DWORD value); - bool repIsObjectImmutable(CORINFO_OBJECT_HANDLE objPtr); - - void recGetStringChar(CORINFO_OBJECT_HANDLE strObj, int index, uint16_t* charValue, bool result); - void dmpGetStringChar(DLD key, DD value); - bool repGetStringChar(CORINFO_OBJECT_HANDLE strObj, int index, uint16_t* charValue); - - void recGetObjectType(CORINFO_OBJECT_HANDLE objPtr, CORINFO_CLASS_HANDLE result); - void dmpGetObjectType(DWORDLONG key, DWORDLONG value); - CORINFO_CLASS_HANDLE repGetObjectType(CORINFO_OBJECT_HANDLE objPtr); - - void recGetReadyToRunHelper(CORINFO_RESOLVED_TOKEN* pResolvedToken, - CorInfoHelpFunc id, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_CONST_LOOKUP* pLookup, - bool result); - void dmpGetReadyToRunHelper(GetReadyToRunHelper_TOKENin key, GetReadyToRunHelper_TOKENout value); - bool repGetReadyToRunHelper(CORINFO_RESOLVED_TOKEN* pResolvedToken, - CorInfoHelpFunc id, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_CONST_LOOKUP* pLookup); - - void recGetReadyToRunDelegateCtorHelper(CORINFO_RESOLVED_TOKEN* pTargetMethod, - mdToken targetConstraint, - CORINFO_CLASS_HANDLE delegateType, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_LOOKUP* pLookup); - void dmpGetReadyToRunDelegateCtorHelper(GetReadyToRunDelegateCtorHelper_TOKENIn key, - Agnostic_CORINFO_LOOKUP pLookup); - void repGetReadyToRunDelegateCtorHelper(CORINFO_RESOLVED_TOKEN* pTargetMethod, - mdToken targetConstraint, - CORINFO_CLASS_HANDLE delegateType, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_LOOKUP* pLookup); - - void recGetHelperFtn(CorInfoHelpFunc ftnNum, CORINFO_CONST_LOOKUP pNativeEntrypoint,CORINFO_METHOD_HANDLE methodHandle); - void dmpGetHelperFtn(DWORD key, Agnostic_GetHelperFtn value); - void repGetHelperFtn(CorInfoHelpFunc ftnNum, CORINFO_CONST_LOOKUP* pNativeEntrypoint,CORINFO_METHOD_HANDLE *pMethodHandle); - bool fndGetHelperFtn(void* functionAddress, CorInfoHelpFunc* pResult); - - void recGetJustMyCodeHandle(CORINFO_METHOD_HANDLE method, - CORINFO_JUST_MY_CODE_HANDLE** ppIndirection, - CORINFO_JUST_MY_CODE_HANDLE result); - void dmpGetJustMyCodeHandle(DWORDLONG key, DLDL value); - CORINFO_JUST_MY_CODE_HANDLE repGetJustMyCodeHandle(CORINFO_METHOD_HANDLE method, - CORINFO_JUST_MY_CODE_HANDLE** ppIndirection); - - void recGetFunctionEntryPoint(CORINFO_METHOD_HANDLE ftn, - CORINFO_CONST_LOOKUP* pResult, - CORINFO_ACCESS_FLAGS accessFlags); - void dmpGetFunctionEntryPoint(DLD key, DLD value); - void repGetFunctionEntryPoint(CORINFO_METHOD_HANDLE ftn, - CORINFO_CONST_LOOKUP* pResult, - CORINFO_ACCESS_FLAGS accessFlags); - bool fndGetFunctionEntryPoint(DLD value, CORINFO_METHOD_HANDLE* pResult); - - void recConstructStringLiteral(CORINFO_MODULE_HANDLE module, mdToken metaTok, void* ppValue, InfoAccessType result); - void dmpConstructStringLiteral(DLD key, DLD value); - InfoAccessType repConstructStringLiteral(CORINFO_MODULE_HANDLE module, mdToken metaTok, void** ppValue); - - void recConvertPInvokeCalliToCall(CORINFO_RESOLVED_TOKEN* pResolvedToken, bool fMustConvert, bool result); - void dmpConvertPInvokeCalliToCall(DLD key, DLDL value); - bool repConvertPInvokeCalliToCall(CORINFO_RESOLVED_TOKEN* pResolvedToken, bool fMustConvert); - - void recEmptyStringLiteral(void** ppValue, InfoAccessType result); - void dmpEmptyStringLiteral(DWORD key, DLD value); - InfoAccessType repEmptyStringLiteral(void** ppValue); - - void recGetArgType(CORINFO_SIG_INFO* sig, - CORINFO_ARG_LIST_HANDLE args, - CORINFO_CLASS_HANDLE* vcTypeRet, - CorInfoTypeWithMod result, - DWORD exception); - void dmpGetArgType(const Agnostic_GetArgType_Key& key, const Agnostic_GetArgType_Value& value); - CorInfoTypeWithMod repGetArgType(CORINFO_SIG_INFO* sig, - CORINFO_ARG_LIST_HANDLE args, - CORINFO_CLASS_HANDLE* vcTypeRet, - DWORD* exception); - - void recGetExactClasses(CORINFO_CLASS_HANDLE baseType, - int maxExactClasses, - CORINFO_CLASS_HANDLE* exactClsRet, - int result); - void dmpGetExactClasses(DLD key, const Agnostic_GetExactClassesResult& value); - int repGetExactClasses(CORINFO_CLASS_HANDLE baseType, - int maxExactClasses, - CORINFO_CLASS_HANDLE* exactClsRet); - - void recGetArgNext(CORINFO_ARG_LIST_HANDLE args, CORINFO_ARG_LIST_HANDLE result); - void dmpGetArgNext(DWORDLONG key, DWORDLONG value); - CORINFO_ARG_LIST_HANDLE repGetArgNext(CORINFO_ARG_LIST_HANDLE args); - - void recGetMethodSig(CORINFO_METHOD_HANDLE ftn, CORINFO_SIG_INFO* sig, CORINFO_CLASS_HANDLE memberParent); - void dmpGetMethodSig(DLDL key, const Agnostic_CORINFO_SIG_INFO& value); - void repGetMethodSig(CORINFO_METHOD_HANDLE ftn, CORINFO_SIG_INFO* sig, CORINFO_CLASS_HANDLE memberParent); - - void recGetArgClass(CORINFO_SIG_INFO* sig, - CORINFO_ARG_LIST_HANDLE args, - CORINFO_CLASS_HANDLE result, - DWORD exceptionCode); - void dmpGetArgClass(const Agnostic_GetArgClass_Key& key, const Agnostic_GetArgClass_Value& value); - CORINFO_CLASS_HANDLE repGetArgClass(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_HANDLE args, DWORD* exceptionCode); - - void recGetHFAType(CORINFO_CLASS_HANDLE clsHnd, CorInfoHFAElemType result); - void dmpGetHFAType(DWORDLONG key, DWORD value); - CorInfoHFAElemType repGetHFAType(CORINFO_CLASS_HANDLE clsHnd); - - void recGetMethodInfo(CORINFO_METHOD_HANDLE ftn, CORINFO_METHOD_INFO* info, CORINFO_CONTEXT_HANDLE context, bool result, DWORD exceptionCode); - void dmpGetMethodInfo(DLDL key, const Agnostic_GetMethodInfo& value); - bool repGetMethodInfo(CORINFO_METHOD_HANDLE ftn, CORINFO_METHOD_INFO* info, CORINFO_CONTEXT_HANDLE context, DWORD* exceptionCode); - - void recHaveSameMethodDefinition(CORINFO_METHOD_HANDLE methHnd1, CORINFO_METHOD_HANDLE methHnd2, bool result); - void dmpHaveSameMethodDefinition(const DLDL& key, DWORD value); - bool repHaveSameMethodDefinition(CORINFO_METHOD_HANDLE methHnd1, CORINFO_METHOD_HANDLE methHnd2); - - void recGetTypeDefinition(CORINFO_CLASS_HANDLE type, CORINFO_CLASS_HANDLE result); - void dmpGetTypeDefinition(DWORDLONG key, DWORDLONG value); - CORINFO_CLASS_HANDLE repGetTypeDefinition(CORINFO_CLASS_HANDLE type); - - void recGetNewHelper(CORINFO_CLASS_HANDLE classHandle, - bool hasSideEffects, - CorInfoHelpFunc result, - DWORD exceptionCode); - void dmpGetNewHelper(DWORDLONG key, const DDD& value); - CorInfoHelpFunc repGetNewHelper(CORINFO_CLASS_HANDLE classHandle, bool* pHasSideEffects, DWORD* exceptionCode); - - void recEmbedGenericHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken, - bool fEmbedParent, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_GENERICHANDLE_RESULT* pResult); - void dmpEmbedGenericHandle(const Agnostic_EmbedGenericHandle& key, - const Agnostic_CORINFO_GENERICHANDLE_RESULT& value); - void repEmbedGenericHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken, - bool fEmbedParent, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_GENERICHANDLE_RESULT* pResult); - - void recGetEHinfo(CORINFO_METHOD_HANDLE ftn, unsigned EHnumber, CORINFO_EH_CLAUSE* clause); - void dmpGetEHinfo(DLD key, const Agnostic_CORINFO_EH_CLAUSE& value); - void repGetEHinfo(CORINFO_METHOD_HANDLE ftn, unsigned EHnumber, CORINFO_EH_CLAUSE* clause); - - void recGetMethodVTableOffset(CORINFO_METHOD_HANDLE method, - unsigned* offsetOfIndirection, - unsigned* offsetAfterIndirection, - bool* isRelative); - void dmpGetMethodVTableOffset(DWORDLONG key, DDD value); - void repGetMethodVTableOffset(CORINFO_METHOD_HANDLE method, - unsigned* offsetOfIndirection, - unsigned* offsetAfterIndirection, - bool* isRelative); - - void recResolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO * info, bool returnValue); - void dmpResolveVirtualMethod(const Agnostic_ResolveVirtualMethodKey& key, const Agnostic_ResolveVirtualMethodResult& value); - bool repResolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO * info); - - void recGetAsyncOtherVariant(CORINFO_METHOD_HANDLE ftn, bool variantIsThunk, CORINFO_METHOD_HANDLE result); - void dmpGetAsyncOtherVariant(DWORDLONG key, DLD value); - CORINFO_METHOD_HANDLE repGetAsyncOtherVariant(CORINFO_METHOD_HANDLE ftn, bool* variantIsThunk); - - void recGetDefaultComparerClass(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE result); - void dmpGetDefaultComparerClass(DWORDLONG key, DWORDLONG value); - CORINFO_CLASS_HANDLE repGetDefaultComparerClass(CORINFO_CLASS_HANDLE cls); - - void recGetDefaultEqualityComparerClass(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE result); - void dmpGetDefaultEqualityComparerClass(DWORDLONG key, DWORDLONG value); - CORINFO_CLASS_HANDLE repGetDefaultEqualityComparerClass(CORINFO_CLASS_HANDLE cls); - - void recGetSZArrayHelperEnumeratorClass(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE result); - void dmpGetSZArrayHelperEnumeratorClass(DWORDLONG key, DWORDLONG value); - CORINFO_CLASS_HANDLE repGetSZArrayHelperEnumeratorClass(CORINFO_CLASS_HANDLE cls); - - void recGetTokenTypeAsHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_CLASS_HANDLE result); - void dmpGetTokenTypeAsHandle(const GetTokenTypeAsHandleValue& key, DWORDLONG value); - CORINFO_CLASS_HANDLE repGetTokenTypeAsHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken); - - void recGetFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_ACCESS_FLAGS flags, - CORINFO_FIELD_INFO* pResult); - void dmpGetFieldInfo(const Agnostic_GetFieldInfo& key, const Agnostic_CORINFO_FIELD_INFO& value); - void repGetFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_ACCESS_FLAGS flags, - CORINFO_FIELD_INFO* pResult); - - void recGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, bool isGCType, uint32_t result); - void dmpGetThreadLocalFieldInfo(DLD key, DWORD value); - uint32_t repGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, bool isGCType); - - void recGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo); - void dmpGetThreadLocalStaticBlocksInfo(DWORD key, const Agnostic_GetThreadLocalStaticBlocksInfo& value); - void repGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo); - - void recGetThreadLocalStaticInfo_NativeAOT(CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo); - void dmpGetThreadLocalStaticInfo_NativeAOT(DWORDLONG key, const Agnostic_GetThreadStaticInfo_NativeAOT& value); - void repGetThreadLocalStaticInfo_NativeAOT(CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo); - - void recEmbedMethodHandle(CORINFO_METHOD_HANDLE handle, void** ppIndirection, CORINFO_METHOD_HANDLE result); - void dmpEmbedMethodHandle(DWORDLONG key, DLDL value); - CORINFO_METHOD_HANDLE repEmbedMethodHandle(CORINFO_METHOD_HANDLE handle, void** ppIndirection); - - void recGetStaticFieldContent(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects, bool result); - void dmpGetStaticFieldContent(DLDDD key, DD value); - bool repGetStaticFieldContent(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects); - - void recGetObjectContent(CORINFO_OBJECT_HANDLE obj, uint8_t* buffer, int bufferSize, int valueOffset, bool result); - void dmpGetObjectContent(DLDD key, DD value); - bool repGetObjectContent(CORINFO_OBJECT_HANDLE obj, uint8_t* buffer, int bufferSize, int valueOffset); - - void recGetStaticFieldCurrentClass(CORINFO_FIELD_HANDLE field, bool* pIsSpeculative, CORINFO_CLASS_HANDLE result); - void dmpGetStaticFieldCurrentClass(DLD key, const Agnostic_GetStaticFieldCurrentClass& value); - CORINFO_CLASS_HANDLE repGetStaticFieldCurrentClass(CORINFO_FIELD_HANDLE field, bool* pIsSpeculative); - - void recGetClassGClayout(CORINFO_CLASS_HANDLE cls, BYTE* gcPtrs, unsigned len, unsigned result); - void dmpGetClassGClayout(DWORDLONG key, const Agnostic_GetClassGClayout& value); - unsigned repGetClassGClayout(CORINFO_CLASS_HANDLE cls, BYTE* gcPtrs); - - void recGetClassAlignmentRequirement(CORINFO_CLASS_HANDLE cls, bool fDoubleAlignHint, unsigned result); - void dmpGetClassAlignmentRequirement(DLD key, DWORD value); - unsigned repGetClassAlignmentRequirement(CORINFO_CLASS_HANDLE cls, bool fDoubleAlignHint); - - void recCanAccessClass(CORINFO_RESOLVED_TOKEN* pResolvedToken, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_HELPER_DESC* pAccessHelper, - CorInfoIsAccessAllowedResult result); - void dmpCanAccessClass(const Agnostic_CanAccessClassIn& key, const Agnostic_CanAccessClassOut& value); - CorInfoIsAccessAllowedResult repCanAccessClass(CORINFO_RESOLVED_TOKEN* pResolvedToken, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_HELPER_DESC* pAccessHelper); - - void recGetCastingHelper(CORINFO_RESOLVED_TOKEN* pResolvedToken, bool fThrowing, CorInfoHelpFunc result); - void dmpGetCastingHelper(const Agnostic_GetCastingHelper& key, DWORD value); - CorInfoHelpFunc repGetCastingHelper(CORINFO_RESOLVED_TOKEN* pResolvedToken, bool fThrowing); - - void recEmbedModuleHandle(CORINFO_MODULE_HANDLE handle, void** ppIndirection, CORINFO_MODULE_HANDLE result); - void dmpEmbedModuleHandle(DWORDLONG key, DLDL value); - CORINFO_MODULE_HANDLE repEmbedModuleHandle(CORINFO_MODULE_HANDLE handle, void** ppIndirection); - - void recEmbedClassHandle(CORINFO_CLASS_HANDLE handle, void** ppIndirection, CORINFO_CLASS_HANDLE result); - void dmpEmbedClassHandle(DWORDLONG key, DLDL value); - CORINFO_CLASS_HANDLE repEmbedClassHandle(CORINFO_CLASS_HANDLE handle, void** ppIndirection); - - void recPInvokeMarshalingRequired(CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* callSiteSig, bool result); - void dmpPInvokeMarshalingRequired(const MethodOrSigInfoValue& key, DWORD value); - bool repPInvokeMarshalingRequired(CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* callSiteSig); - - void recGetUnmanagedCallConv(CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* callSiteSig, CorInfoCallConvExtension result, bool suppressGCTransitionResult); - void dmpGetUnmanagedCallConv(const MethodOrSigInfoValue& key, DD value); - CorInfoCallConvExtension repGetUnmanagedCallConv(CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* callSiteSig, bool* pSuppressGCTransition); - - void recFindSig(CORINFO_MODULE_HANDLE module, - unsigned sigTOK, - CORINFO_CONTEXT_HANDLE context, - CORINFO_SIG_INFO* sig); - void dmpFindSig(const Agnostic_FindSig& key, const Agnostic_CORINFO_SIG_INFO& value); - void repFindSig(CORINFO_MODULE_HANDLE module, - unsigned sigTOK, - CORINFO_CONTEXT_HANDLE context, - CORINFO_SIG_INFO* sig); - - void recGetEEInfo(CORINFO_EE_INFO* pEEInfoOut); - void dmpGetEEInfo(DWORD key, const Agnostic_CORINFO_EE_INFO& value); - void repGetEEInfo(CORINFO_EE_INFO* pEEInfoOut); - - void recGetAsyncInfo(const CORINFO_ASYNC_INFO* pAsyncInfo); - void dmpGetAsyncInfo(DWORD key, const Agnostic_CORINFO_ASYNC_INFO& value); - void repGetAsyncInfo(CORINFO_ASYNC_INFO* pAsyncInfoOut); - - void recGetAwaitReturnCall(CORINFO_METHOD_HANDLE callerHnd, CORINFO_CONTEXT_HANDLE* contextHandle, CORINFO_LOOKUP* instArg, CORINFO_METHOD_HANDLE methHnd); - void dmpGetAwaitReturnCall(DWORDLONG key, Agnostic_GetAwaitReturnCallResult& value); - CORINFO_METHOD_HANDLE repGetAwaitReturnCall(CORINFO_METHOD_HANDLE callerHnd, CORINFO_CONTEXT_HANDLE* contextHandle, CORINFO_LOOKUP* instArg); - - void recGetAwaitAwaiterInContinuationCall(CORINFO_METHOD_HANDLE callerHnd, - CORINFO_RESOLVED_TOKEN* pResolvedToken, - bool isUnsafe, - CORINFO_CONTEXT_HANDLE* contextHandle, - CORINFO_LOOKUP* instArg, - CORINFO_METHOD_HANDLE methHnd); - void dmpGetAwaitAwaiterInContinuationCall(const Agnostic_GetAwaitAwaiterInContinuationCall& key, - Agnostic_GetAwaitReturnCallResult& value); - CORINFO_METHOD_HANDLE repGetAwaitAwaiterInContinuationCall(CORINFO_METHOD_HANDLE callerHnd, - CORINFO_RESOLVED_TOKEN* pResolvedToken, - bool isUnsafe, - CORINFO_CONTEXT_HANDLE* contextHandle, - CORINFO_LOOKUP* instArg); - - void recGetWasmWellKnownGlobals(const CORINFO_WASM_WELLKNOWN_GLOBALS* pBaseGlobals); - void dmpGetWasmWellKnownGlobals(DWORD key, const Agnostic_CORINFO_WASM_WELLKNOWN_GLOBALS& value); - void repGetWasmWellKnownGlobals(CORINFO_WASM_WELLKNOWN_GLOBALS* pWellKnownGlobalsOut); - - void recGetGSCookie(GSCookie* pCookieVal, GSCookie** ppCookieVal); - void dmpGetGSCookie(DWORD key, DLDL value); - void repGetGSCookie(GSCookie* pCookieVal, GSCookie** ppCookieVal); - - void recGetOSRInfo(PatchpointInfo* patchpointInfo, unsigned* ilOffset); - void dmpGetOSRInfo(DWORD key, const Agnostic_GetOSRInfo& value); - PatchpointInfo* repGetOSRInfo(unsigned* ilOffset); - - void recGetClassModuleIdForStatics(CORINFO_CLASS_HANDLE cls, - CORINFO_MODULE_HANDLE* pModule, - void** ppIndirection, - size_t result); - void dmpGetClassModuleIdForStatics(DWORDLONG key, const Agnostic_GetClassModuleIdForStatics& value); - size_t repGetClassModuleIdForStatics(CORINFO_CLASS_HANDLE cls, - CORINFO_MODULE_HANDLE* pModule, - void** ppIndirection); - - void recGetIsClassInitedFlagAddress(CORINFO_CLASS_HANDLE cls, CORINFO_CONST_LOOKUP* addr, int* offset, bool result); - void dmpGetIsClassInitedFlagAddress(DWORDLONG key, const Agnostic_GetIsClassInitedFlagAddress& value); - bool repGetIsClassInitedFlagAddress(CORINFO_CLASS_HANDLE cls, CORINFO_CONST_LOOKUP* addr, int* offset); - - void recGetStaticBaseAddress(CORINFO_CLASS_HANDLE cls, bool isGc, CORINFO_CONST_LOOKUP* addr, bool result); - void dmpGetStaticBaseAddress(DLD key, const Agnostic_GetStaticBaseAddress& value); - bool repGetStaticBaseAddress(CORINFO_CLASS_HANDLE cls, bool isGc, CORINFO_CONST_LOOKUP* addr); - - void recGetThreadTLSIndex(void** ppIndirection, DWORD result); - void dmpGetThreadTLSIndex(DWORD key, DLD value); - DWORD repGetThreadTLSIndex(void** ppIndirection); - - void recGetAddrOfCaptureThreadGlobal(void** ppIndirection, int32_t* result); - void dmpGetAddrOfCaptureThreadGlobal(DWORD key, DLDL value); - int32_t* repGetAddrOfCaptureThreadGlobal(void** ppIndirection); - - void recGetClassStaticDynamicInfo(CORINFO_CLASS_HANDLE cls, void* result); - void dmpGetClassStaticDynamicInfo(DWORDLONG key, DLD value); - void* repGetClassStaticDynamicInfo(CORINFO_CLASS_HANDLE cls); - - void recGetClassThreadStaticDynamicInfo(CORINFO_CLASS_HANDLE cls, void* result); - void dmpGetClassThreadStaticDynamicInfo(DWORDLONG key, DLD value); - void* repGetClassThreadStaticDynamicInfo(CORINFO_CLASS_HANDLE cls); - - void recGetLocationOfThisType(CORINFO_METHOD_HANDLE context, CORINFO_LOOKUP_KIND* result); - void dmpGetLocationOfThisType(DWORDLONG key, const Agnostic_CORINFO_LOOKUP_KIND& value); - void repGetLocationOfThisType(CORINFO_METHOD_HANDLE context, CORINFO_LOOKUP_KIND* pLookupKind); - - void recGetDelegateCtor(CORINFO_METHOD_HANDLE methHnd, - CORINFO_CLASS_HANDLE clsHnd, - CORINFO_METHOD_HANDLE targetMethodHnd, - DelegateCtorArgs* pCtorData, - CORINFO_METHOD_HANDLE result); - void dmpGetDelegateCtor(const Agnostic_GetDelegateCtorIn& key, const Agnostic_GetDelegateCtorOut& value); - CORINFO_METHOD_HANDLE repGetDelegateCtor(CORINFO_METHOD_HANDLE methHnd, - CORINFO_CLASS_HANDLE clsHnd, - CORINFO_METHOD_HANDLE targetMethodHnd, - DelegateCtorArgs* pCtorData); - - void recGetFunctionFixedEntryPoint(CORINFO_METHOD_HANDLE ftn, CORINFO_CONST_LOOKUP* pResult); - void dmpGetFunctionFixedEntryPoint(DWORDLONG key, const Agnostic_CORINFO_CONST_LOOKUP& value); - void repGetFunctionFixedEntryPoint(CORINFO_METHOD_HANDLE ftn, bool isUnsafeFunctionPointer, CORINFO_CONST_LOOKUP* pResult); - - void recGetFieldInClass(CORINFO_CLASS_HANDLE clsHnd, INT num, CORINFO_FIELD_HANDLE result); - void dmpGetFieldInClass(DLD key, DWORDLONG value); - CORINFO_FIELD_HANDLE repGetFieldInClass(CORINFO_CLASS_HANDLE clsHnd, INT num); - - void recGetTypeLayout(GetTypeLayoutResult result, CORINFO_CLASS_HANDLE typeHnd, CORINFO_TYPE_LAYOUT_NODE* nodes, size_t numNodes); - void dmpGetTypeLayout(DWORDLONG key, const Agnostic_GetTypeLayoutResult& value); - void dmpTypeLayoutTree(const Agnostic_CORINFO_TYPE_LAYOUT_NODE* nodes, size_t maxNodes, size_t* index, size_t indent); - GetTypeLayoutResult repGetTypeLayout(CORINFO_CLASS_HANDLE typeHnd, CORINFO_TYPE_LAYOUT_NODE* nodes, size_t* numNodes); - - void recGetFieldType(CORINFO_FIELD_HANDLE field, - CORINFO_CLASS_HANDLE* structType, - CORINFO_CLASS_HANDLE fieldOwnerHint, - CorInfoType result); - void dmpGetFieldType(DLDL key, DLD value); - CorInfoType repGetFieldType(CORINFO_FIELD_HANDLE field, - CORINFO_CLASS_HANDLE* structType, - CORINFO_CLASS_HANDLE fieldOwnerHint); - - void recSatisfiesMethodConstraints(CORINFO_CLASS_HANDLE parent, CORINFO_METHOD_HANDLE method, bool result); - void dmpSatisfiesMethodConstraints(DLDL key, DWORD value); - bool repSatisfiesMethodConstraints(CORINFO_CLASS_HANDLE parent, CORINFO_METHOD_HANDLE method); - - void recIsValidStringRef(CORINFO_MODULE_HANDLE module, unsigned metaTOK, bool result); - void dmpIsValidStringRef(DLD key, DWORD value); - bool repIsValidStringRef(CORINFO_MODULE_HANDLE module, unsigned metaTOK); - - void recGetStringLiteral(CORINFO_MODULE_HANDLE module, unsigned metaTOK, char16_t* buffer, int bufferSize, int startIndex, int length); - void dmpGetStringLiteral(DLDDD key, DD value); - int repGetStringLiteral(CORINFO_MODULE_HANDLE module, unsigned metaTOK, char16_t* buffer, int bufferSize, int startIndex); - - void recCanCast(CORINFO_CLASS_HANDLE child, CORINFO_CLASS_HANDLE parent, bool result); - void dmpCanCast(DLDL key, DWORD value); - bool repCanCast(CORINFO_CLASS_HANDLE child, CORINFO_CLASS_HANDLE parent); - - void recGetChildType(CORINFO_CLASS_HANDLE clsHnd, CORINFO_CLASS_HANDLE* clsRet, CorInfoType result); - void dmpGetChildType(DWORDLONG key, DLD value); - CorInfoType repGetChildType(CORINFO_CLASS_HANDLE clsHnd, CORINFO_CLASS_HANDLE* clsRet); - - void recGetArrayInitializationData(CORINFO_FIELD_HANDLE field, DWORD size, void* result); - void dmpGetArrayInitializationData(DLD key, DWORDLONG value); - void* repGetArrayInitializationData(CORINFO_FIELD_HANDLE field, DWORD size); - - void recGetAddressOfPInvokeTarget(CORINFO_METHOD_HANDLE method, CORINFO_CONST_LOOKUP* pLookup); - void dmpGetAddressOfPInvokeTarget(DWORDLONG key, DLD value); - void repGetAddressOfPInvokeTarget(CORINFO_METHOD_HANDLE method, CORINFO_CONST_LOOKUP* pLookup); - - void recGetMethodHash(CORINFO_METHOD_HANDLE ftn, unsigned result); - void dmpGetMethodHash(DWORDLONG key, DWORD value); - unsigned repGetMethodHash(CORINFO_METHOD_HANDLE ftn); - - void recCanTailCall(CORINFO_METHOD_HANDLE callerHnd, - CORINFO_METHOD_HANDLE declaredCalleeHnd, - CORINFO_METHOD_HANDLE exactCalleeHnd, - bool fIsTailPrefix, - bool result); - void dmpCanTailCall(const Agnostic_CanTailCall& key, DWORD value); - bool repCanTailCall(CORINFO_METHOD_HANDLE callerHnd, - CORINFO_METHOD_HANDLE declaredCalleeHnd, - CORINFO_METHOD_HANDLE exactCalleeHnd, - bool fIsTailPrefix); - - void recIsDelegateCreationAllowed(CORINFO_CLASS_HANDLE delegateHnd, CORINFO_METHOD_HANDLE calleeHnd, bool result); - void dmpIsDelegateCreationAllowed(DLDL key, DWORD value); - bool repIsDelegateCreationAllowed(CORINFO_CLASS_HANDLE delegateHnd, CORINFO_METHOD_HANDLE calleeHnd); - - void recFindCallSiteSig(CORINFO_MODULE_HANDLE module, - unsigned methTOK, - CORINFO_CONTEXT_HANDLE context, - CORINFO_SIG_INFO* sig); - void dmpFindCallSiteSig(const Agnostic_FindCallSiteSig& key, const Agnostic_CORINFO_SIG_INFO& value); - void repFindCallSiteSig(CORINFO_MODULE_HANDLE module, - unsigned methTOK, - CORINFO_CONTEXT_HANDLE context, - CORINFO_SIG_INFO* sig); - - void recGetVarArgsHandle(CORINFO_SIG_INFO* pSig, CORINFO_METHOD_HANDLE methHnd, void** ppIndirection, CORINFO_VARARGS_HANDLE result); - void dmpGetVarArgsHandle(const GetVarArgsHandleValue& key, DLDL value); - CORINFO_VARARGS_HANDLE repGetVarArgsHandle(CORINFO_SIG_INFO* pSig, CORINFO_METHOD_HANDLE methHnd, void** ppIndirection); - - void recGetFieldThreadLocalStoreID(CORINFO_FIELD_HANDLE field, void** ppIndirection, DWORD result); - void dmpGetFieldThreadLocalStoreID(DWORDLONG key, DLD value); - DWORD repGetFieldThreadLocalStoreID(CORINFO_FIELD_HANDLE field, void** ppIndirection); - - void recAllocPgoInstrumentationBySchema(CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema* pSchema, UINT32 countSchemaItems, BYTE** pInstrumentationData, HRESULT result); - void dmpAllocPgoInstrumentationBySchema(DWORDLONG key, const Agnostic_AllocPgoInstrumentationBySchema& value); - HRESULT repAllocPgoInstrumentationBySchema(CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema* pSchema, UINT32 countSchemaItems, BYTE** pInstrumentationData); - bool repAllocPgoInstrumentationBySchemaRecorded(CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema* pSchema, UINT32 countSchemaItems, BYTE** pInstrumentationData, HRESULT* result); - - void recGetPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema** pSchema, UINT32* pCountSchemaItems, BYTE** pInstrumentationData, ICorJitInfo::PgoSource* pPgoSource, bool* pDynamicPgo, HRESULT result); - void dmpGetPgoInstrumentationResults(DWORDLONG key, const Agnostic_GetPgoInstrumentationResults& value); - HRESULT repGetPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema** pSchema, UINT32* pCountSchemaItems, BYTE** pInstrumentationData, ICorJitInfo::PgoSource* pPgoSource, bool* pDynamicPgo); - - void recIsMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2, bool result); - void dmpIsMoreSpecificType(DLDL key, DWORD value); - bool repIsMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2); - - void recIsExactType(CORINFO_CLASS_HANDLE cls, bool result); - void dmpIsExactType(DWORDLONG key, DWORD value); - bool repIsExactType(CORINFO_CLASS_HANDLE cls); - - void recIsGenericType(CORINFO_CLASS_HANDLE cls, TypeCompareState result); - void dmpIsGenericType(DWORDLONG key, DWORD value); - TypeCompareState repIsGenericType(CORINFO_CLASS_HANDLE cls); - - void recIsNullableType(CORINFO_CLASS_HANDLE cls, TypeCompareState result); - void dmpIsNullableType(DWORDLONG key, DWORD value); - TypeCompareState repIsNullableType(CORINFO_CLASS_HANDLE cls); - - void recIsEnum(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE underlyingType, TypeCompareState result); - void dmpIsEnum(DWORDLONG key, DLD value); - TypeCompareState repIsEnum(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE* underlyingType); - - LPVOID repGetCookieForInterpreterCalliSig(CORINFO_SIG_INFO* szMetaSig); - void recGetCookieForInterpreterCalliSig(CORINFO_SIG_INFO* szMetaSig, LPVOID result); - void dmpGetCookieForInterpreterCalliSig(const GetCookieForInterpreterCalliSigValue& key, DLDL value); - - void recErrorList(const char* error); - void dmpErrorList(DWORD key, DWORD value); - - void recGetProfilingHandle(bool* pbHookFunction, void** pProfilerHandle, bool* pbIndirectedHandles); - void dmpGetProfilingHandle(DWORD key, const Agnostic_GetProfilingHandle& value); - void repGetProfilingHandle(bool* pbHookFunction, void** pProfilerHandle, bool* pbIndirectedHandles); - - void recEmbedFieldHandle(CORINFO_FIELD_HANDLE handle, void** ppIndirection, CORINFO_FIELD_HANDLE result); - void dmpEmbedFieldHandle(DWORDLONG key, DLDL value); - CORINFO_FIELD_HANDLE repEmbedFieldHandle(CORINFO_FIELD_HANDLE handle, void** ppIndirection); - - void recCompareTypesForCast(CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass, TypeCompareState result); - void dmpCompareTypesForCast(DLDL key, DWORD value); - TypeCompareState repCompareTypesForCast(CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass); - - void recCompareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2, TypeCompareState result); - void dmpCompareTypesForEquality(DLDL key, DWORD value); - TypeCompareState repCompareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2); - - void recGetSystemVAmd64PassStructInRegisterDescriptor( - CORINFO_CLASS_HANDLE structHnd, - SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr, - bool result); - void dmpGetSystemVAmd64PassStructInRegisterDescriptor( - DWORDLONG key, const Agnostic_GetSystemVAmd64PassStructInRegisterDescriptor& value); - bool repGetSystemVAmd64PassStructInRegisterDescriptor( - CORINFO_CLASS_HANDLE structHnd, SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr); - - void recGetSwiftLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_SWIFT_LOWERING* pLowering); - void dmpGetSwiftLowering(DWORDLONG key, const Agnostic_GetSwiftLowering& value); - void repGetSwiftLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_SWIFT_LOWERING* pLowering); - - void recGetFpStructLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_FPSTRUCT_LOWERING* pLowering); - void dmpGetFpStructLowering(DWORDLONG key, const Agnostic_GetFpStructLowering& value); - void repGetFpStructLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_FPSTRUCT_LOWERING* pLowering); - - void recGetWasmLowering(CORINFO_CLASS_HANDLE structHnd, CorInfoWasmType wasmType); - void dmpGetWasmLowering(DWORDLONG key, DWORD value); - CorInfoWasmType repGetWasmLowering(CORINFO_CLASS_HANDLE structHnd); - - void recGetRelocTypeHint(void* target, CorInfoReloc result); - void dmpGetRelocTypeHint(DWORDLONG key, DWORD value); - CorInfoReloc repGetRelocTypeHint(void* target); - - void recGetAddressAlignment(void* address, uint32_t result); - void dmpGetAddressAlignment(DWORDLONG key, DWORD value); - uint32_t repGetAddressAlignment(void* address); - - void recGetExpectedTargetArchitecture(DWORD result); - void dmpGetExpectedTargetArchitecture(DWORD key, DWORD result); - DWORD repGetExpectedTargetArchitecture(); - - void recDoesFieldBelongToClass(CORINFO_FIELD_HANDLE fld, CORINFO_CLASS_HANDLE cls, bool result); - void dmpDoesFieldBelongToClass(DLDL key, bool value); - bool repDoesFieldBelongToClass(CORINFO_FIELD_HANDLE fld, CORINFO_CLASS_HANDLE cls); - - void recGetClassNameFromMetadata(CORINFO_CLASS_HANDLE cls, char* className, const char** namespaceName); - void dmpGetClassNameFromMetadata(DLD key, DD value); - const char* repGetClassNameFromMetadata(CORINFO_CLASS_HANDLE cls, const char** namespaceName); - - void recGetTypeInstantiationArgument(CORINFO_CLASS_HANDLE cls, unsigned index, CORINFO_CLASS_HANDLE result); - void dmpGetTypeInstantiationArgument(DLD key, DWORDLONG value); - CORINFO_CLASS_HANDLE repGetTypeInstantiationArgument(CORINFO_CLASS_HANDLE cls, unsigned index); - - void recGetMethodInstantiationArgument(CORINFO_METHOD_HANDLE ftn, unsigned index, CORINFO_CLASS_HANDLE result); - void dmpGetMethodInstantiationArgument(DLD key, DWORDLONG value); - CORINFO_CLASS_HANDLE repGetMethodInstantiationArgument(CORINFO_METHOD_HANDLE ftn, unsigned index); - - void recPrint( - const char* name, - LightWeightMap*& map, - DWORDLONG handle, - char* buffer, - size_t bufferSize, - size_t* pRequiredBufferSize, - size_t bytesWritten); - void dmpPrint( - const char* name, - LightWeightMapBuffer* buffer, - DWORDLONG key, - const Agnostic_PrintResult& value); - size_t repPrint( - const char* name, - LightWeightMap*& map, - DWORDLONG handle, - char* buffer, - size_t bufferSize, - size_t* pRequiredBufferSize); - - void recPrintObjectDescription(CORINFO_OBJECT_HANDLE handle, char* buffer, size_t bufferSize, size_t* pRequiredBufferSize, size_t bytesWritten); - void dmpPrintObjectDescription(DWORDLONG key, const Agnostic_PrintResult& value); - size_t repPrintObjectDescription(CORINFO_OBJECT_HANDLE handle, char* buffer, size_t bufferSize, size_t* pRequiredBufferSize); - - void recPrintClassName(CORINFO_CLASS_HANDLE cls, char* buffer, size_t bufferSize, size_t* pRequiredBufferSize, size_t bytesWritten); - void dmpPrintClassName(DWORDLONG cls, const Agnostic_PrintResult& value); - size_t repPrintClassName(CORINFO_CLASS_HANDLE cls, char* buffer, size_t bufferSize, size_t* pRequiredBufferSize = nullptr); - - void recPrintFieldName(CORINFO_FIELD_HANDLE fld, char* buffer, size_t bufferSize, size_t* pRequiredBufferSize, size_t bytesWritten); - void dmpPrintFieldName(DWORDLONG fld, const Agnostic_PrintResult& value); - size_t repPrintFieldName(CORINFO_FIELD_HANDLE fld, char* buffer, size_t bufferSize, size_t* pRequiredBufferSize = nullptr); - - void recPrintMethodName(CORINFO_METHOD_HANDLE meth, char* buffer, size_t bufferSize, size_t* pRequiredBufferSize, size_t bytesWritten); - void dmpPrintMethodName(DWORDLONG meth, const Agnostic_PrintResult& value); - size_t repPrintMethodName(CORINFO_METHOD_HANDLE meth, char* buffer, size_t bufferSize, size_t* pRequiredBufferSize = nullptr); - - void recGetTailCallHelpers( - CORINFO_RESOLVED_TOKEN* callToken, - CORINFO_SIG_INFO* sig, - CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, - CORINFO_TAILCALL_HELPERS* pResult); - void dmpGetTailCallHelpers(const Agnostic_GetTailCallHelpers& key, const Agnostic_CORINFO_TAILCALL_HELPERS& value); - bool repGetTailCallHelpers( - CORINFO_RESOLVED_TOKEN* callToken, - CORINFO_SIG_INFO* sig, - CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, - CORINFO_TAILCALL_HELPERS* pResult); - - void recGetAsyncResumptionStub(CORINFO_METHOD_HANDLE hnd, void* entryPoint); - void dmpGetAsyncResumptionStub(DWORD key, const DLDL& value); - CORINFO_METHOD_HANDLE repGetAsyncResumptionStub(void** entryPoint); - - void recGetContinuationType(size_t dataSize, bool* objRefs, size_t objRefsSize, CORINFO_CLASS_HANDLE result); - void dmpGetContinuationType(const Agnostic_GetContinuationTypeIn& key, DWORDLONG value); - CORINFO_CLASS_HANDLE repGetContinuationType(size_t dataSize, bool* objRefs, size_t objRefsSize); - - void recUpdateEntryPointForTailCall(const CORINFO_CONST_LOOKUP& origEntryPoint, const CORINFO_CONST_LOOKUP& newEntryPoint); - void dmpUpdateEntryPointForTailCall(const Agnostic_CORINFO_CONST_LOOKUP& origEntryPoint, const Agnostic_CORINFO_CONST_LOOKUP& newEntryPoint); - void repUpdateEntryPointForTailCall(CORINFO_CONST_LOOKUP* entryPoint); - - void recGetMethodDefFromMethod(CORINFO_METHOD_HANDLE hMethod, mdMethodDef result); - void dmpGetMethodDefFromMethod(DWORDLONG key, DWORD value); - mdMethodDef repGetMethodDefFromMethod(CORINFO_METHOD_HANDLE hMethod); - - void recCheckMethodModifier(CORINFO_METHOD_HANDLE hMethod, LPCSTR modifier, bool fOptional, bool result); - void dmpCheckMethodModifier(const Agnostic_CheckMethodModifier& key, DWORD value); - bool repCheckMethodModifier(CORINFO_METHOD_HANDLE hMethod, LPCSTR modifier, bool fOptional); - - void recGetArrayRank(CORINFO_CLASS_HANDLE cls, unsigned result); - void dmpGetArrayRank(DWORDLONG key, DWORD value); - unsigned repGetArrayRank(CORINFO_CLASS_HANDLE cls); - - void recGetArrayIntrinsicID(CORINFO_METHOD_HANDLE hMethod, CorInfoArrayIntrinsic result); - void dmpGetArrayIntrinsicID(DWORDLONG key, DWORD value); - CorInfoArrayIntrinsic repGetArrayIntrinsicID(CORINFO_METHOD_HANDLE hMethod); - - void recIsFieldStatic(CORINFO_FIELD_HANDLE fhld, bool result); - void dmpIsFieldStatic(DWORDLONG key, DWORD value); - bool repIsFieldStatic(CORINFO_FIELD_HANDLE fhld); - - void recGetArrayOrStringLength(CORINFO_OBJECT_HANDLE objHnd, int result); - void dmpGetArrayOrStringLength(DWORDLONG key, DWORD value); - int repGetArrayOrStringLength(CORINFO_OBJECT_HANDLE objHnd); - - void recGetIntConfigValue(const char* name, int defaultValue, int result); - void dmpGetIntConfigValue(const Agnostic_ConfigIntInfo& key, int value); - int repGetIntConfigValue(const char* name, int defaultValue); - - void recGetStringConfigValue(const char* name, const char* result); - void dmpGetStringConfigValue(DWORD nameIndex, DWORD result); - const char* repGetStringConfigValue(const char* name); - - void recGetSpecialCopyHelper(CORINFO_CLASS_HANDLE type, CORINFO_METHOD_HANDLE helper); - void dmpGetSpecialCopyHelper(DWORDLONG key, DWORDLONG value); - CORINFO_METHOD_HANDLE repGetSpecialCopyHelper(CORINFO_CLASS_HANDLE type); - - void recGetWasmTypeSymbol(CorInfoWasmType* types, size_t typesSize, CORINFO_WASM_TYPE_SYMBOL_HANDLE result); - void dmpGetWasmTypeSymbol(const Agnostic_GetWasmTypeSymbol& key, DWORDLONG value); - CORINFO_WASM_TYPE_SYMBOL_HANDLE repGetWasmTypeSymbol(CorInfoWasmType* types, size_t typesSize); - - void dmpSigInstHandleMap(DWORD key, DWORDLONG value); - - struct Environment - { - Environment() : getIntConfigValue(nullptr), getStringConfigValue(nullptr) - { - } - - LightWeightMap* getIntConfigValue; - LightWeightMap* getStringConfigValue; - }; - - Environment cloneEnvironment(); - - bool WasEnvironmentChanged(const Environment& prevEnv); - - void Reset() - { - delete cr; - FreeTempAllocations(); - cr = new CompileResult(); - } - - CompileResult* cr; - int index; - bool ignoreStoredConfig; - -private: - bool IsEnvironmentHeaderEqual(const Environment& prevEnv); - bool IsEnvironmentContentEqual(const Environment& prevEnv); - - template - static bool AreLWMHeadersEqual(LightWeightMap* prev, LightWeightMap* curr); - static bool IsIntConfigContentEqual(LightWeightMap* prev, - LightWeightMap* curr); - static bool IsStringContentEqual(LightWeightMap* prev, LightWeightMap* curr); - -#define LWM(map, key, value) LightWeightMap* map; -#define DENSELWM(map, value) DenseLightWeightMap* map; -#include "lwmlist.h" - - // MD5 hasher - static Hash m_hash; - - // Scheme for jit time temporary allocations - struct DeletionNode - { - DeletionNode* pNext; - }; - DeletionNode *nodesToDelete = nullptr; - - void* AllocJitTempBuffer(size_t size) - { - DeletionNode *pDeletionNode = (DeletionNode *)malloc(sizeof(DeletionNode) + size); - pDeletionNode->pNext = this->nodesToDelete; - this->nodesToDelete = pDeletionNode; - return pDeletionNode + 1; - } - - void FreeTempAllocations() - { - while (nodesToDelete != nullptr) - { - DeletionNode *next = nodesToDelete->pNext; - free(nodesToDelete); - nodesToDelete = next; - } - } -}; - -enum mcPackets -{ - //Packet_AreTypesEquivalent = 1, - Packet_AsCorInfoType = 2, - Packet_CanAccessClass = 3, - //Packet_CanAccessFamily = 4, - Packet_CanCast = 5, - Packet_PrintMethodName = 6, - Packet_CanGetCookieForPInvokeCalliSig = 7, - Packet_CanGetVarArgsHandle = 8, - Packet_CanInline = 9, - Packet_PrintFieldName = 10, - //Packet_CanSkipMethodVerification = 11, - Packet_CanTailCall = 12, - //Retired4 = 13, - //Retired3 = 14, - Packet_ConstructStringLiteral = 15, - Packet_EmbedClassHandle = 16, - Packet_EmbedFieldHandle = 17, - Packet_EmbedGenericHandle = 18, - Packet_EmbedMethodHandle = 19, - Packet_EmbedModuleHandle = 20, - Packet_EmptyStringLiteral = 21, - Packet_ErrorList = 22, - Packet_FindCallSiteSig = 23, - //Retired7 = 24, - Packet_FindSig = 25, - Packet_GetAddressOfPInvokeFixup = 26, - Packet_GetAddrOfCaptureThreadGlobal = 27, - //Retired1 = 28, - Packet_GetArgNext = 29, - //Retired2 = 30, - Packet_GetArrayInitializationData = 31, - Packet_GetArrayRank = 32, - //Packet_GetMethodBlockCounts = 33, - Packet_GetBoundaries = 34, - Packet_GetBoxHelper = 35, - Packet_GetBuiltinClass = 36, - Packet_GetCallInfo = 37, - Packet_GetCastingHelper = 38, - Packet_GetChildType = 39, - Packet_GetClassAlignmentRequirement = 40, - Packet_GetClassAttribs = 41, - //Packet_GetClassDomainID = 42, - Packet_GetClassGClayout = 43, - Packet_GetClassModuleIdForStatics = 44, - Packet_GetClassName = 45, - Packet_GetClassNumInstanceFields = 46, - Packet_GetClassSize = 47, - Packet_GetCookieForPInvokeCalliSig = 48, - Packet_GetDelegateCtor = 49, - Packet_GetEEInfo = 50, - Packet_GetEHinfo = 51, - //Packet_GetFieldAddress = 52, - Packet_GetFieldClass = 53, - Packet_GetFieldInClass = 54, - Packet_GetFieldInfo = 55, - Packet_GetFieldOffset = 57, - Packet_GetFieldThreadLocalStoreID = 58, - Packet_GetFieldType = 59, - Packet_GetFunctionEntryPoint = 60, - Packet_GetFunctionFixedEntryPoint = 61, - Packet_GetGSCookie = 62, - //Packet_GetHelperFtn = 63, - //Packet_GetInlinedCallFrameVptr = 65, - Packet_GetArrayIntrinsicID = 66, - //Packet_GetJitTimeLogFilename = 67, - Packet_GetJustMyCodeHandle = 68, - Packet_GetLocationOfThisType = 69, - Packet_GetMethodAttribs = 70, - Packet_GetMethodClass = 71, - Packet_GetMethodDefFromMethod = 72, - Packet_GetMethodHash = 73, - Packet_GetMethodInfo = 74, - Packet_GetMethodSig = 76, - // Packet_GetMethodSync = 77, - Packet_GetMethodVTableOffset = 78, - Packet_GetNewArrHelper = 79, - Packet_GetNewHelper = 80, - Packet_GetParentType = 81, - //Packet_GetPInvokeUnmanagedTarget = 82, - Packet_GetProfilingHandle = 83, - Packet_GetRelocTypeHint = 84, - //Packet_GetSecurityPrologHelper = 85, - Packet_GetSharedCCtorHelper = 86, - //Packet_GetTailCallCopyArgsThunk = 87, - Packet_GetThreadTLSIndex = 88, - Packet_GetTokenTypeAsHandle = 89, - Packet_GetTypeForBox = 90, - Packet_GetTypeForPrimitiveValueClass = 91, - Packet_GetUnBoxHelper = 92, - Packet_GetUnmanagedCallConv = 94, - Packet_GetVarArgsHandle = 95, - Packet_GetVars = 96, - Packet_InitClass = 97, - //Packet_InitConstraintsForVerification = 98, - //Packet_IsCompatibleDelegate = 99, - //Packet_IsInstantiationOfVerifiedGeneric = 100, - Packet_IsSDArray = 101, - //Packet_IsStructRequiringStackAllocRetBuf = 102, - Packet_IsValidStringRef = 103, - //Retired6 = 104, - Packet_IsValueClass = 105, - //Packet_IsWriteBarrierHelperRequired = 106, - //Packet_MergeClasses = 107, - Packet_PInvokeMarshalingRequired = 108, - Packet_ResolveToken = 109, - //Packet_SatisfiesClassConstraints = 110, - Packet_SatisfiesMethodConstraints = 111, - Packet_DoesFieldBelongToClass = 112, - //PacketCR_AddressMap = 113, - PacketCR_AllocGCInfo = 114, - PacketCR_AllocMem = 115, - PacketCR_CallLog = 116, - //PacketCR_ClassMustBeLoadedBeforeCodeIsRun = 117, - PacketCR_CompileMethod = 118, - PacketCR_MessageLog = 119, - //PacketCR_MethodMustBeLoadedBeforeCodeIsRun = 120, - PacketCR_ProcessName = 121, - PacketCR_RecordRelocation = 122, - PacketCR_ReportFatalError = 123, - PacketCR_ReportInliningDecision = 124, - PacketCR_ReportTailCallDecision = 125, - PacketCR_SetBoundaries = 126, - PacketCR_SetEHcount = 127, - PacketCR_SetEHinfo = 128, - PacketCR_SetMethodAttribs = 129, - PacketCR_SetVars = 130, - //Packet_AllocMethodBlockCounts = 131, - PacketCR_AllocUnwindInfo = 132, - PacketCR_ReserveUnwindInfo = 133, - //Packet_FilterException = 134, - //Packet_HandleException = 135, - //Retired9 = 136, - Packet_IsFieldStatic = 137, - PacketCR_AssertLog = 138, - Packet_GetArgClass = 139, - Packet_GetArgType = 140, - //Retired5 = 141, - Packet_CheckMethodModifier = 142, - Packet_CompileMethod = 143, - //Packet_IsValidToken = 144, - //Packet_FindNameOfToken = 145, - //PacketCR_RecordCallSite = 146, - //Packet_GetLazyStringLiteralHelper = 147, - Packet_IsIntrinsicType = 148, - Packet_PrintClassName = 149, - Packet_GetReadyToRunHelper = 150, - Packet_GetIntConfigValue = 151, - Packet_GetStringConfigValue = 152, - Packet_GetAddressOfPInvokeTarget = 153, - Packet_GetJitFlags = 154, - Packet_IsDelegateCreationAllowed = 155, - Packet_GetSystemVAmd64PassStructInRegisterDescriptor = 156, - Packet_GetReadyToRunDelegateCtorHelper = 157, - //Packet_TryResolveToken = 158, - Packet_GetHFAType = 159, - Packet_ResolveVirtualMethod = 160, - Packet_GetMethodNameFromMetadata = 161, - Packet_GetDefaultEqualityComparerClass = 162, - Packet_CompareTypesForCast = 163, - Packet_CompareTypesForEquality = 164, - //Packet_GetUnboxedEntry = 165, - Packet_GetClassNameFromMetadata = 166, - Packet_GetTypeInstantiationArgument = 167, - Packet_GetTypeForPrimitiveNumericClass = 168, - Packet_ConvertPInvokeCalliToCall = 169, - Packet_GetHeapClassSize = 170, - Packet_CanAllocateOnStack = 171, - Packet_GetStaticFieldCurrentClass = 172, - // Packet_CanInlineTypeCheck = 173, - Packet_IsMoreSpecificType = 174, - Packet_GetStringLiteral = 175, - PacketCR_SetPatchpointInfo = 176, - Packet_GetOSRInfo = 177, - Packet_GetTailCallHelpers = 178, - PacketCR_RecordCallSiteWithSignature = 179, - PacketCR_RecordCallSiteWithoutSignature = 180, - //Packet_GetMethodModule = 181, - //Retired10 = 182, - Packet_GetExpectedTargetArchitecture = 183, - Packet_SigInstHandleMap = 184, - PacketCR_CrSigInstHandleMap = 185, - Packet_AllocPgoInstrumentationBySchema = 186, - Packet_GetPgoInstrumentationResults = 187, - Packet_GetDefaultComparerClass = 188, - //Packet_GetClassModule = 189, - //Packet_GetModuleAssembly = 190, - //Packet_GetAssemblyName = 191, - Packet_IsIntrinsic = 192, - Packet_UpdateEntryPointForTailCall = 193, - //Packet_GetLoongArch64PassStructInRegisterFlags = 194, - Packet_GetExactClasses = 195, - Packet_GetRuntimeTypePointer = 196, - Packet_PrintObjectDescription = 197, - Packet_GetStaticFieldContent = 198, - Packet_GetObjectType = 199, - Packet_IsObjectImmutable = 200, - Packet_ExpandRawHandleIntrinsic = 201, - Packet_GetArrayOrStringLength = 202, - Packet_IsEnum = 203, - Packet_GetStringChar = 204, - Packet_GetIsClassInitedFlagAddress = 205, - Packet_GetStaticBaseAddress = 206, - Packet_GetThreadLocalFieldInfo = 207, - Packet_GetThreadLocalStaticBlocksInfo = 208, - Packet_GetThreadLocalStaticInfo_NativeAOT = 209, - //Packet_GetRISCV64PassStructInRegisterFlags = 210, - Packet_GetObjectContent = 211, - Packet_GetTypeLayout = 212, - Packet_HaveSameMethodDefinition = 213, - Packet_NotifyMethodInfoUsage = 214, - Packet_IsExactType = 215, - Packet_GetSwiftLowering = 216, - Packet_IsNullableType = 217, - Packet_GetClassStaticDynamicInfo = 218, - Packet_GetClassThreadStaticDynamicInfo = 219, - Packet_IsGenericType = 220, - //Packet_GetTypeForBoxOnStack = 221, - Packet_GetTypeDefinition = 222, - Packet_GetFpStructLowering = 223, - Packet_GetSpecialCopyHelper = 224, - Packet_GetClassAssemblyName = 225, - Packet_GetSZArrayHelperEnumeratorClass = 226, - Packet_GetMethodInstantiationArgument = 227, - //Packet_GetInstantiatedEntry = 228, - Packet_NotifyInstructionSetUsage = 229, - Packet_GetAsyncInfo = 230, - Packet_GetAsyncResumptionStub = 231, - Packet_GetCookieForInterpreterCalliSig = 232, - Packet_GetHelperFtn = 233, - Packet_GetContinuationType = 234, - Packet_GetWasmTypeSymbol = 235, - Packet_GetWasmLowering = 236, - Packet_GetAsyncOtherVariant = 237, - Packet_GetAwaitReturnCall = 238, - Packet_GetAddressAlignment = 239, - Packet_GetWasmWellKnownGlobals = 240, - Packet_CanValueClassInstancePointerEscape = 241, - Packet_GetAwaitAwaiterInContinuationCall = 242, - Packet_IsByRefLike = 243, - Packet_IsSharedInst = 244, -}; - -void SetDebugDumpVariables(); - -#endif // _MethodContext diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontextiterator.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontextiterator.cpp deleted file mode 100644 index 3cd0ecbc53b2b7..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontextiterator.cpp +++ /dev/null @@ -1,126 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "standardpch.h" -#include "methodcontext.h" -#include "methodcontextiterator.h" - -bool MethodContextIterator::Initialize(const char* fileName) -{ - m_hFile = CreateFileA(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); - if (m_hFile == INVALID_HANDLE_VALUE) - { - LogError("Failed to open file '%s'. GetLastError()=%u", fileName, GetLastError()); - return false; - } - - LARGE_INTEGER DataTemp; - if (GetFileSizeEx(m_hFile, &DataTemp) == 0) - { - LogError("GetFileSizeEx failed. GetLastError()=%u", GetLastError()); - CloseHandle(m_hFile); - m_hFile = INVALID_HANDLE_VALUE; - return false; - } - - m_fileSize = DataTemp.QuadPart; - - if (m_progressReport) - { - m_timer->Start(); - } - - return true; -} - -bool MethodContextIterator::Destroy() -{ - bool ret = true; // assume success - if (m_hFile != INVALID_HANDLE_VALUE) - { - if (!CloseHandle(m_hFile)) - { - LogError("CloseHandle failed. GetLastError()=%u", GetLastError()); - ret = false; - } - m_hFile = INVALID_HANDLE_VALUE; - } - delete m_mc; - m_mc = nullptr; - - if (m_index < m_indexCount) - { - LogWarning("Didn't use all of index count input: %d < %d (i.e., didn't see MC #%d)", m_index, m_indexCount, - m_indexes[m_index]); - } - - delete m_timer; - m_timer = nullptr; - - return ret; -} - -bool MethodContextIterator::MoveNext() -{ - if (m_mc != nullptr) - { - delete m_mc; - m_mc = nullptr; - } - - while (true) - { - // Figure out where the pointer is currently. - LARGE_INTEGER pos; - pos.QuadPart = 0; - if (SetFilePointerEx(m_hFile, pos, &m_pos, FILE_CURRENT) == 0) - { - LogError("SetFilePointerEx failed. GetLastError()=%u", GetLastError()); - return false; // any failure causes us to bail out. - } - - if (m_pos.QuadPart >= m_fileSize) - { - return false; - } - - // Load the current method context. - m_methodContextNumber++; - - if (m_progressReport) - { - if ((m_methodContextNumber % m_progressRate) == 0) - { - m_timer->Stop(); - LogVerbose("Loaded %d at %d per second", m_methodContextNumber, - (int)((double)m_progressRate / m_timer->GetSeconds())); - m_timer->Start(); - } - } - - if (!MethodContext::Initialize(m_methodContextNumber, m_hFile, /* readCompileResults */ true, &m_mc)) - return false; - - // If we have an array of indexes, skip the loaded indexes that have not been specified. - - if (m_indexCount == -1) - { - break; - } - else if (m_index == m_indexCount) - { - return false; // we're beyond the array of indexes - } - else if (m_index < m_indexCount) - { - if (m_indexes[m_index] == m_methodContextNumber) - { - m_index++; - break; - } - } - } - - return true; -} diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontextiterator.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontextiterator.h deleted file mode 100644 index f45e85ea6e3954..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontextiterator.h +++ /dev/null @@ -1,103 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "simpletimer.h" - -// Class to implement method context hive reading and iterating. - -class MethodContextIterator -{ -public: - MethodContextIterator(bool progressReport = false) - : m_hFile(INVALID_HANDLE_VALUE) - , m_fileSize(0) - , m_methodContextNumber(0) - , m_mc(nullptr) - , m_indexCount(-1) - , m_index(0) - , m_indexes(nullptr) - , m_progressReport(progressReport) - , m_progressRate(1000) - , m_timer(nullptr) - { - if (m_progressReport) - { - m_timer = new SimpleTimer(); - } - } - - MethodContextIterator(const int indexCount, const int* indexes, bool progressReport = false) - : m_hFile(INVALID_HANDLE_VALUE) - , m_fileSize(0) - , m_methodContextNumber(0) - , m_mc(nullptr) - , m_indexCount(indexCount) - , m_index(0) - , m_indexes(indexes) - , m_progressReport(progressReport) - , m_progressRate(1000) - , m_timer(nullptr) - { - if (m_progressReport) - { - m_timer = new SimpleTimer(); - } - } - - ~MethodContextIterator() - { - Destroy(); - } - - bool Initialize(const char* fileName); - - bool Destroy(); - - bool MoveNext(); - - // The iterator class owns the memory returned by Current(); the caller should not delete it. - MethodContext* Current() - { - return m_mc; - } - - // In this case, we are giving ownership of the MethodContext* to the caller. So, null out m_mc - // before we return, so we don't attempt to delete it in this class. - MethodContext* CurrentTakeOwnership() - { - MethodContext* ret = m_mc; - m_mc = nullptr; - return ret; - } - - // Return the file position offset of the current method context. - int64_t CurrentPos() - { - return m_pos.QuadPart; - } - - int MethodContextNumber() - { - return m_methodContextNumber; - } - -private: - HANDLE m_hFile; - int64_t m_fileSize; - int m_methodContextNumber; - MethodContext* m_mc; - LARGE_INTEGER m_pos; - - // If m_indexCount==-1, use all method contexts. Otherwise, m_indexCount is the number of elements in the - // m_indexes array, which contains a sorted set of method context indexes to return. In this case, m_index - // is the index of the current element in m_indexes. - const int m_indexCount; - int m_index; - const int* m_indexes; - - // Should we log a progress report as we are loading the method contexts? - // The timer is only used when m_progressReport==true. - bool m_progressReport; - const int m_progressRate; // Report progress every `m_progressRate` method contexts. - SimpleTimer* m_timer; -}; diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontextreader.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontextreader.cpp deleted file mode 100644 index 73206fa3bedfae..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontextreader.cpp +++ /dev/null @@ -1,648 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// MethodContextReader.cpp - Abstraction for reading MethodContexts -// Should eventually support multithreading -//---------------------------------------------------------- - -#include "standardpch.h" -#include "tocfile.h" -#include "methodcontextreader.h" -#include "methodcontext.h" -#include "logging.h" -#include "runtimedetails.h" - -#if TARGET_UNIX -#include -#endif // TARGET_UNIX - -// Just a helper... -HANDLE MethodContextReader::OpenFile(const char* inputFile, DWORD flags) -{ - HANDLE fileHandle = - CreateFileA(inputFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | flags, NULL); - if (fileHandle == INVALID_HANDLE_VALUE) - { - LogError("Failed to open file '%s'. GetLastError()=%u", inputFile, GetLastError()); - } - return fileHandle; -} - -static std::string to_lower(const std::string& input) -{ - std::string res = input; - std::transform(input.cbegin(), input.cend(), res.begin(), [](const char c){ return (char)tolower(c); }); - return res; -} - -bool test_filename_available(const std::string& path) -{ -#ifdef TARGET_WINDOWS - DWORD attribs = GetFileAttributesA(path.c_str()); - return (attribs != INVALID_FILE_ATTRIBUTES) && !(attribs & FILE_ATTRIBUTE_DIRECTORY); -#else // TARGET_WINDOWS - struct stat stat_data; - if (stat(path.c_str(), &stat_data) != 0) - return false; - - return (stat_data.st_mode & S_IFMT) == S_IFREG; -#endif // TARGET_WINDOWS -} - -// Looks for a file named foo.origSuffix.newSuffix or foo.newSuffix -// but only if foo.origSuffix exists. -// -// Note: filename extensions must be lower-case, even on case-sensitive file systems! -std::string MethodContextReader::CheckForPairedFile(const std::string& fileName, - const std::string& origSuffix, - const std::string& newSuffix) -{ - std::string tmp = to_lower(origSuffix); - - // First, check to see if foo.origSuffix exists and is not a directory name - size_t suffix_offset = fileName.find_last_of('.'); - if (suffix_offset == std::string::npos || suffix_offset == 0 || (tmp != to_lower(fileName.substr(suffix_offset)))) - return std::string(); - - if (!test_filename_available(fileName)) - return std::string(); - - // next, check foo.orig.new from foo.orig - tmp = fileName + newSuffix; - if (test_filename_available(tmp)) - return tmp; - - // Finally, lets try foo.new from foo.orig - tmp = fileName.substr(0, suffix_offset) + newSuffix; - if (test_filename_available(tmp)) - return tmp; - - return std::string(); -} - -MethodContextReader::MethodContextReader( - const char* inputFileName, const int* indexes, int indexCount, char* hash, int offset, int increment) - : fileHandle(INVALID_HANDLE_VALUE) - , fileSize(0) - , curMCIndex(0) - , Indexes(indexes) - , IndexCount(indexCount) - , curIndexPos(0) - , Hash(hash) - , curTOCIndex(0) - , Offset(offset) - , Increment(increment) -{ - minipal_mutex_init(&this->mutex); - - std::string tocFileName, mchFileName; - - // First, check to see if they passed an MCH file (look for a paired MCT file) - tocFileName = MethodContextReader::CheckForPairedFile(inputFileName, ".mch", ".mct"); - if (!tocFileName.empty()) - { - mchFileName = inputFileName; - } - else - { - // Okay, it wasn't an MCH file, let's check to see if it was an MCT file - // so check for a paired MCH file instead - mchFileName = MethodContextReader::CheckForPairedFile(inputFileName, ".mct", ".mch"); - if (!mchFileName.empty()) - { - tocFileName = inputFileName; - } - else - { - mchFileName = inputFileName; - } - } - - if (!tocFileName.empty()) - this->tocFile.LoadToc(tocFileName.c_str()); - - // we'll get here even if we don't have a valid index file - this->fileHandle = OpenFile(mchFileName.c_str(), (this->hasTOC() && this->hasIndex()) ? FILE_ATTRIBUTE_NORMAL - : FILE_FLAG_SEQUENTIAL_SCAN); - if (this->fileHandle != INVALID_HANDLE_VALUE) - { - GetFileSizeEx(this->fileHandle, (PLARGE_INTEGER) & this->fileSize); - } - - ReadExcludedMethods(mchFileName); -} - -MethodContextReader::~MethodContextReader() -{ - if (fileHandle != INVALID_HANDLE_VALUE) - { - CloseHandle(this->fileHandle); - } - - minipal_mutex_destroy(&this->mutex); - CleanExcludedMethods(); -} - -bool MethodContextReader::AcquireLock() -{ - minipal_mutex_enter(&this->mutex); - return true; -} - -void MethodContextReader::ReleaseLock() -{ - minipal_mutex_leave(&this->mutex); -} - -bool MethodContextReader::atEof() -{ - int64_t pos = 0; - SetFilePointerEx(this->fileHandle, *(PLARGE_INTEGER)&pos, (PLARGE_INTEGER)&pos, - FILE_CURRENT); // LARGE_INTEGER is a crime against humanity - return pos == this->fileSize; -} - -MethodContextBuffer MethodContextReader::ReadMethodContextNoLock(bool justSkip) -{ - DWORD bytesRead; - char buff[512]; - unsigned int totalLen = 0; - if (atEof()) - { - return MethodContextBuffer(); - } - Assert(ReadFile(this->fileHandle, buff, 2 + sizeof(unsigned int), &bytesRead, NULL) == TRUE); - AssertMsg((buff[0] == 'm') && (buff[1] == 'c'), "Didn't find magic number"); - memcpy(&totalLen, &buff[2], sizeof(unsigned int)); - if (justSkip) - { - int64_t pos = totalLen + 2; - // Just move the file pointer ahead the correct number of bytes - AssertMsg(SetFilePointerEx(this->fileHandle, *(PLARGE_INTEGER)&pos, (PLARGE_INTEGER)&pos, FILE_CURRENT) == TRUE, - "SetFilePointerEx failed (Error %X)", GetLastError()); - - // Increment curMCIndex as we advanced the file pointer by another MC - ++curMCIndex; - - return MethodContextBuffer(0); - } - else - { - unsigned char* buff2 = new unsigned char[totalLen + 2]; // total + End Canary - Assert(ReadFile(this->fileHandle, buff2, totalLen + 2, &bytesRead, NULL) == TRUE); - - // Increment curMCIndex as we read another MC - ++curMCIndex; - - return MethodContextBuffer(buff2, totalLen); - } -} - -MethodContextBuffer MethodContextReader::ReadMethodContext(bool acquireLock, bool justSkip) -{ - if (acquireLock && !this->AcquireLock()) - { - LogError("Can't acquire the reader lock!"); - return MethodContextBuffer(-1); - } - - struct Param - { - MethodContextReader* pThis; - MethodContextBuffer ret; - bool justSkip; - } param; - param.pThis = this; - param.ret = MethodContextBuffer(-2); - param.justSkip = justSkip; - - PAL_TRY(Param*, pParam, ¶m) - { - pParam->ret = pParam->pThis->ReadMethodContextNoLock(pParam->justSkip); - } - PAL_FINALLY - { - this->ReleaseLock(); - } - PAL_ENDTRY - - return param.ret; -} - -// Read a method context buffer from the ContextCollection -// (either a hive [single] or an index) -MethodContextBuffer MethodContextReader::GetNextMethodContext() -{ - struct Param : FilterSuperPMIExceptionsParam_CaptureException - { - MethodContextReader* pThis; - MethodContextBuffer mcb; - } param; - param.pThis = this; - - PAL_TRY(Param*, pParam, ¶m) - { - pParam->mcb = pParam->pThis->GetNextMethodContextHelper(); - } - PAL_EXCEPT_FILTER(FilterSuperPMIExceptions_CaptureExceptionAndStop) - { - LogError("Method %d is of low integrity.", GetMethodContextIndex()); - param.mcb = MethodContextBuffer(-1); - } - PAL_ENDTRY - - return param.mcb; -} - -MethodContextBuffer MethodContextReader::GetNextMethodContextHelper() -{ - // If we have an offset/increment combo - if (this->Offset > 0 && this->Increment > 0) - return GetNextMethodContextFromOffsetIncrement(); - - // If we have an index - if (this->hasIndex()) - { - if (this->curIndexPos < this->IndexCount) - { - // If we are not done with all of them - return GetNextMethodContextFromIndexes(); - } - else // We are done with all of them, return - return MethodContextBuffer(); - } - - // If we have a hash - if (this->Hash != nullptr) - return GetNextMethodContextFromHash(); - - // If we don't have any of these options return all MCs one by one - return this->ReadMethodContext(true); -} - -// Read a method context buffer from the ContextCollection using Indexes -MethodContextBuffer MethodContextReader::GetNextMethodContextFromIndexes() -{ - // Assert if we don't have an Index or we are done with all the indexes - Assert(this->hasIndex() && this->curIndexPos < this->IndexCount); - - if (this->hasTOC()) - { - // If we have an index & we have a TOC, we can just jump to that method! - return this->GetSpecificMethodContext(this->Indexes[this->curIndexPos++]); - } - else - { - // Find the current method (either #0, or the previous index) - int curMethod = this->curIndexPos ? this->Indexes[this->curIndexPos - 1] : 0; - // Get the next method - int nextMethod = this->Indexes[this->curIndexPos++]; - // Skip over methods until we get to the right now - while (++curMethod < nextMethod) - { - // Skip a method context - MethodContextBuffer mcb = this->ReadMethodContext(true, true); - if (mcb.allDone() || mcb.Error()) - return mcb; - } - } - return this->ReadMethodContext(true); -} - -// Read a method context buffer from the ContextCollection using Hash -MethodContextBuffer MethodContextReader::GetNextMethodContextFromHash() -{ - // Assert if we don't have a valid hash - Assert(this->Hash != nullptr); - - if (this->hasTOC()) - { - // We have a TOC so lets go through the TOCElements - // one-by-one till we find a matching hash - for (; curTOCIndex < (int)this->tocFile.GetTocCount(); curTOCIndex++) - { - if (_strnicmp(this->Hash, this->tocFile.GetElementPtr(curTOCIndex)->Hash, MM3_HASH_BUFFER_SIZE) == 0) - { - // We found a match, return this specific method - return this->GetSpecificMethodContext(this->tocFile.GetElementPtr(curTOCIndex++)->Number); - } - } - - // No more matches in the TOC for our hash value - return MethodContextBuffer(); - } - else - { - // Keep reading all MCs until we hit a match - // or we reach the end or hit an error - while (true) - { - // Read a method context - // we can't skip because we need to calculate hashes - MethodContextBuffer mcb = this->ReadMethodContext(true, false); - if (mcb.allDone() || mcb.Error()) - return mcb; - - char mcHash[MM3_HASH_BUFFER_SIZE]; - - // Create a temporary copy of mcb.buff plus ending 2-byte canary - // this will get freed up by MethodContext constructor - unsigned char* buff = new unsigned char[mcb.size + 2]; - memcpy(buff, mcb.buff, mcb.size + 2); - - MethodContext* mc; - - if (!MethodContext::Initialize(-1, buff, mcb.size, /* readCompileResults */ true, &mc)) - return MethodContextBuffer(-1); - - mc->dumpMethodHashToBuffer(mcHash, MM3_HASH_BUFFER_SIZE); - delete mc; - - if (_strnicmp(this->Hash, mcHash, MM3_HASH_BUFFER_SIZE) == 0) - { - // We found a match, return this specific method - return mcb; - } - } - } - - // We should never get here under normal conditions - AssertMsg(true, "Unexpected condition hit while reading input file."); - return MethodContextBuffer(-1); -} - -// Read a method context buffer from the ContextCollection using offset/increment -MethodContextBuffer MethodContextReader::GetNextMethodContextFromOffsetIncrement() -{ - // Assert if we don't have a valid increment/offset combo - Assert(this->Offset > 0 && this->Increment > 0); - - int methodNumber = this->curMCIndex > 0 ? this->curMCIndex + this->Increment : this->Offset; - - if (this->hasTOC()) - { - // Check if we are within the TOC - if ((int)this->tocFile.GetTocCount() >= methodNumber) - { - // We have a TOC so we can request a specific method context - return this->GetSpecificMethodContext(methodNumber); - } - else - return MethodContextBuffer(); - } - else - { - // Keep skipping MCs until we get to the one we need to return - while (this->curMCIndex + 1 < methodNumber) - { - // skip over a method - MethodContextBuffer mcb = this->ReadMethodContext(true, true); - if (mcb.allDone() || mcb.Error()) - return mcb; - } - } - return this->ReadMethodContext(true); -} - -bool MethodContextReader::hasIndex() -{ - return this->IndexCount > 0; -} - -bool MethodContextReader::hasTOC() -{ - return this->tocFile.GetTocCount() > 0; -} - -bool MethodContextReader::isValid() -{ - return this->fileHandle != INVALID_HANDLE_VALUE; -} - -// Return a measure of "progress" through the method contexts, as follows: -// 1. With a given set of indices, this is the current index array position. -// 2. With a TOC, this is the current method context number. -// 3. Otherwise, it is the current byte offset in the method context file. -// Only useful when compared with `TotalWork()`. -double MethodContextReader::Progress() -{ - if (this->hasIndex()) - { - return (double)this->curIndexPos; - } - else if (this->hasTOC()) - { - return (double)this->curMCIndex; - } - else - { - this->AcquireLock(); - int64_t pos = 0; - SetFilePointerEx(this->fileHandle, *(PLARGE_INTEGER)&pos, (PLARGE_INTEGER)&pos, FILE_CURRENT); - this->ReleaseLock(); - return (double)pos; - } -} - -// Return a measure of the total amount of work to be done, as follows: -// 1. With a given set of indices, this is the total number of indices to return. -// 2. With a TOC, this is the number of method contexts in the TOC. -// 3. Otherwise, it is the size in bytes of the method context file. -// Only useful when compared with `Progress()`. -double MethodContextReader::TotalWork() -{ - if (this->hasIndex()) - { - return (double)this->IndexCount; - } - else if (this->hasTOC()) - { - return (double)this->tocFile.GetTocCount(); - } - else - { - return (double)this->fileSize; - } -} - -// Compute a percentage completion value using the previously defined -// Progress() and TotalWork() functions. -// Note that this is not useful to the user as a total percentage complete number -// in the case of small number of methods and a large compile repeat count. -double MethodContextReader::PercentComplete() -{ - return 100.0 * Progress() / TotalWork(); -} - -// Binary search to get this method number from the index -// Returns -1 for not found, or -2 for not indexed -// Interview question alert: hurray for CLR headers incompatibility with STL :-( -// Note that TOC is 0 based and MC# are 1 based! -int64_t MethodContextReader::GetOffset(unsigned int methodNumber) -{ - if (!this->hasTOC()) - return -2; - size_t high = this->tocFile.GetTocCount() - 1; - size_t low = 0; - while (low <= high) - { - size_t pos = (high + low) / 2; - unsigned int num = this->tocFile.GetElementPtr(pos)->Number; - if (num == methodNumber) - return this->tocFile.GetElementPtr(pos)->Offset; - if (num > methodNumber) - high = pos - 1; - else - low = pos + 1; - } - return -1; -} - -MethodContextBuffer MethodContextReader::GetSpecificMethodContext(unsigned int methodNumber) -{ - int64_t pos = this->GetOffset(methodNumber); - if (pos < 0) - { - return MethodContextBuffer(-3); - } - - // Take the IO lock before we set the file pointer, so we can do this on multiple threads - if (!this->AcquireLock()) - { - return MethodContextBuffer(-2); - } - if (SetFilePointerEx(this->fileHandle, *(PLARGE_INTEGER)&pos, (PLARGE_INTEGER)&pos, FILE_BEGIN)) - { - // ReadMethodContext will release the lock, but we already acquired it - MethodContextBuffer mcb = this->ReadMethodContext(false); - - // The curMCIndex value updated by ReadMethodContext() is incorrect - // since we are repositioning the file pointer we need to update it - curMCIndex = methodNumber; - - return mcb; - } - else - { - // Don't forget to release the lock! - this->ReleaseLock(); - return MethodContextBuffer(-4); - } -} - -// Read the file with excluded methods hashes and save them. -void MethodContextReader::ReadExcludedMethods(std::string mchFileName) -{ - excludedMethodsList = nullptr; - - size_t suffix_offset = mchFileName.find_last_of('.'); - if (suffix_offset == std::string::npos) - { - LogError("Failed to get file extension from %s", mchFileName.c_str()); - return; - } - std::string suffix = mchFileName.substr(suffix_offset); - std::string excludeFileName = MethodContextReader::CheckForPairedFile(mchFileName, suffix.c_str(), ".exc"); - - if (excludeFileName.empty()) - { - return; - } - HANDLE excludeFileHandle = OpenFile(excludeFileName.c_str()); - if (excludeFileHandle != INVALID_HANDLE_VALUE) - { - int64_t excludeFileSizeLong; - GetFileSizeEx(excludeFileHandle, (PLARGE_INTEGER)&excludeFileSizeLong); - unsigned excludeFileSize = (unsigned)excludeFileSizeLong; - - char* buffer = new char[excludeFileSize + 1]; - DWORD bytesRead; - bool success = (ReadFile(excludeFileHandle, buffer, excludeFileSize, &bytesRead, NULL) == TRUE); - CloseHandle(excludeFileHandle); - - if (!success || excludeFileSize != bytesRead) - { - LogError("Failed to read the exclude file."); - delete[] buffer; - return; - } - - buffer[excludeFileSize] = 0; - - int counter = 0; - - char* curr = buffer; - while (*curr != 0) - { - while (isspace(*curr)) - { - curr++; - } - - std::string hash; - while (*curr != 0 && !isspace(*curr)) - { - hash += *curr; - curr++; - } - - if (hash.length() == MM3_HASH_BUFFER_SIZE - 1) - { - StringList* node = new StringList(); - node->hash = hash; - node->next = excludedMethodsList; - excludedMethodsList = node; - counter++; - } - else - { - LogInfo("The exclude file contains wrong values: %s.", hash.c_str()); - } - } - delete[] buffer; - LogInfo("Exclude file %s contains %d methods.", excludeFileName.c_str(), counter); - } -} - -// Free memory used for excluded methods. -void MethodContextReader::CleanExcludedMethods() -{ - while (excludedMethodsList != nullptr) - { - StringList* next = excludedMethodsList->next; - delete excludedMethodsList; - excludedMethodsList = next; - } -} - -// Return should this method context be excluded from the replay or not. -bool MethodContextReader::IsMethodExcluded(MethodContext* mc) -{ - if (excludedMethodsList != nullptr) - { - char md5HashBuf[MM3_HASH_BUFFER_SIZE] = {0}; - mc->dumpMethodHashToBuffer(md5HashBuf, MM3_HASH_BUFFER_SIZE); - for (StringList* node = excludedMethodsList; node != nullptr; node = node->next) - { - if (strcmp(node->hash.c_str(), md5HashBuf) == 0) - { - return true; - } - } - } - return false; -} - -void MethodContextReader::Reset(const int* newIndexes, int newIndexCount) -{ - int64_t pos = 0; - BOOL result = SetFilePointerEx(fileHandle, *(PLARGE_INTEGER)&pos, NULL, FILE_BEGIN); - assert(result); - - Indexes = newIndexes; - IndexCount = newIndexCount; - curIndexPos = 0; - curMCIndex = 0; - curTOCIndex = 0; -} diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontextreader.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontextreader.h deleted file mode 100644 index f5ef48009b8370..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontextreader.h +++ /dev/null @@ -1,159 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// MethodContextReader.h - Abstraction for reading MethodContexts -// Should eventually support multithreading -//---------------------------------------------------------- -#ifndef _MethodContextReader -#define _MethodContextReader - -#include "methodcontext.h" -#include "tocfile.h" -#include - -struct MethodContextBuffer -{ -private: - static const int Completed = 0x1234abcd; - -public: - unsigned char* buff; - DWORD size; - - MethodContextBuffer() : buff(nullptr), size(Completed) - { - } - MethodContextBuffer(DWORD error) : buff(nullptr), size(error) - { - } - MethodContextBuffer(unsigned char* b, DWORD e) : buff(b), size(e) - { - } - - bool allDone() - { - return size == Completed && buff == nullptr; - } - bool Error() - { - return size != 0 && size != Completed && buff == nullptr; - } -}; - -// The pack(4) directive is so that each entry is 12 bytes, instead of 16 -#pragma pack(push) -#pragma pack(4) -class MethodContextReader -{ -private: - // The MC/MCH file - HANDLE fileHandle; - - // The size of the MC/MCH file - int64_t fileSize; - - // Current MC index in the input MC/MCH file - int curMCIndex; - - // The synchronization mutex - minipal_mutex mutex; - bool AcquireLock(); - void ReleaseLock(); - - TOCFile tocFile; - - // Method ranges to process - // If you have an index file, these things get processed - // much faster, now - const int* Indexes; - int IndexCount; - int curIndexPos; - - // Method hash to process - // If you have an index file, these things get processed - // much faster, now - char* Hash; - int curTOCIndex; - - // Offset/increment if running in parallel mode - // If you have an index file, these things get processed - // much faster, now - int Offset; - int Increment; - - struct StringList - { - StringList* next; - std::string hash; - }; - StringList* excludedMethodsList; - - // Binary search to get this method number from the index - // Returns -1 for not found, or -2 for not indexed - int64_t GetOffset(unsigned int methodNumber); - - // Just a helper... - static HANDLE OpenFile(const char* inputFile, DWORD flags = FILE_ATTRIBUTE_NORMAL); - - MethodContextBuffer ReadMethodContextNoLock(bool justSkip = false); - MethodContextBuffer ReadMethodContext(bool acquireLock, bool justSkip = false); - MethodContextBuffer GetSpecificMethodContext(unsigned int methodNumber); - - MethodContextBuffer GetNextMethodContextFromIndexes(); - MethodContextBuffer GetNextMethodContextFromHash(); - MethodContextBuffer GetNextMethodContextFromOffsetIncrement(); - MethodContextBuffer GetNextMethodContextHelper(); - - // Looks for a file named foo.origSuffix.newSuffix or foo.newSuffix - // but only if foo.origSuffix exists - static std::string CheckForPairedFile(const std::string& fileName, - const std::string& origSuffix, - const std::string& newSuffix); - - // are we're at the end of the file... - bool atEof(); - - // Do we have a valid TOC? - bool hasTOC(); - - // Do we have a valid index? - bool hasIndex(); - - void ReadExcludedMethods(std::string mchFileName); - void CleanExcludedMethods(); - -public: - MethodContextReader(const char* inputFileName, - const int* indexes = nullptr, - int indexCount = -1, - char* hash = nullptr, - int offset = -1, - int increment = -1); - ~MethodContextReader(); - - // Read a method context buffer from the ContextCollection - // (either a hive [single] or an index) - MethodContextBuffer GetNextMethodContext(); - // No C++ exceptions, so the constructor has to always succeed... - bool isValid(); - - double Progress(); - double TotalWork(); - double PercentComplete(); - - // Returns the index of the last MethodContext read by GetNextMethodContext - inline int GetMethodContextIndex() - { - return curMCIndex; - } - - // Return should this method context be excluded from the replay or not. - bool IsMethodExcluded(MethodContext* mc); - - // Reset for reading a new sequence of method indices - void Reset(const int* newIndexes, int newIndexCount); -}; -#pragma pack(pop) - -#endif diff --git a/src/coreclr/tools/superpmi/superpmi-shared/runtimedetails.h b/src/coreclr/tools/superpmi/superpmi-shared/runtimedetails.h deleted file mode 100644 index f4a351f0585561..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/runtimedetails.h +++ /dev/null @@ -1,19 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// RuntimeDetails.h - the collection of runtime includes that we need to access. -//---------------------------------------------------------- -#ifndef _RuntimeDetails -#define _RuntimeDetails - -#include -#include -#include -#include - -// Jit Exports -typedef ICorJitCompiler*(__stdcall* PgetJit)(); -typedef void(__stdcall* PjitStartup)(ICorJitHost* host); - -#endif diff --git a/src/coreclr/tools/superpmi/superpmi-shared/simpletimer.cpp b/src/coreclr/tools/superpmi/superpmi-shared/simpletimer.cpp deleted file mode 100644 index 87fe784e1c784c..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/simpletimer.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "standardpch.h" -#include "logging.h" -#include "simpletimer.h" -#include "minipal/time.h" - -SimpleTimer::SimpleTimer() -{ - start = 0; - stop = 0; - - proc_freq = minipal_hires_tick_frequency(); -} - -SimpleTimer::~SimpleTimer() -{ -} - -void SimpleTimer::Start() -{ - start = minipal_hires_ticks(); -} - -void SimpleTimer::Stop() -{ - stop = minipal_hires_ticks(); -} - -double SimpleTimer::GetMilliseconds() -{ - return GetSeconds() * 1000.0; -} - -double SimpleTimer::GetSeconds() -{ - return ((stop - start) / (double)proc_freq); -} diff --git a/src/coreclr/tools/superpmi/superpmi-shared/simpletimer.h b/src/coreclr/tools/superpmi/superpmi-shared/simpletimer.h deleted file mode 100644 index 48aae5e12b0fff..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/simpletimer.h +++ /dev/null @@ -1,25 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#ifndef _SimpleTimer -#define _SimpleTimer - -#include - -class SimpleTimer -{ -public: - SimpleTimer(); - ~SimpleTimer(); - - void Start(); - void Stop(); - double GetMilliseconds(); - double GetSeconds(); - -private: - int64_t proc_freq; - int64_t start; - int64_t stop; -}; -#endif diff --git a/src/coreclr/tools/superpmi/superpmi-shared/spmidumphelper.cpp b/src/coreclr/tools/superpmi/superpmi-shared/spmidumphelper.cpp deleted file mode 100644 index 5c4b5298ab6009..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/spmidumphelper.cpp +++ /dev/null @@ -1,285 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// SpmiDumpHelper.cpp - a helper to dump structs that are used in JitEEInterface calls and spmi collections. -//---------------------------------------------------------- - -#include "standardpch.h" -#include "spmidumphelper.h" -#include "spmirecordhelper.h" -#include - -std::string SpmiDumpHelper::DumpAgnostic_CORINFO_RESOLVED_TOKENin( - const Agnostic_CORINFO_RESOLVED_TOKENin& tokenIn) -{ - char buffer[MAX_BUFFER_SIZE]; - sprintf_s(buffer, MAX_BUFFER_SIZE, "tc-%016llX ts-%016llX tok-%08X tt-%u", tokenIn.tokenContext, tokenIn.tokenScope, - tokenIn.token, tokenIn.tokenType); - return std::string(buffer); -} - -std::string SpmiDumpHelper::DumpAgnostic_CORINFO_RESOLVED_TOKENout( - const Agnostic_CORINFO_RESOLVED_TOKENout& tokenOut) -{ - char buffer[MAX_BUFFER_SIZE]; - sprintf_s(buffer, MAX_BUFFER_SIZE, "cls-%016llX meth-%016llX fld-%016llX ti-%u ts-%u mi-%u ms-%u", tokenOut.hClass, - tokenOut.hMethod, tokenOut.hField, tokenOut.pTypeSpec_Index, tokenOut.cbTypeSpec, - tokenOut.pMethodSpec_Index, tokenOut.cbMethodSpec); - return std::string(buffer); -} - -std::string SpmiDumpHelper::DumpAgnostic_CORINFO_RESOLVED_TOKEN( - const Agnostic_CORINFO_RESOLVED_TOKEN& token) -{ - return DumpAgnostic_CORINFO_RESOLVED_TOKENin(token.inValue) + std::string(" ") + - DumpAgnostic_CORINFO_RESOLVED_TOKENout(token.outValue); -} - -std::string SpmiDumpHelper::DumpAgnostic_CORINFO_LOOKUP_KIND( - const Agnostic_CORINFO_LOOKUP_KIND& lookupKind) -{ - char buffer[MAX_BUFFER_SIZE]; - sprintf_s(buffer, MAX_BUFFER_SIZE, "nrl-%u rlk-%u", lookupKind.needsRuntimeLookup, lookupKind.runtimeLookupKind); - return std::string(buffer); -} - -std::string SpmiDumpHelper::DumpAgnostic_CORINFO_CONST_LOOKUP( - const Agnostic_CORINFO_CONST_LOOKUP& constLookup) -{ - char buffer[MAX_BUFFER_SIZE]; - sprintf_s(buffer, MAX_BUFFER_SIZE, "at-%u handle/address-%016llX", constLookup.accessType, constLookup.handle); - return std::string(buffer); -} - -std::string SpmiDumpHelper::DumpAgnostic_CORINFO_RUNTIME_LOOKUP( - const Agnostic_CORINFO_RUNTIME_LOOKUP& lookup) -{ - char buffer[MAX_BUFFER_SIZE]; - sprintf_s(buffer, MAX_BUFFER_SIZE, " sig-%016llX hlp-%u ind-%u tfn-%u so-%u { ", lookup.signature, lookup.helper, - lookup.indirections, lookup.testForNull, lookup.sizeOffset); - std::string resultDump(buffer); - for (int i = 0; i < CORINFO_MAXINDIRECTIONS; i++) - { - sprintf_s(buffer, MAX_BUFFER_SIZE, "%016llX ", lookup.offsets[i]); - resultDump += std::string(buffer); - } - resultDump += std::string("}"); - return resultDump; -} - -std::string SpmiDumpHelper::DumpAgnostic_CORINFO_LOOKUP(const Agnostic_CORINFO_LOOKUP& lookup) -{ - std::string kind = DumpAgnostic_CORINFO_LOOKUP_KIND(lookup.lookupKind); - std::string lookupDescription; - if (lookup.lookupKind.needsRuntimeLookup) - { - lookupDescription = DumpAgnostic_CORINFO_RUNTIME_LOOKUP(lookup.runtimeLookup); - } - else - { - lookupDescription = DumpAgnostic_CORINFO_CONST_LOOKUP(lookup.constLookup); - } - return kind + std::string(" ") + lookupDescription; -} - -// Dump the consecutive elements of a DenseLightweightMap, which are DWORDLONG, and assumed to represent an array of handles. -void SpmiDumpHelper::FormatHandleArray(char*& pbuf, int& sizeOfBuffer, const DenseLightWeightMap* map, DWORD count, DWORD startIndex) -{ - int cch; - - cch = sprintf_s(pbuf, sizeOfBuffer, "{"); - pbuf += cch; - sizeOfBuffer -= cch; - - const unsigned int maxHandleArrayDisplayElems = 5; // Don't display more than this. - const unsigned int handleArrayDisplayElems = min(maxHandleArrayDisplayElems, (unsigned int)count); - - bool first = true; - for (DWORD i = startIndex; i < startIndex + handleArrayDisplayElems; i++) - { - cch = sprintf_s(pbuf, sizeOfBuffer, "%s%016llX", first ? "" : " ", map->Get(i)); - pbuf += cch; - sizeOfBuffer -= cch; - - first = false; - } - - if (handleArrayDisplayElems < count) - { - cch = sprintf_s(pbuf, sizeOfBuffer, " ..."); - pbuf += cch; - sizeOfBuffer -= cch; - } - - cch = sprintf_s(pbuf, sizeOfBuffer, "}"); - pbuf += cch; - sizeOfBuffer -= cch; -} - -void SpmiDumpHelper::FormatAgnostic_CORINFO_SIG_INST_Element( - char*& pbuf, - int& sizeOfBuffer, - const char* prefixStr, - const char* instCountPrefixStr, - const char* instIndexPrefixStr, - unsigned handleInstCount, - unsigned handleInstIndex, - const DenseLightWeightMap* handleMap) -{ - int cch = sprintf_s(pbuf, sizeOfBuffer, "%s%s-%u %s-%u ", prefixStr, instCountPrefixStr, handleInstCount, instIndexPrefixStr, handleInstIndex); - pbuf += cch; - sizeOfBuffer -= cch; - - FormatHandleArray(pbuf, sizeOfBuffer, handleMap, handleInstCount, handleInstIndex); -} - -std::string SpmiDumpHelper::DumpAgnostic_CORINFO_SIG_INST_Element( - const char* prefixStr, - const char* instCountPrefixStr, - const char* instIndexPrefixStr, - unsigned handleInstCount, - unsigned handleInstIndex, - const DenseLightWeightMap* handleMap) -{ - char buffer[MAX_BUFFER_SIZE]; - char* pbuf = buffer; - int sizeOfBuffer = sizeof(buffer); - - FormatAgnostic_CORINFO_SIG_INST_Element(pbuf, sizeOfBuffer, prefixStr, instCountPrefixStr, instIndexPrefixStr, handleInstCount, handleInstIndex, handleMap); - - return std::string(buffer); -} - -std::string SpmiDumpHelper::DumpCorInfoFlag(CorInfoFlag flags) -{ - std::string s(""); - -#define AddFlag(__name)\ - if (flags & __name) { s += std::string(" ") + std::string(#__name); flags = (CorInfoFlag)((DWORD)flags & ~(DWORD)__name); } - - AddFlag(CORINFO_FLG_STATIC); - AddFlag(CORINFO_FLG_FINAL); - AddFlag(CORINFO_FLG_SYNCH); - AddFlag(CORINFO_FLG_VIRTUAL); - AddFlag(CORINFO_FLG_INTRINSIC_TYPE); - AddFlag(CORINFO_FLG_ABSTRACT); - AddFlag(CORINFO_FLG_EnC); - AddFlag(CORINFO_FLG_FORCEINLINE); - AddFlag(CORINFO_FLG_SHAREDINST); - AddFlag(CORINFO_FLG_DELEGATE_INVOKE); - AddFlag(CORINFO_FLG_PINVOKE); - AddFlag(CORINFO_FLG_NOGCCHECK); - AddFlag(CORINFO_FLG_INTRINSIC); - AddFlag(CORINFO_FLG_CONSTRUCTOR); - AddFlag(CORINFO_FLG_AGGRESSIVE_OPT); - AddFlag(CORINFO_FLG_DISABLE_TIER0_FOR_LOOPS); - AddFlag(CORINFO_FLG_DONT_INLINE); - AddFlag(CORINFO_FLG_DONT_INLINE_CALLER); - AddFlag(CORINFO_FLG_VALUECLASS); - AddFlag(CORINFO_FLG_VAROBJSIZE); - AddFlag(CORINFO_FLG_ARRAY); - AddFlag(CORINFO_FLG_OVERLAPPING_FIELDS); - AddFlag(CORINFO_FLG_INTERFACE); - AddFlag(CORINFO_FLG_CONTAINS_GC_PTR); - AddFlag(CORINFO_FLG_DELEGATE); - AddFlag(CORINFO_FLG_BYREF_LIKE); - AddFlag(CORINFO_FLG_BEFOREFIELDINIT); - AddFlag(CORINFO_FLG_GENERIC_TYPE_VARIABLE); - AddFlag(CORINFO_FLG_UNSAFE_VALUECLASS); - -#undef AddFlag - - if (flags != 0) - { - char buffer[MAX_BUFFER_SIZE]; - sprintf_s(buffer, MAX_BUFFER_SIZE, " Unknown flags-%08X", flags); - s += std::string(buffer); - } - - return s; -} - -std::string SpmiDumpHelper::DumpJitFlags(CORJIT_FLAGS corJitFlags) -{ - return DumpJitFlags(corJitFlags.GetFlagsRaw()); -} - -std::string SpmiDumpHelper::DumpJitFlags(unsigned long long flags) -{ - std::string s(""); - -#define AddFlag(__name)\ - if (flags & (1ull << CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_ ## __name)) { \ - s += std::string(" ") + std::string(#__name); \ - flags &= ~(1ull << CORJIT_FLAGS::CorJitFlag::CORJIT_FLAG_ ## __name); } - - // Note some flags are target dependent, but we want to - // be target-agnostic. So we use numbers for the few - // flags that are not universally defined. - -#define AddFlagNumeric(__name, __val)\ - if (flags & (1ull << __val)) { \ - s += std::string(" ") + std::string(#__name); \ - flags &= ~(1ull <<__val); } - - AddFlag(SPEED_OPT); - AddFlag(SIZE_OPT); - AddFlag(DEBUG_CODE); - AddFlag(DEBUG_EnC); - AddFlag(DEBUG_INFO); - AddFlag(MIN_OPT); - AddFlag(ENABLE_CFG); - AddFlag(OSR); - AddFlag(ALT_JIT); - AddFlag(FROZEN_ALLOC_ALLOWED); - AddFlag(PORTABLE_ENTRY_POINTS); - AddFlag(AOT); - AddFlag(PROF_ENTERLEAVE); - AddFlag(PROF_NO_PINVOKE_INLINE); - AddFlag(ASYNC); - AddFlag(RELOC); - AddFlag(IL_STUB); - AddFlag(PROCSPLIT); - AddFlag(BBINSTR); - AddFlag(BBINSTR_IF_LOOPS); - AddFlag(BBOPT); - AddFlag(FRAMED); - AddFlag(USE_PINVOKE_HELPERS); - AddFlag(REVERSE_PINVOKE); - AddFlag(TRACK_TRANSITIONS); - AddFlag(TIER0); - AddFlag(TIER1); - AddFlag(NO_INLINING); - - // arm32 only - // - AddFlagNumeric(RELATIVE_CODE_RELOCS, 29); - AddFlagNumeric(SOFTFP_ABI, 30); - - AddFlag(USE_DISPATCH_HELPERS); - AddFlag(WASM_MANAGED_HELPER); - - // "Extra jit flag" support - // - AddFlagNumeric(HAS_PGO, EXTRA_JIT_FLAGS::HAS_PGO); - AddFlagNumeric(HAS_EDGE_PROFILE, EXTRA_JIT_FLAGS::HAS_EDGE_PROFILE); - AddFlagNumeric(HAS_CLASS_PROFILE, EXTRA_JIT_FLAGS::HAS_CLASS_PROFILE); - AddFlagNumeric(HAS_METHOD_PROFILE, EXTRA_JIT_FLAGS::HAS_METHOD_PROFILE); - AddFlagNumeric(HAS_LIKELY_CLASS, EXTRA_JIT_FLAGS::HAS_LIKELY_CLASS); - AddFlagNumeric(HAS_LIKELY_METHOD, EXTRA_JIT_FLAGS::HAS_LIKELY_METHOD); - AddFlagNumeric(HAS_STATIC_PROFILE, EXTRA_JIT_FLAGS::HAS_STATIC_PROFILE); - AddFlagNumeric(HAS_DYNAMIC_PROFILE, EXTRA_JIT_FLAGS::HAS_DYNAMIC_PROFILE); - -#undef AddFlag -#undef AddFlagNumeric - - if (flags != 0) - { - char buffer[MAX_BUFFER_SIZE]; - sprintf_s(buffer, MAX_BUFFER_SIZE, " Unknown jit flags-%016llX", flags); - s += std::string(buffer); - } - - return s; -} diff --git a/src/coreclr/tools/superpmi/superpmi-shared/spmidumphelper.h b/src/coreclr/tools/superpmi/superpmi-shared/spmidumphelper.h deleted file mode 100644 index b989fb50d1c468..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/spmidumphelper.h +++ /dev/null @@ -1,175 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// SpmiDumpHelper.h - a helper to dump structs that are used in JitEEInterface calls and spmi collections. -//---------------------------------------------------------- - -#ifndef _SpmiDumpHelper -#define _SpmiDumpHelper - -#include "methodcontext.h" - -class SpmiDumpHelper -{ -public: - static std::string DumpAgnostic_CORINFO_RESOLVED_TOKENin( - const Agnostic_CORINFO_RESOLVED_TOKENin& tokenIn); - static std::string DumpAgnostic_CORINFO_RESOLVED_TOKENout( - const Agnostic_CORINFO_RESOLVED_TOKENout& tokenOut); - static std::string DumpAgnostic_CORINFO_RESOLVED_TOKEN(const Agnostic_CORINFO_RESOLVED_TOKEN& token); - static std::string DumpAgnostic_CORINFO_LOOKUP_KIND(const Agnostic_CORINFO_LOOKUP_KIND& lookupKind); - static std::string DumpAgnostic_CORINFO_CONST_LOOKUP( - const Agnostic_CORINFO_CONST_LOOKUP& constLookup); - static std::string DumpAgnostic_CORINFO_RUNTIME_LOOKUP( - const Agnostic_CORINFO_RUNTIME_LOOKUP& lookup); - static std::string DumpAgnostic_CORINFO_LOOKUP(const Agnostic_CORINFO_LOOKUP& lookup); - - template - static std::string DumpPSig( - DWORD pSig_Index, - DWORD cbSig, - LightWeightMap* buffers); - - template - static std::string DumpAgnostic_CORINFO_SIG_INFO( - const Agnostic_CORINFO_SIG_INFO& sigInfo, - LightWeightMap* buffers, - const DenseLightWeightMap* handleMap); - - static std::string DumpAgnostic_CORINFO_SIG_INST_Element( - const char* prefixStr, - const char* instCountPrefixStr, - const char* instIndexPrefixStr, - unsigned handleInstCount, - unsigned handleInstIndex, - const DenseLightWeightMap* handleMap); - - static std::string DumpCorInfoFlag(CorInfoFlag flags); - - static std::string DumpJitFlags(CORJIT_FLAGS corJitFlags); - static std::string DumpJitFlags(unsigned long long rawFlags); - -private: - - static void FormatAgnostic_CORINFO_SIG_INST_Element( - char*& pbuf, - int& sizeOfBuffer, - const char* prefixStr, - const char* instCountPrefixStr, - const char* instIndexPrefixStr, - unsigned handleInstCount, - unsigned handleInstIndex, - const DenseLightWeightMap* handleMap); - - static void FormatHandleArray(char*& pbuf, int& sizeOfBuffer, const DenseLightWeightMap* map, DWORD count, DWORD startIndex); - - static const int MAX_BUFFER_SIZE = 1000; -}; - -template -inline std::string SpmiDumpHelper::DumpPSig( - DWORD pSig_Index, - DWORD cbSig, - LightWeightMap* buffers) -{ - char buffer[MAX_BUFFER_SIZE]; - char* pbuf = buffer; - int sizeOfBuffer = sizeof(buffer); - int cch; - - cch = sprintf_s(pbuf, sizeOfBuffer, "cbSig-%u, si-%08X", - cbSig, pSig_Index); - pbuf += cch; - sizeOfBuffer -= cch; - - // Add the signature bytes to the output. - // Normally, pSig_Index will be -1 if there is no signature. However, in some error cases - // it will be 0 if there are other reasons why it will never be consulted (like a "return value" - // from an API of `false`). So check that cbSig > 0 before calling GetBuffer(), just to be sure - // there is some data to find. - - if (cbSig == 0) - { - cch = sprintf_s(pbuf, sizeOfBuffer, " (SIG SIZE ZERO)"); - pbuf += cch; - sizeOfBuffer -= cch; - } - else - { - PCCOR_SIGNATURE pSig = buffers->GetBuffer(pSig_Index); - if (pSig == nullptr) - { - cch = sprintf_s(pbuf, sizeOfBuffer, " (NO SIG FOUND)"); - pbuf += cch; - sizeOfBuffer -= cch; - } - else - { - cch = sprintf_s(pbuf, sizeOfBuffer, " sig-{"); - pbuf += cch; - sizeOfBuffer -= cch; - - const size_t maxSigDisplayBytes = 25; // Don't display more than this. - const size_t sigDisplayBytes = min(maxSigDisplayBytes, (size_t)cbSig); - - // TODO: display character representation of the types? - - for (DWORD i = 0; i < sigDisplayBytes; i++) - { - if (i > 0) - { - cch = sprintf_s(pbuf, sizeOfBuffer, " "); - pbuf += cch; - sizeOfBuffer -= cch; - } - cch = sprintf_s(pbuf, sizeOfBuffer, "%02X", pSig[i]); - pbuf += cch; - sizeOfBuffer -= cch; - } - - if (sigDisplayBytes < cbSig) - { - cch = sprintf_s(pbuf, sizeOfBuffer, "..."); - pbuf += cch; - sizeOfBuffer -= cch; - } - - cch = sprintf_s(pbuf, sizeOfBuffer, "}"); - pbuf += cch; - sizeOfBuffer -= cch; - } - buffers->Unlock(); - } - - return std::string(buffer); -} - -template -inline std::string SpmiDumpHelper::DumpAgnostic_CORINFO_SIG_INFO( - const Agnostic_CORINFO_SIG_INFO& sigInfo, - LightWeightMap* buffers, - const DenseLightWeightMap* handleMap) -{ - char buffer[MAX_BUFFER_SIZE]; - char* pbuf = buffer; - int sizeOfBuffer = sizeof(buffer); - int cch; - - cch = sprintf_s(pbuf, sizeOfBuffer, "{callConv-%08X retTypeClass-%016llX retTypeSigClass-%016llX retType-%08X(%s) flg-%08X na-%u", - sigInfo.callConv, sigInfo.retTypeClass, sigInfo.retTypeSigClass, sigInfo.retType, toString((CorInfoType)sigInfo.retType), sigInfo.flags, sigInfo.numArgs); - pbuf += cch; - sizeOfBuffer -= cch; - - FormatAgnostic_CORINFO_SIG_INST_Element(pbuf, sizeOfBuffer, " ", "cc", "ci", sigInfo.sigInst_classInstCount, sigInfo.sigInst_classInst_Index, handleMap); - FormatAgnostic_CORINFO_SIG_INST_Element(pbuf, sizeOfBuffer, " ", "mc", "mi", sigInfo.sigInst_methInstCount, sigInfo.sigInst_methInst_Index, handleMap); - - cch = sprintf_s(pbuf, sizeOfBuffer, " args-%016llX sig-%s msig-%016llX scp-%016llX tok-%08X}", - sigInfo.args, DumpPSig(sigInfo.pSig_Index, sigInfo.cbSig, buffers).c_str(), sigInfo.methodSignature, sigInfo.scope, sigInfo.token); - pbuf += cch; - sizeOfBuffer -= cch; - - return std::string(buffer); -} - -#endif diff --git a/src/coreclr/tools/superpmi/superpmi-shared/spmirecordhelper.h b/src/coreclr/tools/superpmi/superpmi-shared/spmirecordhelper.h deleted file mode 100644 index b2df4eded655e6..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/spmirecordhelper.h +++ /dev/null @@ -1,579 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// SpmiRecordHelper.h - a helper to copy data between agnostic/non-agnostic types. -//---------------------------------------------------------- -#ifndef _SpmiRecordsHelper -#define _SpmiRecordsHelper - -#include "methodcontext.h" -#include "spmiutil.h" - -class SpmiRecordsHelper -{ -public: - static Agnostic_CORINFO_RESOLVED_TOKENin CreateAgnostic_CORINFO_RESOLVED_TOKENin( - CORINFO_RESOLVED_TOKEN* pResolvedToken); - - static Agnostic_CORINFO_RESOLVED_TOKENout CreateAgnostic_CORINFO_RESOLVED_TOKENout_without_buffers( - CORINFO_RESOLVED_TOKEN* pResolvedToken); - - template - static Agnostic_CORINFO_RESOLVED_TOKENout StoreAgnostic_CORINFO_RESOLVED_TOKENout( - CORINFO_RESOLVED_TOKEN* pResolvedToken, LightWeightMap* buffers); - - template - static Agnostic_CORINFO_RESOLVED_TOKENout RestoreAgnostic_CORINFO_RESOLVED_TOKENout( - CORINFO_RESOLVED_TOKEN* pResolvedToken, LightWeightMap* buffers); - - template - static Agnostic_CORINFO_RESOLVED_TOKEN StoreAgnostic_CORINFO_RESOLVED_TOKEN( - CORINFO_RESOLVED_TOKEN* pResolvedToken, LightWeightMap* buffers); - - template - static Agnostic_CORINFO_RESOLVED_TOKEN RestoreAgnostic_CORINFO_RESOLVED_TOKEN( - CORINFO_RESOLVED_TOKEN* pResolvedToken, LightWeightMap* buffers); - - template - static CORINFO_RESOLVED_TOKEN Restore_CORINFO_RESOLVED_TOKEN( - Agnostic_CORINFO_RESOLVED_TOKEN* pResolvedTokenAgnostic, LightWeightMap* buffers); - - // Restore the out values in the first argument from the second. - // Can't just return whole CORINFO_RESOLVED_TOKEN because [in] values in it are important too. - template - static void Restore_CORINFO_RESOLVED_TOKENout(CORINFO_RESOLVED_TOKEN* pResolvedToken, - Agnostic_CORINFO_RESOLVED_TOKENout& token, - LightWeightMap* buffers); - - static Agnostic_CORINFO_SIG_INFO CreateAgnostic_CORINFO_SIG_INFO_without_buffers( - const CORINFO_SIG_INFO& sigInfo); - - static void StoreAgnostic_CORINFO_SIG_INST_HandleArray( - unsigned handleInstCount, - CORINFO_CLASS_HANDLE* handleInstArray, - DenseLightWeightMap*& handleMap, // If we initialize it, the pointer gets updated. - /* OUT */ DWORD* handleInstCountOut, - /* OUT */ DWORD* handleInstIndexOut); - - template - static Agnostic_CORINFO_SIG_INFO StoreAgnostic_CORINFO_SIG_INFO( - const CORINFO_SIG_INFO& sigInfo, - LightWeightMap* buffers, - DenseLightWeightMap*& handleMap); - - static DWORD ContainsHandleMap( - unsigned handleCount, - const CORINFO_CLASS_HANDLE* handleArray, - const DenseLightWeightMap* handleMap); - - template - static Agnostic_CORINFO_SIG_INFO RestoreAgnostic_CORINFO_SIG_INFO( - const CORINFO_SIG_INFO& sigInfo, - LightWeightMap* buffers, - const DenseLightWeightMap* handleMap); - - static void DeserializeCORINFO_SIG_INST_HandleArray( - DWORD handleInstCount, - DWORD handleInstIndex, - const DenseLightWeightMap* handleMap, - MemoryTracker* memoryTracker, - /* OUT */ unsigned* handleInstCountOut, - /* OUT */ CORINFO_CLASS_HANDLE** handleInstArrayOut); - - static void DeserializeCORINFO_SIG_INST( - CORINFO_SIG_INFO& sigInfoOut, - const Agnostic_CORINFO_SIG_INFO& sigInfo, - const DenseLightWeightMap* handleMap, - MemoryTracker* memoryTracker); - - template - static CORINFO_SIG_INFO Restore_CORINFO_SIG_INFO( - const Agnostic_CORINFO_SIG_INFO& sigInfo, - LightWeightMap* buffers, - const DenseLightWeightMap* handleMap, - MemoryTracker* memoryTracker); - - static Agnostic_CORINFO_LOOKUP_KIND CreateAgnostic_CORINFO_LOOKUP_KIND( - const CORINFO_LOOKUP_KIND* pGenericLookupKind); - - static CORINFO_LOOKUP_KIND RestoreCORINFO_LOOKUP_KIND(const Agnostic_CORINFO_LOOKUP_KIND& lookupKind); - - static Agnostic_CORINFO_CONST_LOOKUP StoreAgnostic_CORINFO_CONST_LOOKUP( - const CORINFO_CONST_LOOKUP* pLookup); - - static CORINFO_CONST_LOOKUP RestoreCORINFO_CONST_LOOKUP(const Agnostic_CORINFO_CONST_LOOKUP& lookup); - - static Agnostic_CORINFO_RUNTIME_LOOKUP StoreAgnostic_CORINFO_RUNTIME_LOOKUP( - CORINFO_RUNTIME_LOOKUP* pLookup); - - static CORINFO_RUNTIME_LOOKUP RestoreCORINFO_RUNTIME_LOOKUP(const Agnostic_CORINFO_RUNTIME_LOOKUP& lookup); - - static Agnostic_CORINFO_LOOKUP StoreAgnostic_CORINFO_LOOKUP(CORINFO_LOOKUP* pLookup); - - static CORINFO_LOOKUP RestoreCORINFO_LOOKUP(const Agnostic_CORINFO_LOOKUP& agnosticLookup); - - static Agnostic_CORINFO_TYPE_LAYOUT_NODE StoreAgnostic_CORINFO_TYPE_LAYOUT_NODE(const CORINFO_TYPE_LAYOUT_NODE& node); - static CORINFO_TYPE_LAYOUT_NODE RestoreCORINFO_TYPE_LAYOUT_NODE(const Agnostic_CORINFO_TYPE_LAYOUT_NODE& node); -}; - -inline Agnostic_CORINFO_RESOLVED_TOKENin SpmiRecordsHelper::CreateAgnostic_CORINFO_RESOLVED_TOKENin( - CORINFO_RESOLVED_TOKEN* pResolvedToken) -{ - Agnostic_CORINFO_RESOLVED_TOKENin tokenIn; - ZeroMemory(&tokenIn, sizeof(tokenIn)); - - if (pResolvedToken != nullptr) - { - tokenIn.tokenContext = CastHandle(pResolvedToken->tokenContext); - tokenIn.tokenScope = CastHandle(pResolvedToken->tokenScope); - tokenIn.token = (DWORD)pResolvedToken->token; - tokenIn.tokenType = (DWORD)pResolvedToken->tokenType; - } - return tokenIn; -} - -inline Agnostic_CORINFO_RESOLVED_TOKENout SpmiRecordsHelper:: - CreateAgnostic_CORINFO_RESOLVED_TOKENout_without_buffers(CORINFO_RESOLVED_TOKEN* pResolvedToken) -{ - Agnostic_CORINFO_RESOLVED_TOKENout tokenOut; - ZeroMemory(&tokenOut, sizeof(tokenOut)); - - if (pResolvedToken != nullptr) - { - tokenOut.hClass = CastHandle(pResolvedToken->hClass); - tokenOut.hMethod = CastHandle(pResolvedToken->hMethod); - tokenOut.hField = CastHandle(pResolvedToken->hField); - - tokenOut.cbTypeSpec = (DWORD)pResolvedToken->cbTypeSpec; - tokenOut.cbMethodSpec = (DWORD)pResolvedToken->cbMethodSpec; - } - - tokenOut.pTypeSpec_Index = -1; - tokenOut.pMethodSpec_Index = -1; - - return tokenOut; -} - -template -inline Agnostic_CORINFO_RESOLVED_TOKENout SpmiRecordsHelper::StoreAgnostic_CORINFO_RESOLVED_TOKENout( - CORINFO_RESOLVED_TOKEN* pResolvedToken, LightWeightMap* buffers) -{ - Agnostic_CORINFO_RESOLVED_TOKENout tokenOut( - CreateAgnostic_CORINFO_RESOLVED_TOKENout_without_buffers(pResolvedToken)); - - if (pResolvedToken != nullptr) - { - tokenOut.pTypeSpec_Index = - (DWORD)buffers->AddBuffer((unsigned char*)pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec); - tokenOut.pMethodSpec_Index = - (DWORD)buffers->AddBuffer((unsigned char*)pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec); - } - - return tokenOut; -} - -template -inline Agnostic_CORINFO_RESOLVED_TOKENout SpmiRecordsHelper::RestoreAgnostic_CORINFO_RESOLVED_TOKENout( - CORINFO_RESOLVED_TOKEN* pResolvedToken, LightWeightMap* buffers) -{ - Agnostic_CORINFO_RESOLVED_TOKENout tokenOut( - CreateAgnostic_CORINFO_RESOLVED_TOKENout_without_buffers(pResolvedToken)); - if (pResolvedToken != nullptr) - { - tokenOut.pTypeSpec_Index = - (DWORD)buffers->Contains((unsigned char*)pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec); - tokenOut.pMethodSpec_Index = - (DWORD)buffers->Contains((unsigned char*)pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec); - } - return tokenOut; -} - -template -inline Agnostic_CORINFO_RESOLVED_TOKEN SpmiRecordsHelper::StoreAgnostic_CORINFO_RESOLVED_TOKEN( - CORINFO_RESOLVED_TOKEN* pResolvedToken, LightWeightMap* buffers) -{ - Agnostic_CORINFO_RESOLVED_TOKEN token; - token.inValue = CreateAgnostic_CORINFO_RESOLVED_TOKENin(pResolvedToken); - token.outValue = StoreAgnostic_CORINFO_RESOLVED_TOKENout(pResolvedToken, buffers); - return token; -} - -template -inline Agnostic_CORINFO_RESOLVED_TOKEN SpmiRecordsHelper::RestoreAgnostic_CORINFO_RESOLVED_TOKEN( - CORINFO_RESOLVED_TOKEN* pResolvedToken, LightWeightMap* buffers) -{ - Agnostic_CORINFO_RESOLVED_TOKEN token; - ZeroMemory(&token, sizeof(token)); - token.inValue = CreateAgnostic_CORINFO_RESOLVED_TOKENin(pResolvedToken); - token.outValue = RestoreAgnostic_CORINFO_RESOLVED_TOKENout(pResolvedToken, buffers); - return token; -} - -template -inline CORINFO_RESOLVED_TOKEN SpmiRecordsHelper::Restore_CORINFO_RESOLVED_TOKEN( - Agnostic_CORINFO_RESOLVED_TOKEN* pResolvedTokenAgnostic, LightWeightMap* buffers) -{ - CORINFO_RESOLVED_TOKEN token; - ZeroMemory(&token, sizeof(token)); - - token.tokenContext = (CORINFO_CONTEXT_HANDLE)pResolvedTokenAgnostic->inValue.tokenContext; - token.tokenScope = (CORINFO_MODULE_HANDLE)pResolvedTokenAgnostic->inValue.tokenScope; - token.token = (mdToken)pResolvedTokenAgnostic->inValue.token; - token.tokenType = (CorInfoTokenKind)pResolvedTokenAgnostic->inValue.tokenType; - - Restore_CORINFO_RESOLVED_TOKENout(&token, pResolvedTokenAgnostic->outValue, buffers); - return token; -} - -template -inline void SpmiRecordsHelper::Restore_CORINFO_RESOLVED_TOKENout( - CORINFO_RESOLVED_TOKEN* pResolvedToken, - Agnostic_CORINFO_RESOLVED_TOKENout& tokenOut, - LightWeightMap* buffers) -{ - if (pResolvedToken != nullptr) - { - pResolvedToken->hClass = (CORINFO_CLASS_HANDLE)tokenOut.hClass; - pResolvedToken->hMethod = (CORINFO_METHOD_HANDLE)tokenOut.hMethod; - pResolvedToken->hField = (CORINFO_FIELD_HANDLE)tokenOut.hField; - pResolvedToken->pTypeSpec = (PCCOR_SIGNATURE)buffers->GetBuffer(tokenOut.pTypeSpec_Index); - pResolvedToken->cbTypeSpec = (ULONG)tokenOut.cbTypeSpec; - pResolvedToken->pMethodSpec = (PCCOR_SIGNATURE)buffers->GetBuffer(tokenOut.pMethodSpec_Index); - pResolvedToken->cbMethodSpec = (ULONG)tokenOut.cbMethodSpec; - } -} - -inline Agnostic_CORINFO_SIG_INFO SpmiRecordsHelper::CreateAgnostic_CORINFO_SIG_INFO_without_buffers( - const CORINFO_SIG_INFO& sigInfo) -{ - Agnostic_CORINFO_SIG_INFO sig; - ZeroMemory(&sig, sizeof(sig)); - sig.callConv = (DWORD)sigInfo.callConv; - sig.retTypeClass = CastHandle(sigInfo.retTypeClass); - sig.retTypeSigClass = CastHandle(sigInfo.retTypeSigClass); - sig.retType = (DWORD)sigInfo.retType; - sig.flags = (DWORD)sigInfo.flags; - sig.numArgs = (DWORD)sigInfo.numArgs; - sig.sigInst_classInstCount = (DWORD)sigInfo.sigInst.classInstCount; - sig.sigInst_methInstCount = (DWORD)sigInfo.sigInst.methInstCount; - sig.args = CastHandle(sigInfo.args); - sig.cbSig = (DWORD)sigInfo.cbSig; - sig.methodSignature = CastPointer(sigInfo.methodSignature); - sig.scope = CastHandle(sigInfo.scope); - sig.token = (DWORD)sigInfo.token; - return sig; -} - -inline void SpmiRecordsHelper::StoreAgnostic_CORINFO_SIG_INST_HandleArray( - unsigned handleInstCount, - CORINFO_CLASS_HANDLE* handleInstArray, - DenseLightWeightMap*& handleMap, // If we initialize it, the pointer gets updated. - /* OUT */ DWORD* handleInstCountOut, - /* OUT */ DWORD* handleInstIndexOut) -{ - unsigned handleInstIndex; - - // We shouldn't need to check (handleInstArray != nullptr), but often, crossgen2 sets (leaves?) - // handleInstCount > 0 and handleInstArray == nullptr. - if ((handleInstCount > 0) && (handleInstArray != nullptr)) - { - if (handleMap == nullptr) - handleMap = new DenseLightWeightMap(); // this updates the caller - - // If the we already have this array, we need to re-use it, so when we look it up on - // replay we get the same index. It also reduces the amount of data in the handle map, - // since there are typically few handle unique arrays. - handleInstIndex = ContainsHandleMap(handleInstCount, handleInstArray, handleMap); - if (handleInstIndex == (DWORD)-1) - { - handleInstIndex = handleMap->GetCount(); - for (unsigned int i = 0; i < handleInstCount; i++) - { - handleMap->Append(CastHandle(handleInstArray[i])); - } - AssertCodeMsg(handleInstIndex + handleInstCount == handleMap->GetCount(), EXCEPTIONCODE_MC, - "Unexpected size of handleMap"); - } - } - else - { - if (handleInstCount > 0) - { - // This is really a VM/crossgen2 bug (or, a by-design crossgen2 feature to avoid creating - // an array the JIT doesn't look at). - handleInstCount = 0; - } - - handleInstIndex = (DWORD)-1; - } - - *handleInstCountOut = handleInstCount; - *handleInstIndexOut = handleInstIndex; -} - -template -inline Agnostic_CORINFO_SIG_INFO SpmiRecordsHelper::StoreAgnostic_CORINFO_SIG_INFO( - const CORINFO_SIG_INFO& sigInfo, - LightWeightMap* buffers, - DenseLightWeightMap*& handleMap) -{ - Agnostic_CORINFO_SIG_INFO sig(CreateAgnostic_CORINFO_SIG_INFO_without_buffers(sigInfo)); - - StoreAgnostic_CORINFO_SIG_INST_HandleArray(sigInfo.sigInst.classInstCount, sigInfo.sigInst.classInst, handleMap, &sig.sigInst_classInstCount, &sig.sigInst_classInst_Index); - StoreAgnostic_CORINFO_SIG_INST_HandleArray(sigInfo.sigInst.methInstCount, sigInfo.sigInst.methInst, handleMap, &sig.sigInst_methInstCount, &sig.sigInst_methInst_Index); - sig.pSig_Index = (DWORD)buffers->AddBuffer((unsigned char*)sigInfo.pSig, sigInfo.cbSig); - - return sig; -} - -inline DWORD SpmiRecordsHelper::ContainsHandleMap( - unsigned handleCount, - const CORINFO_CLASS_HANDLE* handleArray, - const DenseLightWeightMap* handleMap) -{ - // Special case: no handles isn't found. - if (handleCount == 0) - { - return (DWORD)-1; - } - - for (unsigned mapIndex = 0; mapIndex < handleMap->GetCount(); mapIndex++) - { - if (mapIndex + handleCount > handleMap->GetCount()) - { - // The handles can't be found; it would overflow the handleMap. - return (DWORD)-1; - } - - // See if the handle map starting at `mapIndex` contains all the handles we're looking for, in order. - bool found = true; // Assume we'll find it - for (unsigned handleIndex = 0; handleIndex < handleCount; handleIndex++) - { - if (handleMap->Get(mapIndex + handleIndex) != CastHandle(handleArray[handleIndex])) - { - found = false; - break; - } - } - if (found) - { - return (DWORD)mapIndex; - } - } - return (DWORD)-1; // not found -} - -// RestoreAgnostic_CORINFO_SIG_INFO: from a CORINFO_SIG_INFO, fill out an Agnostic_CORINFO_SIG_INFO from the data already stored. -// Don't create and store a new Agnostic_CORINFO_SIG_INFO. The buffers and indices need to be found in the existing stored data. -// This is used when we need to create an Agnostic_CORINFO_SIG_INFO to be used as a key to look up in an existing map. -template -inline Agnostic_CORINFO_SIG_INFO SpmiRecordsHelper::RestoreAgnostic_CORINFO_SIG_INFO( - const CORINFO_SIG_INFO& sigInfo, - LightWeightMap* buffers, - const DenseLightWeightMap* handleMap) -{ - Agnostic_CORINFO_SIG_INFO sig(CreateAgnostic_CORINFO_SIG_INFO_without_buffers(sigInfo)); - sig.sigInst_classInst_Index = ContainsHandleMap(sigInfo.sigInst.classInstCount, sigInfo.sigInst.classInst, handleMap); - sig.sigInst_methInst_Index = ContainsHandleMap(sigInfo.sigInst.methInstCount, sigInfo.sigInst.methInst, handleMap); - sig.pSig_Index = (DWORD)buffers->Contains((unsigned char*)sigInfo.pSig, sigInfo.cbSig); - return sig; -} - -inline void SpmiRecordsHelper::DeserializeCORINFO_SIG_INST_HandleArray( - DWORD handleInstCount, - DWORD handleInstIndex, - const DenseLightWeightMap* handleMap, - MemoryTracker* memoryTracker, - /* OUT */ unsigned* handleInstCountOut, - /* OUT */ CORINFO_CLASS_HANDLE** handleInstArrayOut) -{ - CORINFO_CLASS_HANDLE* handleInstArray; - - if (handleInstCount > 0) - { - handleInstArray = (CORINFO_CLASS_HANDLE*)memoryTracker->allocate(handleInstCount * sizeof(CORINFO_CLASS_HANDLE)); - for (unsigned int i = 0; i < handleInstCount; i++) - { - DWORD key = handleInstIndex + i; - handleInstArray[i] = (CORINFO_CLASS_HANDLE)handleMap->Get(key); - } - } - else - { - handleInstArray = nullptr; - } - - *handleInstCountOut = handleInstCount; - *handleInstArrayOut = handleInstArray; -} - -inline void SpmiRecordsHelper::DeserializeCORINFO_SIG_INST( - CORINFO_SIG_INFO& sigInfoOut, const Agnostic_CORINFO_SIG_INFO& sigInfo, const DenseLightWeightMap* handleMap, MemoryTracker* memoryTracker) -{ - DeserializeCORINFO_SIG_INST_HandleArray(sigInfo.sigInst_classInstCount, sigInfo.sigInst_classInst_Index, handleMap, memoryTracker, &sigInfoOut.sigInst.classInstCount, &sigInfoOut.sigInst.classInst); - DeserializeCORINFO_SIG_INST_HandleArray(sigInfo.sigInst_methInstCount, sigInfo.sigInst_methInst_Index, handleMap, memoryTracker, &sigInfoOut.sigInst.methInstCount, &sigInfoOut.sigInst.methInst); -} - -template -inline CORINFO_SIG_INFO SpmiRecordsHelper::Restore_CORINFO_SIG_INFO(const Agnostic_CORINFO_SIG_INFO& sigInfo, - LightWeightMap* buffers, - const DenseLightWeightMap* handleMap, - MemoryTracker* memoryTracker) -{ - CORINFO_SIG_INFO sig; - sig.callConv = (CorInfoCallConv)sigInfo.callConv; - sig.retTypeClass = (CORINFO_CLASS_HANDLE)sigInfo.retTypeClass; - sig.retTypeSigClass = (CORINFO_CLASS_HANDLE)sigInfo.retTypeSigClass; - sig.retType = (CorInfoType)sigInfo.retType; - sig.flags = (unsigned)sigInfo.flags; - sig.numArgs = (unsigned)sigInfo.numArgs; - sig.args = (CORINFO_ARG_LIST_HANDLE)sigInfo.args; - sig.cbSig = (unsigned int)sigInfo.cbSig; - sig.pSig = (PCCOR_SIGNATURE)buffers->GetBuffer(sigInfo.pSig_Index); - sig.methodSignature = (MethodSignatureInfo*)sigInfo.methodSignature; - sig.scope = (CORINFO_MODULE_HANDLE)sigInfo.scope; - sig.token = (mdToken)sigInfo.token; - - DeserializeCORINFO_SIG_INST(sig, sigInfo, handleMap, memoryTracker); - - return sig; -} - -inline Agnostic_CORINFO_LOOKUP_KIND SpmiRecordsHelper::CreateAgnostic_CORINFO_LOOKUP_KIND( - const CORINFO_LOOKUP_KIND* pGenericLookupKind) -{ - Agnostic_CORINFO_LOOKUP_KIND genericLookupKind; - ZeroMemory(&genericLookupKind, sizeof(genericLookupKind)); - if (pGenericLookupKind != nullptr) - { - genericLookupKind.needsRuntimeLookup = (DWORD)pGenericLookupKind->needsRuntimeLookup; - genericLookupKind.runtimeLookupKind = (DWORD)pGenericLookupKind->runtimeLookupKind; - } - return genericLookupKind; -} - -inline CORINFO_LOOKUP_KIND SpmiRecordsHelper::RestoreCORINFO_LOOKUP_KIND( - const Agnostic_CORINFO_LOOKUP_KIND& lookupKind) -{ - CORINFO_LOOKUP_KIND genericLookupKind; - genericLookupKind.needsRuntimeLookup = lookupKind.needsRuntimeLookup != 0; - genericLookupKind.runtimeLookupKind = (CORINFO_RUNTIME_LOOKUP_KIND)lookupKind.runtimeLookupKind; - return genericLookupKind; -} - -inline Agnostic_CORINFO_CONST_LOOKUP SpmiRecordsHelper::StoreAgnostic_CORINFO_CONST_LOOKUP( - const CORINFO_CONST_LOOKUP* pLookup) -{ - Agnostic_CORINFO_CONST_LOOKUP constLookup; - ZeroMemory(&constLookup, sizeof(constLookup)); - constLookup.accessType = (DWORD)pLookup->accessType; - constLookup.handle = CastHandle(pLookup->handle); - return constLookup; -} - -inline CORINFO_CONST_LOOKUP SpmiRecordsHelper::RestoreCORINFO_CONST_LOOKUP( - const Agnostic_CORINFO_CONST_LOOKUP& lookup) -{ - CORINFO_CONST_LOOKUP constLookup; - constLookup.accessType = (InfoAccessType)lookup.accessType; - constLookup.handle = (CORINFO_GENERIC_HANDLE)lookup.handle; - return constLookup; -} - -inline Agnostic_CORINFO_RUNTIME_LOOKUP SpmiRecordsHelper::StoreAgnostic_CORINFO_RUNTIME_LOOKUP( - CORINFO_RUNTIME_LOOKUP* pLookup) -{ - Agnostic_CORINFO_RUNTIME_LOOKUP runtimeLookup; - ZeroMemory(&runtimeLookup, sizeof(runtimeLookup)); - runtimeLookup.signature = CastPointer(pLookup->signature); - runtimeLookup.helper = (DWORD)pLookup->helper; - runtimeLookup.indirections = (DWORD)pLookup->indirections; - runtimeLookup.testForNull = (DWORD)pLookup->testForNull; - runtimeLookup.sizeOffset = pLookup->sizeOffset; - runtimeLookup.indirectFirstOffset = (DWORD)pLookup->indirectFirstOffset; - runtimeLookup.indirectSecondOffset = (DWORD)pLookup->indirectSecondOffset; - for (int i = 0; i < CORINFO_MAXINDIRECTIONS; i++) - runtimeLookup.offsets[i] = (DWORDLONG)pLookup->offsets[i]; - runtimeLookup.helperEntryPoint = StoreAgnostic_CORINFO_CONST_LOOKUP(&pLookup->helperEntryPoint); - return runtimeLookup; -} - -inline CORINFO_RUNTIME_LOOKUP SpmiRecordsHelper::RestoreCORINFO_RUNTIME_LOOKUP( - const Agnostic_CORINFO_RUNTIME_LOOKUP& lookup) -{ - CORINFO_RUNTIME_LOOKUP runtimeLookup; - runtimeLookup.signature = (LPVOID)lookup.signature; - runtimeLookup.helper = (CorInfoHelpFunc)lookup.helper; - runtimeLookup.indirections = (WORD)lookup.indirections; - runtimeLookup.testForNull = lookup.testForNull != 0; - runtimeLookup.sizeOffset = lookup.sizeOffset; - runtimeLookup.indirectFirstOffset = lookup.indirectFirstOffset != 0; - runtimeLookup.indirectSecondOffset = lookup.indirectSecondOffset != 0; - for (int i = 0; i < CORINFO_MAXINDIRECTIONS; i++) - runtimeLookup.offsets[i] = (size_t)lookup.offsets[i]; - runtimeLookup.helperEntryPoint = RestoreCORINFO_CONST_LOOKUP(lookup.helperEntryPoint); - return runtimeLookup; -} - -inline Agnostic_CORINFO_LOOKUP SpmiRecordsHelper::StoreAgnostic_CORINFO_LOOKUP(CORINFO_LOOKUP* pLookup) -{ - Agnostic_CORINFO_LOOKUP lookup; - ZeroMemory(&lookup, sizeof(lookup)); - lookup.lookupKind = CreateAgnostic_CORINFO_LOOKUP_KIND(&pLookup->lookupKind); - if (pLookup->lookupKind.needsRuntimeLookup) - { - lookup.runtimeLookup = StoreAgnostic_CORINFO_RUNTIME_LOOKUP(&pLookup->runtimeLookup); - } - else - { - lookup.constLookup = StoreAgnostic_CORINFO_CONST_LOOKUP(&pLookup->constLookup); - } - return lookup; -} - -inline CORINFO_LOOKUP SpmiRecordsHelper::RestoreCORINFO_LOOKUP(const Agnostic_CORINFO_LOOKUP& agnosticLookup) -{ - CORINFO_LOOKUP lookup; - ZeroMemory(&lookup, sizeof(lookup)); - lookup.lookupKind = RestoreCORINFO_LOOKUP_KIND(agnosticLookup.lookupKind); - if (lookup.lookupKind.needsRuntimeLookup) - { - lookup.runtimeLookup = RestoreCORINFO_RUNTIME_LOOKUP(agnosticLookup.runtimeLookup); - } - else - { - lookup.constLookup = RestoreCORINFO_CONST_LOOKUP(agnosticLookup.constLookup); - } - return lookup; -} - -inline Agnostic_CORINFO_TYPE_LAYOUT_NODE SpmiRecordsHelper::StoreAgnostic_CORINFO_TYPE_LAYOUT_NODE(const CORINFO_TYPE_LAYOUT_NODE& node) -{ - Agnostic_CORINFO_TYPE_LAYOUT_NODE result; - result.simdTypeHnd = CastHandle(node.simdTypeHnd); - result.diagFieldHnd = CastHandle(node.diagFieldHnd); - result.parent = node.parent; - result.offset = node.offset; - result.size = node.size; - result.numFields = node.numFields; - result.type = (BYTE)node.type; - result.hasSignificantPadding = node.hasSignificantPadding; - return result; -} - -inline CORINFO_TYPE_LAYOUT_NODE SpmiRecordsHelper::RestoreCORINFO_TYPE_LAYOUT_NODE(const Agnostic_CORINFO_TYPE_LAYOUT_NODE& node) -{ - CORINFO_TYPE_LAYOUT_NODE result; - result.simdTypeHnd = (CORINFO_CLASS_HANDLE)node.simdTypeHnd; - result.diagFieldHnd = (CORINFO_FIELD_HANDLE)node.diagFieldHnd; - result.parent = node.parent; - result.offset = node.offset; - result.size = node.size; - result.numFields = node.numFields; - result.type = (CorInfoType)node.type; - result.hasSignificantPadding = node.hasSignificantPadding; - return result; -} - -#endif diff --git a/src/coreclr/tools/superpmi/superpmi-shared/spmiutil.cpp b/src/coreclr/tools/superpmi/superpmi-shared/spmiutil.cpp deleted file mode 100644 index 1044df01ba7581..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/spmiutil.cpp +++ /dev/null @@ -1,595 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// SPMIUtil.cpp - General utility functions -//---------------------------------------------------------- - -#include "standardpch.h" -#include "logging.h" -#include "spmiutil.h" - -#include -#include -#include -#include - -static bool breakOnDebugBreakorAV = false; - -bool BreakOnDebugBreakorAV() -{ - return breakOnDebugBreakorAV; -} - -void SetBreakOnDebugBreakOrAV(bool value) -{ - breakOnDebugBreakorAV = value; -} - -static bool breakOnException = false; - -bool BreakOnException() -{ - return breakOnException; -} - -void SetBreakOnException(bool value) -{ - breakOnException = value; -} - -void DebugBreakorAV(int val) -{ - if (minipal_is_native_debugger_present()) - { - if (val == 0) - DEBUG_BREAK; - if (BreakOnDebugBreakorAV()) - DEBUG_BREAK; - } - - int exception_code = EXCEPTIONCODE_DebugBreakorAV + val; - // assert((EXCEPTIONCODE_DebugBreakorAV <= exception_code) && (exception_code < EXCEPTIONCODE_DebugBreakorAV_MAX)) - LogException(exception_code, "DebugBreak or AV Exception %d", val); -} - -char* GetEnvironmentVariableWithDefaultA(const char* envVarName, const char* defaultValue) -{ - char* retString = nullptr; - - // Figure out how much space we need to allocate - DWORD dwRetVal = ::GetEnvironmentVariableA(envVarName, nullptr, 0); - if (dwRetVal != 0) - { - retString = new char[dwRetVal]; - dwRetVal = ::GetEnvironmentVariableA(envVarName, retString, dwRetVal); - } - else - { - if (defaultValue != nullptr) - { - dwRetVal = (DWORD)strlen(defaultValue) + 1; // add one for null terminator - retString = new char[dwRetVal]; - memcpy_s(retString, dwRetVal, defaultValue, dwRetVal); - } - } - - return retString; -} - -WCHAR* GetEnvironmentVariableWithDefaultW(const WCHAR* envVarName, const WCHAR* defaultValue) -{ - WCHAR* retString = nullptr; - - // Figure out how much space we need to allocate - DWORD dwRetVal = ::GetEnvironmentVariableW(envVarName, nullptr, 0); - if (dwRetVal != 0) - { - retString = new WCHAR[dwRetVal]; - dwRetVal = ::GetEnvironmentVariableW(envVarName, retString, dwRetVal); - } - else - { - if (defaultValue != nullptr) - { - dwRetVal = (DWORD)u16_strlen(defaultValue) + 1; // add one for null terminator - retString = new WCHAR[dwRetVal]; - memcpy_s(retString, dwRetVal * sizeof(WCHAR), defaultValue, dwRetVal * sizeof(WCHAR)); - } - } - - return retString; -} - -const char* GetEnvWithDefault(const char* envVarName, const char* defaultValue) -{ - // getenv isn't thread safe, but it's simple and sufficient since we are development-only tool - char* env = getenv(envVarName); - return env ? env : defaultValue; -} - -std::string GetProcessCommandLine() -{ -#ifdef TARGET_WINDOWS - return ::GetCommandLineA(); -#else - FILE* fp = fopen("/proc/self/cmdline", "r"); - if (fp != NULL) - { - std::string result; - char* cmdLine = nullptr; - size_t size = 0; - - while (getdelim(&cmdLine, &size, '\0', fp) != -1) - { - // /proc/self/cmdline uses \0 as delimiter, convert it to space - if (!result.empty()) - result += ' '; - - result += cmdLine; - - free(cmdLine); - cmdLine = nullptr; - size = 0; - } - - fclose(fp); - return result; - } - - return ""; -#endif -} - -bool LoadRealJitLib(HMODULE& jitLib, const std::string& jitLibPath) -{ - // Load Library - if (jitLib == NULL) - { - if (jitLibPath.empty()) - { - LogError("LoadRealJitLib - No real jit path"); - return false; - } -#ifdef TARGET_WINDOWS - jitLib = ::LoadLibraryExA(jitLibPath.c_str(), NULL, 0); - if (jitLib == NULL) - { - LogError("LoadRealJitLib - LoadLibrary failed to load '%s' (0x%08x)", jitLibPath.c_str(), ::GetLastError()); - return false; - } -#else - jitLib = ::dlopen(jitLibPath.c_str(), RTLD_LAZY); - // The simulated DllMain of JIT doesn't do any meaningful initialization. Skip it. - if (jitLib == NULL) - { - LogError("LoadRealJitLib - dlopen failed to load '%s' (%s)", jitLibPath.c_str(), ::dlerror()); - return false; - } -#endif - } - return true; -} - -void ReplaceIllegalCharacters(std::string& fileName) -{ - // Perform the following transforms: - // - Convert non-ASCII to ASCII for simplicity - // - Remove any illegal or annoying characters from the file name by - // converting them to underscores. - // - Replace any quotes in the file name with spaces. - - for (char& quote : fileName) - { - char ch = quote; - if ((ch <= 32) || (ch >= 127)) // Only allow textual ASCII characters - { - quote = '_'; - } - else - { - switch (ch) - { - case '(': case ')': case '=': case '<': - case '>': case ':': case '/': case '\\': - case '|': case '?': case '!': case '*': - case '.': case ',': - quote = '_'; - break; - case '"': - quote = ' '; - break; - default: - break; - } - } - } -} - -std::string GetResultFileName(const std::string& folderPath, - const std::string& fileName, - const std::string& extension) -{ - // Append a random string to improve uniqueness. - // - uint32_t randomNumber = 0; - minipal_get_non_cryptographically_secure_random_bytes((uint8_t*)&randomNumber, sizeof(randomNumber)); - std::stringstream ss; - ss << std::hex << std::setw(8) << std::setfill('0') << randomNumber; - std::string suffix = ss.str() + extension; - - // Limit the total file name length to MAX_PATH - 50 - int usableLength = MAX_PATH - 50 - (int)folderPath.size() - (int)suffix.size(); - if (usableLength < 0) - { - LogError("GetResultFileName - folder path '%s' length + minimal file name exceeds limit %d", folderPath.c_str(), MAX_PATH - 50); - return ""; - } - - std::string copy = fileName; - if ((int)copy.size() > usableLength) - { - copy = copy.substr(0, usableLength); - } - - ReplaceIllegalCharacters(copy); - return folderPath + DIRECTORY_SEPARATOR_CHAR_A + copy + suffix; -} - -#ifdef TARGET_AMD64 -static SPMI_TARGET_ARCHITECTURE SpmiTargetArchitecture = SPMI_TARGET_ARCHITECTURE_AMD64; -#elif defined(TARGET_X86) -static SPMI_TARGET_ARCHITECTURE SpmiTargetArchitecture = SPMI_TARGET_ARCHITECTURE_X86; -#elif defined(TARGET_ARM) -static SPMI_TARGET_ARCHITECTURE SpmiTargetArchitecture = SPMI_TARGET_ARCHITECTURE_ARM; -#elif defined(TARGET_ARM64) -static SPMI_TARGET_ARCHITECTURE SpmiTargetArchitecture = SPMI_TARGET_ARCHITECTURE_ARM64; -#elif defined(TARGET_LOONGARCH64) -static SPMI_TARGET_ARCHITECTURE SpmiTargetArchitecture = SPMI_TARGET_ARCHITECTURE_LOONGARCH64; -#elif defined(TARGET_RISCV64) -static SPMI_TARGET_ARCHITECTURE SpmiTargetArchitecture = SPMI_TARGET_ARCHITECTURE_RISCV64; -#elif defined(TARGET_WASM32) -static SPMI_TARGET_ARCHITECTURE SpmiTargetArchitecture = SPMI_TARGET_ARCHITECTURE_WASM32; -#else -#error Unsupported architecture -#endif - -SPMI_TARGET_ARCHITECTURE GetSpmiTargetArchitecture() -{ - return SpmiTargetArchitecture; -} - -void SetSpmiTargetArchitecture(SPMI_TARGET_ARCHITECTURE spmiTargetArchitecture) -{ - SpmiTargetArchitecture = spmiTargetArchitecture; -} - -// The following functions are used for arm64/arm32 relocation processing. -// They are copies of the code in src\coreclr\utilcode\util.cpp. -// We decided to copy them instead of linking with utilcode library -// to avoid introducing additional runtime dependencies. - -void PutArm64Rel28(UINT32* pCode, INT32 imm28) -{ - UINT32 branchInstr = *pCode; - branchInstr &= 0xFC000000; - branchInstr |= ((imm28 >> 2) & 0x03FFFFFF); - *pCode = branchInstr; -} - -void PutArm64Rel21(UINT32* pCode, INT32 imm21) -{ - UINT32 adrpInstr = *pCode; - adrpInstr &= 0x9F00001F; - INT32 immlo = imm21 & 0x03; - INT32 immhi = (imm21 & 0x1FFFFC) >> 2; - adrpInstr |= ((immlo << 29) | (immhi << 5)); - *pCode = adrpInstr; -} - -void PutArm64Rel12(UINT32* pCode, INT32 imm12) -{ - UINT32 addInstr = *pCode; - addInstr &= 0xFFC003FF; - addInstr |= (imm12 << 10); - *pCode = addInstr; -} - -void PutArm64Rel12Ldr(UINT32* pCode, INT32 imm12) -{ - // For a 64-bit LDR the encoded immediate is scaled by the access size (8). - INT32 scaledImm12 = imm12 >> 3; - UINT32 ldrInstr = *pCode; - ldrInstr &= 0xFFC003FF; - ldrInstr |= (scaledImm12 << 10); - *pCode = ldrInstr; -} - -void PutThumb2Imm16(UINT16* p, UINT16 imm16) -{ - USHORT Opcode0 = p[0]; - USHORT Opcode1 = p[1]; - Opcode0 &= ~((0xf000 >> 12) | (0x0800 >> 1)); - Opcode1 &= ~((0x0700 << 4) | (0x00ff << 0)); - Opcode0 |= (imm16 & 0xf000) >> 12; - Opcode0 |= (imm16 & 0x0800) >> 1; - Opcode1 |= (imm16 & 0x0700) << 4; - Opcode1 |= (imm16 & 0x00ff) << 0; - p[0] = Opcode0; - p[1] = Opcode1; -} - -void PutThumb2Mov32(UINT16* p, UINT32 imm32) -{ - PutThumb2Imm16(p, (UINT16)imm32); - PutThumb2Imm16(p + 2, (UINT16)(imm32 >> 16)); -} - -void PutThumb2BlRel24(UINT16* p, INT32 imm24) -{ - USHORT Opcode0 = p[0]; - USHORT Opcode1 = p[1]; - Opcode0 &= 0xF800; - Opcode1 &= 0xD000; - - UINT32 S = (imm24 & 0x1000000) >> 24; - UINT32 J1 = ((imm24 & 0x0800000) >> 23) ^ S ^ 1; - UINT32 J2 = ((imm24 & 0x0400000) >> 22) ^ S ^ 1; - - Opcode0 |= ((imm24 & 0x03FF000) >> 12) | (S << 10); - Opcode1 |= ((imm24 & 0x0000FFE) >> 1) | (J1 << 13) | (J2 << 11); - - p[0] = Opcode0; - p[1] = Opcode1; -} - -// GetArm64MovConstant / GetArm64MovkConstant: Decode arm64 mov / movk instructions, e.g.: -// d29ff600 mov x0, #65456 -// f2ab8640 movk x0, #23602, lsl #16 -// f2c04bc0 movk x0, #606, lsl #32 -// -// This is used in the NearDiffer to determine if a sequence of mov/movk is actually an address. -// -// Return `true` if the instruction pointed to by `p` is a mov/movk, `false` otherwise. -// If true, fill out the target register in `*pReg`, constant in `*pCon`, and (for movk) shift value in `*pShift`. - -bool GetArm64MovConstant(UINT32* p, unsigned* pReg, unsigned* pCon) -{ - UINT32 instr = *p; - if ((instr & 0xffe00000) == 0xd2800000) - { - *pReg = instr & 0x1f; - *pCon = (instr >> 5) & 0xffff; - return true; - } - - return false; -} - -bool GetArm64MovkConstant(UINT32* p, unsigned* pReg, unsigned* pCon, unsigned* pShift) -{ - UINT32 instr = *p; - if ((instr & 0xff800000) == 0xf2800000) - { - *pReg = instr & 0x1f; - *pCon = (instr >> 5) & 0xffff; - *pShift = ((instr >> 21) & 0x3) * 16; - return true; - } - - return false; -} - -// PutArm64MovkConstant: set the constant field in an Arm64 `movk` instruction -void PutArm64MovkConstant(UINT32* p, unsigned con) -{ - *p = (*p & ~(0xffff << 5)) | ((con & 0xffff) << 5); -} - -// GetArm32MovwConstant / GetArm32MovtConstant: Decode Arm32 movw / movt instructions, e.g.: -// 4b f2 33 40 movw r0, #46131 -// c0 f2 79 30 movt r0, #889 -// -// Return `true` if the instruction pointed to by `p` is a movw/movt, `false` otherwise. -// If true, fill out the target register in `*pReg`, constant in `*pCon`. - -bool GetArm32MovwConstant(UINT32* p, unsigned* pReg, unsigned* pCon) -{ - // This decodes the "MOV (immediate)" instruction, Encoding T3, from the ARM manual section A8.8.102. - if (!Is32BitThumb2Instruction((UINT16*)p)) - { - return false; - } - - // A Thumb-2 instruction is one or two 16-bit words (in little-endian format). - UINT16 instr1 = *(UINT16*)p; - UINT16 instr2 = *((UINT16*)p + 1); - UINT32 instr = (instr1 << 16) | instr2; - if ((instr & 0xfbf08000) != 0xf2400000) - { - return false; - } - - *pReg = (instr & 0xf00) >> 8; - *pCon = ExtractArm32MovImm(instr); - return true; -} - -bool GetArm32MovtConstant(UINT32* p, unsigned* pReg, unsigned* pCon) -{ - // This decodes the "MOVT" instruction, Encoding T1, from the ARM manual section A8.8.106. - if (!Is32BitThumb2Instruction((UINT16*)p)) - { - return false; - } - - // A Thumb-2 instruction is one or two 16-bit words (in little-endian format). - UINT16 instr1 = *(UINT16*)p; - UINT16 instr2 = *((UINT16*)p + 1); - UINT32 instr = (instr1 << 16) | instr2; - if ((instr & 0xfbf08000) != 0xf2C00000) - { - return false; - } - - *pReg = (instr & 0xf00) >> 8; - *pCon = ExtractArm32MovImm(instr); - return true; -} - -// Is the instruction we're pointing to an Arm32 (Thumb-2) 32-bit instruction? -bool Is32BitThumb2Instruction(UINT16* p) -{ - UINT16 instr1 = *p; - if ((instr1 & 0xf800) < 0xe800) - { - // Not a 32-bit instruction - return false; - } - return true; -} - -// Extract the immediate value from a movw/movt instruction encoding. -UINT32 ExtractArm32MovImm(UINT32 instr) -{ - UINT32 imm4 = (instr >> 16) & 0xf; - UINT32 i = (instr >> 26) & 0x1; - UINT32 imm3 = (instr >> 12) & 0x7; - UINT32 imm8 = instr & 0xff; - return (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8; -} - -// PutArm32MovtConstant: set the constant field in an Arm32 `movt` instruction. -// `*p` points to a `movt` instruction. `con` must be a 16-bit constant. -void PutArm32MovtConstant(UINT32* p, unsigned con) -{ - UINT32 imm4 = (con >> 12) & 0xf; - UINT32 i = (con >> 11) & 0x1; - UINT32 imm3 = (con >> 8) & 0x7; - UINT32 imm8 = con & 0xff; - UINT16 instr1 = *(UINT16*)p; - UINT16 instr2 = *((UINT16*)p + 1); - UINT32 instr = (instr1 << 16) | instr2; - instr = (instr & 0xfbf08f00) | (imm4 << 16) | (i << 26) | (imm3 << 12) | imm8; - *(UINT16*)p = (UINT16)(instr >> 16); - *((UINT16*)p + 1) = (UINT16)instr; -} - -//***************************************************************************** -// Extract the PC-Relative offset from auipc + I-type or S-type adder (addi/load/store/jalr) -//***************************************************************************** -INT64 GetRiscV64AuipcCombo(UINT32 * pCode, bool isStype) -{ - enum - { - OpcodeAuipc = 0x17, - OpcodeAddi = 0x13, - OpcodeLoad = 0x03, - OpcodeStore = 0x23, - OpcodeLoadFp = 0x07, - OpcodeStoreFp = 0x27, - OpcodeJalr = 0x67, - OpcodeMask = 0x7F, - - Funct3AddiJalr = 0x0000, - Funct3Mask = 0x7000, - }; - - UINT32 auipc = pCode[0]; - _ASSERTE((auipc & OpcodeMask) == OpcodeAuipc); - int auipcRegDest = (auipc >> 7) & 0x1F; - _ASSERTE(auipcRegDest != 0); - - INT64 hi20 = (INT32(auipc) >> 12) << 12; - - UINT32 instr = pCode[1]; - UINT32 opcode = instr & OpcodeMask; - UINT32 funct3 = instr & Funct3Mask; - _ASSERTE(opcode == OpcodeLoad || opcode == OpcodeStore || opcode == OpcodeLoadFp || opcode == OpcodeStoreFp || - ((opcode == OpcodeAddi || opcode == OpcodeJalr) && funct3 == Funct3AddiJalr)); - _ASSERTE(isStype == (opcode == OpcodeStore || opcode == OpcodeStoreFp)); - int addrReg = (instr >> 15) & 0x1F; - _ASSERTE(auipcRegDest == addrReg); - - INT64 lo12 = (INT32(instr) >> 25) << 5; // top 7 bits are in the same spot - int bottomBitsPos = isStype ? 7 : 20; - lo12 |= (instr >> bottomBitsPos) & 0x1F; - - return hi20 + lo12; -} - - -//***************************************************************************** -// Deposit the PC-Relative offset into auipc + I-type or S-type adder (addi/load/store/jalr) -//***************************************************************************** -void PutRiscV64AuipcCombo(UINT32 * pCode, INT64 offset, bool isStype) -{ - INT32 lo12 = (offset << (64 - 12)) >> (64 - 12); - INT32 hi20 = INT32(offset - lo12); - _ASSERTE(INT64(lo12) + INT64(hi20) == offset); - - // Replace existing immediate bits because RISC-V relocation placeholders may already carry addends. - pCode[0] &= 0x00000FFF; - pCode[0] |= hi20 & 0xFFFFF000; - - UINT32 lo12Bits = UINT32(lo12) & 0xFFF; - if (isStype) - { - pCode[1] &= 0x01FFF07F; - pCode[1] |= (lo12Bits & 0xFE0) << 20; - pCode[1] |= (lo12Bits & 0x01F) << 7; - } - else - { - pCode[1] &= 0x000FFFFF; - pCode[1] |= lo12Bits << 20; - } - - _ASSERTE(GetRiscV64AuipcCombo(pCode, isStype) == offset); -} - -template -static std::string getFromPrinter(TPrint print) -{ - char buffer[256]; - - size_t requiredBufferSize; - print(buffer, sizeof(buffer), &requiredBufferSize); - - if (requiredBufferSize <= sizeof(buffer)) - { - return std::string(buffer); - } - else - { - std::vector vec(requiredBufferSize); - size_t printed = print(vec.data(), requiredBufferSize, nullptr); - assert(printed == requiredBufferSize - 1); - return std::string(vec.data()); - } -} - -std::string getMethodName(MethodContext* mc, CORINFO_METHOD_HANDLE methHnd) -{ - return getFromPrinter([&](char* buffer, size_t bufferSize, size_t* requiredBufferSize) { - return mc->repPrintMethodName(methHnd, buffer, bufferSize, requiredBufferSize); - }); -} - -std::string getClassName(MethodContext* mc, CORINFO_CLASS_HANDLE clsHnd) -{ - return getFromPrinter([&](char* buffer, size_t bufferSize, size_t* requiredBufferSize) { - return mc->repPrintClassName(clsHnd, buffer, bufferSize, requiredBufferSize); - }); -} - -std::string ConvertToUtf8(const WCHAR* str) -{ - unsigned len = WideCharToMultiByte(CP_UTF8, 0, str, -1, nullptr, 0, nullptr, nullptr); - if (len == 0) - return{}; - - std::vector buf(len + 1); - WideCharToMultiByte(CP_UTF8, 0, str, -1, buf.data(), len + 1, nullptr, nullptr); - return std::string{ buf.data() }; -} diff --git a/src/coreclr/tools/superpmi/superpmi-shared/spmiutil.h b/src/coreclr/tools/superpmi/superpmi-shared/spmiutil.h deleted file mode 100644 index 232eaa8a04861b..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/spmiutil.h +++ /dev/null @@ -1,125 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// SPMIUtil.h - General utility functions -//---------------------------------------------------------- -#ifndef _SPMIUtil -#define _SPMIUtil - -#include "methodcontext.h" -#ifdef TARGET_WINDOWS -#define GET_PROC_ADDRESS ::GetProcAddress -#else -#include -#define GET_PROC_ADDRESS ::dlsym -#endif - -bool BreakOnDebugBreakorAV(); -void SetBreakOnDebugBreakOrAV(bool value); - -bool BreakOnException(); -void SetBreakOnException(bool value); - -void DebugBreakorAV(int val); // Global(ish) error handler - -char* GetEnvironmentVariableWithDefaultA(const char* envVarName, const char* defaultValue = nullptr); - -WCHAR* GetEnvironmentVariableWithDefaultW(const WCHAR* envVarName, const WCHAR* defaultValue = nullptr); - -const char* GetEnvWithDefault(const char* envVarName, const char* defaultValue = nullptr); - -std::string GetProcessCommandLine(); - -bool LoadRealJitLib(HMODULE& realJit, const std::string& realJitPath); - -std::string GetResultFileName(const std::string& folderPath, - const std::string& fileName, - const std::string& extension); - -// SuperPMI stores handles as unsigned 64-bit integers, no matter the platform the collection happens on -// (32 or 64 bit). Handles are defined as pointers. We need to be careful when converting from a handle -// to an int to ensure we don't sign extend the pointer, which is the behavior of some compilers. -// First cast the pointer to an unsigned integer the same size as the pointer, then, if the pointer is -// 32-bits, zero extend it to 64-bits. - -template -inline DWORDLONG CastHandle(T h) -{ - return (DWORDLONG)(uintptr_t)h; -} - -// Basically the same thing, but variables/fields declared as for pointer types. -template -inline DWORDLONG CastPointer(T* p) -{ - return (DWORDLONG)(uintptr_t)p; -} - -enum SPMI_TARGET_ARCHITECTURE -{ - SPMI_TARGET_ARCHITECTURE_X86, - SPMI_TARGET_ARCHITECTURE_AMD64, - SPMI_TARGET_ARCHITECTURE_ARM64, - SPMI_TARGET_ARCHITECTURE_ARM, - SPMI_TARGET_ARCHITECTURE_LOONGARCH64, - SPMI_TARGET_ARCHITECTURE_RISCV64, - SPMI_TARGET_ARCHITECTURE_WASM32, -}; - -SPMI_TARGET_ARCHITECTURE GetSpmiTargetArchitecture(); -void SetSpmiTargetArchitecture(SPMI_TARGET_ARCHITECTURE spmiTargetArchitecture); - -inline bool IsSpmiTarget32Bit() -{ - return (GetSpmiTargetArchitecture() == SPMI_TARGET_ARCHITECTURE_X86) || - (GetSpmiTargetArchitecture() == SPMI_TARGET_ARCHITECTURE_ARM) || - (GetSpmiTargetArchitecture() == SPMI_TARGET_ARCHITECTURE_WASM32); -} - -inline bool IsSpmiTarget64Bit() -{ - return (GetSpmiTargetArchitecture() == SPMI_TARGET_ARCHITECTURE_AMD64) || - (GetSpmiTargetArchitecture() == SPMI_TARGET_ARCHITECTURE_ARM64) || - (GetSpmiTargetArchitecture() == SPMI_TARGET_ARCHITECTURE_LOONGARCH64) || - (GetSpmiTargetArchitecture() == SPMI_TARGET_ARCHITECTURE_RISCV64); -} - -inline size_t SpmiTargetPointerSize() -{ - return IsSpmiTarget64Bit() ? sizeof(INT64) : sizeof(INT32); -} - -void PutArm64Rel28(UINT32* pCode, INT32 imm28); -void PutArm64Rel21(UINT32* pCode, INT32 imm21); -void PutArm64Rel12(UINT32* pCode, INT32 imm12); -void PutArm64Rel12Ldr(UINT32* pCode, INT32 imm12); - -void PutThumb2Mov32(UINT16* p, UINT32 imm32); -void PutThumb2BlRel24(UINT16* p, INT32 imm24); - -bool GetArm64MovConstant(UINT32* p, unsigned* pReg, unsigned* pCon); -bool GetArm64MovkConstant(UINT32* p, unsigned* pReg, unsigned* pCon, unsigned* pShift); -void PutArm64MovkConstant(UINT32* p, unsigned con); - -bool GetArm32MovwConstant(UINT32* p, unsigned* pReg, unsigned* pCon); -bool GetArm32MovtConstant(UINT32* p, unsigned* pReg, unsigned* pCon); -bool Is32BitThumb2Instruction(UINT16* p); -UINT32 ExtractArm32MovImm(UINT32 instr); -void PutArm32MovtConstant(UINT32* p, unsigned con); - -INT64 GetRiscV64AuipcCombo(UINT32 * pCode, bool isStype); -void PutRiscV64AuipcCombo(UINT32 * pCode, INT64 offset, bool isStype); - -template -inline constexpr unsigned ArrLen(T (&)[size]) -{ - return size; -} - -std::string getMethodName(MethodContext* mc, CORINFO_METHOD_HANDLE methHnd); -std::string getClassName(MethodContext* mc, CORINFO_CLASS_HANDLE clsHnd); - -std::string ConvertToUtf8(const WCHAR* str); - -#endif // !_SPMIUtil diff --git a/src/coreclr/tools/superpmi/superpmi-shared/standardpch.h b/src/coreclr/tools/superpmi/superpmi-shared/standardpch.h deleted file mode 100644 index affc2f6ef9688b..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/standardpch.h +++ /dev/null @@ -1,125 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#ifndef STANDARDPCH_H -#define STANDARDPCH_H - -// The point of a PCH file is to never reparse files that never change. -// Only include files here that will almost NEVER change. Headers for the project -// itself are probably inappropriate, because if you change them, the entire -// project will require a recompile. Generally just put SDK style stuff here... - -#ifdef _MSC_VER -#define DEBUG_BREAK __debugbreak() -#else -#define DEBUG_BREAK DebugBreak() -#endif - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif // WIN32_LEAN_AND_MEAN -#include - -#ifdef INTERNAL_BUILD -// There are a few features that reference Microsoft internal resources. We can't build these -// in the open source version. -#define USE_MSVCDIS - -// Disable CoreDisTools until coredistools.dll is statically-linked to the CRT, or until it is delayload linked. -//#define USE_COREDISTOOLS -#endif // INTERNAL_BUILD - -// JIT_BUILD disables certain PAL_TRY debugging and Contracts features. Set this just as the JIT sets it. -#define JIT_BUILD - -#ifdef _MSC_VER -// Defining this prevents: -// error C2338 : / RTCc rejects conformant code, so it isn't supported by the C++ Standard Library. -// Either remove this compiler option, or define _ALLOW_RTCc_IN_STL to acknowledge that you have received this -// warning. -#ifndef _ALLOW_RTCc_IN_STL -#define _ALLOW_RTCc_IN_STL -#endif - -#define MSC_ONLY(x) x -#else // !_MSC_VER -#define MSC_ONLY(x) -#endif // !_MSC_VER - -#ifndef _CRT_SECURE_NO_WARNINGS -#define _CRT_SECURE_NO_WARNINGS -#endif // _CRT_SECURE_NO_WARNINGS - -#define _CRT_RAND_S - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - - -#ifdef USE_MSVCDIS -#define DISLIB -#include "..\external\msvcdis\inc\msvcdis.h" -#include "..\external\msvcdis\inc\disx86.h" -#include "..\external\msvcdis\inc\disarm64.h" -#endif // USE_MSVCDIS - -#ifndef W -#ifdef TARGET_UNIX -#define W(str) u##str -#else // TARGET_UNIX -#define W(str) L##str -#endif // TARGET_UNIX -#endif // !W - -#ifdef TARGET_UNIX -#ifndef DIRECTORY_SEPARATOR_CHAR_A -#define DIRECTORY_SEPARATOR_CHAR_A '/' -#endif -#ifndef DIRECTORY_SEPARATOR_STR_A -#define DIRECTORY_SEPARATOR_STR_A "/" -#endif -#ifndef DIRECTORY_SEPARATOR_STR_W -#define DIRECTORY_SEPARATOR_STR_W W("/") -#endif -#else // TARGET_UNIX -#ifndef DIRECTORY_SEPARATOR_CHAR_A -#define DIRECTORY_SEPARATOR_CHAR_A '\\' -#endif -#ifndef DIRECTORY_SEPARATOR_STR_A -#define DIRECTORY_SEPARATOR_STR_A "\\" -#endif -#ifndef DIRECTORY_SEPARATOR_STR_W -#define DIRECTORY_SEPARATOR_STR_W W("\\") -#endif -#endif // TARGET_UNIX - -#ifdef TARGET_UNIX -#define PLATFORM_SHARED_LIB_SUFFIX_A PAL_SHLIB_SUFFIX -#else // !TARGET_UNIX -#define PLATFORM_SHARED_LIB_SUFFIX_A ".dll" -#endif // !TARGET_UNIX - -#define DEFAULT_REAL_JIT_NAME_A MAKEDLLNAME_A("clrjit2") -#define DEFAULT_REAL_JIT_NAME_W MAKEDLLNAME_W("clrjit2") - -using std::min; -using std::max; - -#include - -#endif // STANDARDPCH_H diff --git a/src/coreclr/tools/superpmi/superpmi-shared/tocfile.cpp b/src/coreclr/tools/superpmi/superpmi-shared/tocfile.cpp deleted file mode 100644 index 4898c6d8b9a161..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/tocfile.cpp +++ /dev/null @@ -1,76 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// TOCFile.cpp - Abstraction for reading a TOC file -//---------------------------------------------------------- - -#include "standardpch.h" -#include "tocfile.h" -#include "logging.h" - -// Tries to load a Table of Contents -void TOCFile::LoadToc(const char* inputFileName, bool validate) -{ - HANDLE hIndex = CreateFileA(inputFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); - if (hIndex == INVALID_HANDLE_VALUE) - { - LogError("Failed to open file '%s'. GetLastError()=%u", inputFileName, GetLastError()); - return; - } - - // Now read the index file - LARGE_INTEGER val; // I'm abusing LARGE_INTEGER here... - DWORD read; - if (!ReadFile(hIndex, &val, sizeof(val), &read, nullptr) || (val.u.LowPart != *(DWORD*)("INDX"))) - { - CloseHandle(hIndex); - LogWarning("The index file %s is invalid: it seems to be missing the starting sentinel/length", inputFileName); - return; - } - - this->m_tocCount = val.u.HighPart; - this->m_tocArray = new TOCElement[this->m_tocCount]; - - // Read the whole array - if (!ReadFile(hIndex, &this->m_tocArray[0], (DWORD)(this->m_tocCount * sizeof(TOCElement)), &read, nullptr) || - (read != (DWORD)(this->m_tocCount * sizeof(TOCElement)))) - { - CloseHandle(hIndex); - this->Clear(); - LogWarning("The index file %s is invalid: it appears to be truncated.", inputFileName); - return; - } - - // Get the last 4 byte token (more abuse of LARGE_INTEGER) - if (!ReadFile(hIndex, &val.u.HighPart, sizeof(DWORD), &read, nullptr) || (read != sizeof(DWORD)) || - (val.u.LowPart != (DWORD)val.u.HighPart)) - { - CloseHandle(hIndex); - this->Clear(); - LogWarning("The index file %s is invalid: it appears to be missing the ending sentinel.", inputFileName); - return; - } - - CloseHandle(hIndex); - - if (validate) - { - int lastNum = -1; - - // Quickly validate that the index is sorted - for (size_t i = 0; i < this->m_tocCount; i++) - { - int nextNum = this->m_tocArray[i].Number; - if (nextNum <= lastNum) - { - // It wasn't sorted: abort - this->Clear(); - LogWarning("The index file %s is invalid: it is not sorted.", inputFileName); - return; - } - lastNum = nextNum; - } - } -} diff --git a/src/coreclr/tools/superpmi/superpmi-shared/tocfile.h b/src/coreclr/tools/superpmi/superpmi-shared/tocfile.h deleted file mode 100644 index 0f010fda824697..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/tocfile.h +++ /dev/null @@ -1,69 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// TOCFile.h - Abstraction for reading a TOC file -//---------------------------------------------------------- -#ifndef _TOCFile -#define _TOCFile - -#include "methodcontext.h" - -class TOCElement -{ -public: - int64_t Offset; - int Number; - char Hash[MM3_HASH_BUFFER_SIZE]; - - TOCElement() - { - } - - TOCElement(int number, int64_t offset) : Offset(offset), Number(number) - { - } -}; - -class TOCFile -{ -private: - TOCElement* m_tocArray; - size_t m_tocCount; - -public: - TOCFile() : m_tocArray(nullptr), m_tocCount(0) - { - } - - ~TOCFile() - { - Clear(); - } - - void Clear() - { - delete[] m_tocArray; - m_tocArray = nullptr; - m_tocCount = 0; - } - - void LoadToc(const char* inputFileName, bool validate = true); - - size_t GetTocCount() - { - return m_tocCount; - } - - const TOCElement* GetElementPtr(size_t i) - { - if (i >= m_tocCount) - { - // error! - return nullptr; - } - return &m_tocArray[i]; - } -}; - -#endif diff --git a/src/coreclr/tools/superpmi/superpmi-shared/typeutils.cpp b/src/coreclr/tools/superpmi/superpmi-shared/typeutils.cpp deleted file mode 100644 index c5945dd562e84d..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/typeutils.cpp +++ /dev/null @@ -1,161 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// TypeUtils.cpp - Utility code for working with managed types -//---------------------------------------------------------- - -#include "standardpch.h" -#include "typeutils.h" -#include "errorhandling.h" -#include "spmiutil.h" - -// Returns a string representation of the given CorInfoType. The naming scheme is based on JITtype2varType -// in src/jit/ee_il_dll.hpp. -const char* TypeUtils::GetCorInfoTypeName(CorInfoType type) -{ - switch (type) - { - case CORINFO_TYPE_VOID: - return "void"; - - case CORINFO_TYPE_BOOL: - return "bool"; - - case CORINFO_TYPE_CHAR: - return "char"; - - case CORINFO_TYPE_BYTE: - return "byte"; - - case CORINFO_TYPE_UBYTE: - return "ubyte"; - - case CORINFO_TYPE_SHORT: - return "short"; - - case CORINFO_TYPE_USHORT: - return "ushort"; - - case CORINFO_TYPE_INT: - return "int"; - - case CORINFO_TYPE_UINT: - return "uint"; - - case CORINFO_TYPE_LONG: - return "long"; - - case CORINFO_TYPE_ULONG: - return "ulong"; - - case CORINFO_TYPE_FLOAT: - return "float"; - - case CORINFO_TYPE_DOUBLE: - return "double"; - - case CORINFO_TYPE_BYREF: - return "byref"; - - case CORINFO_TYPE_VALUECLASS: - return "struct"; - - case CORINFO_TYPE_CLASS: - return "ref"; - - case CORINFO_TYPE_NATIVEINT: - case CORINFO_TYPE_NATIVEUINT: - // Emulates the JIT's concept of TYP_I_IMPL - return IsSpmiTarget64Bit() ? "long" : "int"; - - case CORINFO_TYPE_PTR: - // The JIT just treats this as a TYP_I_IMPL because this isn't a GC root, - // but we don't care about GC-ness: we care about pointer-sized. - return "ptr"; - - default: - LogException(EXCEPTIONCODE_TYPEUTILS, "Unknown type passed into GetCorInfoTypeName (0x%x)", type); - return "UNKNOWN"; - } -} - -bool TypeUtils::IsFloatingPoint(CorInfoType type) -{ - return (type == CORINFO_TYPE_FLOAT || type == CORINFO_TYPE_DOUBLE); -} - -bool TypeUtils::IsPointer(CorInfoType type) -{ - return (type == CORINFO_TYPE_CLASS || type == CORINFO_TYPE_PTR || type == CORINFO_TYPE_BYREF); -} - -bool TypeUtils::IsValueClass(CorInfoType type) -{ - return (type == CORINFO_TYPE_VALUECLASS); -} - -// Determines if a value class, represented by the given class handle, is required to be passed -// by reference (i.e. it cannot be stuffed as-is into a register or stack slot). -bool TypeUtils::ValueClassRequiresByref(MethodContext* mc, CORINFO_CLASS_HANDLE clsHnd) -{ - if (GetSpmiTargetArchitecture() == SPMI_TARGET_ARCHITECTURE_AMD64) - { - size_t size = mc->repGetClassSize(clsHnd); - return ((size > SpmiTargetPointerSize()) || ((size & (size - 1)) != 0)); - } - else - { - LogException(EXCEPTIONCODE_TYPEUTILS, "unsupported architecture", ""); - return false; - } -} - -// Returns the size of the given CorInfoType. If there is no applicable size (e.g. CORINFO_TYPE_VOID, -// CORINFO_TYPE_UNDEF), this throws an exception and returns -1. Taken largely from the MSDN documentation -// for managed sizeof. -size_t TypeUtils::SizeOfCorInfoType(CorInfoType type) -{ - switch (type) - { - case CORINFO_TYPE_BYTE: - case CORINFO_TYPE_UBYTE: - case CORINFO_TYPE_BOOL: - return sizeof(BYTE); - - case CORINFO_TYPE_CHAR: // 2 bytes for Unicode - case CORINFO_TYPE_SHORT: - case CORINFO_TYPE_USHORT: - return sizeof(WORD); - - case CORINFO_TYPE_INT: - case CORINFO_TYPE_UINT: - case CORINFO_TYPE_FLOAT: - return sizeof(DWORD); - - case CORINFO_TYPE_LONG: - case CORINFO_TYPE_ULONG: - case CORINFO_TYPE_DOUBLE: - return sizeof(DWORDLONG); - - case CORINFO_TYPE_NATIVEINT: - case CORINFO_TYPE_NATIVEUINT: - case CORINFO_TYPE_CLASS: - case CORINFO_TYPE_PTR: - case CORINFO_TYPE_BYREF: - return SpmiTargetPointerSize(); - - // This should be obtained via repGetClassSize - case CORINFO_TYPE_VALUECLASS: - LogException(EXCEPTIONCODE_TYPEUTILS, - "SizeOfCorInfoType does not support value types; use repGetClassSize instead (type: 0x%x)", - type); - return 0; - - case CORINFO_TYPE_UNDEF: - case CORINFO_TYPE_VOID: - default: - LogException(EXCEPTIONCODE_TYPEUTILS, "Unsupported type (0x%x) passed into SizeOfCorInfoType", type); - return 0; - } -} diff --git a/src/coreclr/tools/superpmi/superpmi-shared/typeutils.h b/src/coreclr/tools/superpmi/superpmi-shared/typeutils.h deleted file mode 100644 index a62af32371dc60..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shared/typeutils.h +++ /dev/null @@ -1,23 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// TypeUtils.h - Utility code for working with managed types -//---------------------------------------------------------- -#ifndef _TypeUtils -#define _TypeUtils - -#include "methodcontext.h" - -class TypeUtils -{ -public: - static const char* GetCorInfoTypeName(CorInfoType type); - static bool IsFloatingPoint(CorInfoType type); - static bool IsPointer(CorInfoType type); - static bool IsValueClass(CorInfoType type); - static bool ValueClassRequiresByref(MethodContext* mc, CORINFO_CLASS_HANDLE clsHnd); - static size_t SizeOfCorInfoType(CorInfoType type); -}; - -#endif diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/CMakeLists.txt b/src/coreclr/tools/superpmi/superpmi-shim-collector/CMakeLists.txt deleted file mode 100644 index b51f935668ab3d..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/CMakeLists.txt +++ /dev/null @@ -1,88 +0,0 @@ -project(superpmi-shim-collector) - -remove_definitions(-DUNICODE) -remove_definitions(-D_UNICODE) - -add_definitions(-DFEATURE_NO_HOST) -add_definitions(-DSELF_NO_HOST) -add_definitions(-DFEATURE_ENABLE_HARDWARE_EXCEPTIONS) - -if(CLR_CMAKE_HOST_WIN32) - #use static crt - set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded) -endif(CLR_CMAKE_HOST_WIN32) - -include_directories(.) -include_directories(../superpmi-shared) - -set(SUPERPMI_SHIM_COLLECTOR_SOURCES - jithost.cpp - icorjitcompiler.cpp - icorjitinfo.cpp - superpmi-shim-collector.cpp - ../superpmi-shared/callutils.cpp - ../superpmi-shared/compileresult.cpp - ../superpmi-shared/errorhandling.cpp - ../superpmi-shared/hash.cpp - ../superpmi-shared/logging.cpp - ../superpmi-shared/mclist.cpp - ../superpmi-shared/methodcontext.cpp - ../superpmi-shared/methodcontextreader.cpp - ../superpmi-shared/simpletimer.cpp - ../superpmi-shared/spmiutil.cpp - ../superpmi-shared/tocfile.cpp - ../superpmi-shared/typeutils.cpp - ../superpmi-shared/spmidumphelper.cpp -) -if (CLR_CMAKE_TARGET_WIN32) - set(SPMI_COLLECTOR_EXPORTS ${CMAKE_CURRENT_SOURCE_DIR}/superpmi-shim-collector.def) - set(SPMI_COLLECTOR_EXPORTS_FINAL_FILE ${CMAKE_CURRENT_BINARY_DIR}/superpmi-shim-collector.def) - preprocess_file(${SPMI_COLLECTOR_EXPORTS} ${SPMI_COLLECTOR_EXPORTS_FINAL_FILE}) - - list(APPEND SUPERPMI_SHIM_COLLECTOR_SOURCES ${SPMI_COLLECTOR_EXPORTS_FINAL_FILE}) -else() - set(SPMI_COLLECTOR_EXPORTS ${CMAKE_CURRENT_SOURCE_DIR}/superpmi-shim-collector.PAL.exports) - set(SPMI_COLLECTOR_EXPORTS_FINAL_FILE ${CMAKE_CURRENT_BINARY_DIR}/superpmi-shim-collector.PAL.exports) - - generate_exports_file(${SPMI_COLLECTOR_EXPORTS} ${SPMI_COLLECTOR_EXPORTS_FINAL_FILE}) - - if(CLR_CMAKE_TARGET_LINUX OR CLR_CMAKE_TARGET_FREEBSD OR CLR_CMAKE_TARGET_NETBSD OR CLR_CMAKE_TARGET_OPENBSD OR CLR_CMAKE_TARGET_SUNOS) - # This is required to force using our own PAL, not one that we are loaded with. - add_link_options(LINKER:-Bsymbolic) - endif() - - set_exports_linker_option(${SPMI_COLLECTOR_EXPORTS_FINAL_FILE}) - set(SPMI_COLLECTOR_EXPORTS_LINKER_OPTION ${EXPORTS_LINKER_OPTION}) -endif (CLR_CMAKE_TARGET_WIN32) - -add_library_clr(superpmi-shim-collector - SHARED - ${SUPERPMI_SHIM_COLLECTOR_SOURCES} -) - -target_precompile_headers(superpmi-shim-collector PRIVATE "$<$:standardpch.h>") - -add_custom_target(spmi_exports DEPENDS ${SPMI_COLLECTOR_EXPORTS_FINAL_FILE}) -add_dependencies(superpmi-shim-collector spmi_exports) -set_property(TARGET superpmi-shim-collector APPEND_STRING PROPERTY LINK_FLAGS ${SPMI_COLLECTOR_EXPORTS_LINKER_OPTION}) -set_property(TARGET superpmi-shim-collector APPEND_STRING PROPERTY LINK_DEPENDS ${SPMI_COLLECTOR_EXPORTS_FINAL_FILE}) - -if(CLR_CMAKE_HOST_UNIX) - target_link_libraries(superpmi-shim-collector - PRIVATE - utilcodestaticnohost - mscorrc - coreclrpal - coreclrminipal - ) -else() - target_link_libraries(superpmi-shim-collector - PRIVATE - advapi32.lib - coreclrminipal - ${STATIC_MT_CRT_LIB} - ${STATIC_MT_CPP_LIB} - ) -endif(CLR_CMAKE_HOST_UNIX) - -install_clr(TARGETS superpmi-shim-collector DESTINATIONS . COMPONENT spmi) diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitcompiler.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitcompiler.cpp deleted file mode 100644 index d7f15ea6cd1fc3..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitcompiler.cpp +++ /dev/null @@ -1,160 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "standardpch.h" -#include "spmiutil.h" -#include "icorjitcompiler.h" -#include "icorjitinfo.h" -#include "jithost.h" -#include "superpmi-shim-collector.h" - -#define fatMC // this is nice to have on so ildump works... - -void interceptor_ICJC::setTargetOS(CORINFO_OS os) -{ - currentOs = os; - original_ICorJitCompiler->setTargetOS(os); -} - -void interceptor_ICJC::finalizeAndCommitCollection(MethodContext* mc, CorJitResult result, uint8_t* nativeEntry, uint32_t nativeSizeOfCode) -{ - mc->cr->recCompileMethod(&nativeEntry, &nativeSizeOfCode, result); - - if (result == CORJIT_OK) - { - mc->cr->recAllocMemCapture(); - mc->cr->recAllocGCInfoCapture(); - } - - mc->saveToFile(hFile); -} - -template -static void printInFull(TPrinter print) -{ - size_t requiredSize; - char buffer[256]; - print(buffer, sizeof(buffer), &requiredSize); - - if (requiredSize > sizeof(buffer)) - { - std::vector vec(requiredSize); - print(vec.data(), requiredSize, nullptr); - } -} - -CorJitResult interceptor_ICJC::compileMethod(ICorJitInfo* comp, /* IN */ - struct CORINFO_METHOD_INFO* info, /* IN */ - unsigned /* code:CorJitFlag */ flags, /* IN */ - uint8_t** nativeEntry, /* OUT */ - uint32_t* nativeSizeOfCode /* OUT */ - ) -{ - // See if we are filtering the collection (currently by simple substring match) - // - if (g_collectionFilter != nullptr) - { - bool collect = false; - const char* className = nullptr; - const char* methodName = comp->getMethodNameFromMetadata(info->ftn, &className, nullptr, nullptr, 0); - collect |= (methodName != nullptr) && strstr(methodName, g_collectionFilter) != nullptr; - collect |= (className != nullptr) && strstr(className, g_collectionFilter) != nullptr; - if (!collect) - { - return original_ICorJitCompiler->compileMethod(comp, info, flags, nativeEntry, nativeSizeOfCode); - } - } - - auto* mc = new MethodContext(); - interceptor_ICJI our_ICorJitInfo(this, comp, mc); - - mc->cr->recProcessName(GetProcessCommandLine().c_str()); - - mc->recCompileMethod(info, flags, currentOs); - - // force some extra data into our tables.. - // data probably not needed with RyuJIT, but needed in 4.5 and 4.5.1 to help with catching cached values - our_ICorJitInfo.getBuiltinClass(CLASSID_SYSTEM_OBJECT); - our_ICorJitInfo.getBuiltinClass(CLASSID_TYPED_BYREF); - our_ICorJitInfo.getBuiltinClass(CLASSID_TYPE_HANDLE); - our_ICorJitInfo.getBuiltinClass(CLASSID_FIELD_HANDLE); - our_ICorJitInfo.getBuiltinClass(CLASSID_METHOD_HANDLE); - our_ICorJitInfo.getBuiltinClass(CLASSID_STRING); - our_ICorJitInfo.getBuiltinClass(CLASSID_RUNTIME_TYPE); - -#ifdef fatMC - // to build up a fat mc - CORINFO_CLASS_HANDLE ourClass = our_ICorJitInfo.getMethodClass(info->ftn); - our_ICorJitInfo.getClassAttribs(ourClass); - our_ICorJitInfo.isValueClass(ourClass); - our_ICorJitInfo.asCorInfoType(ourClass); - - printInFull([&](char* buffer, size_t bufferSize, size_t* requiredBufferSize) { our_ICorJitInfo.printClassName(ourClass, buffer, bufferSize, requiredBufferSize); }); - printInFull([&](char* buffer, size_t bufferSize, size_t* requiredBufferSize) { our_ICorJitInfo.printMethodName(info->ftn, buffer, bufferSize, requiredBufferSize); }); -#endif - - // Record data from the global context, if any - if (g_globalContext != nullptr) - { - mc->recGlobalContext(*g_globalContext); - } - - struct CompileParams - { - ICorJitCompiler* origComp; - interceptor_ICJI* ourICJI; - struct CORINFO_METHOD_INFO* methodInfo; - unsigned flags; - uint8_t** nativeEntry; - uint32_t* nativeSizeOfCode; - CorJitResult result; - } compileParams; - - compileParams.origComp = original_ICorJitCompiler; - compileParams.ourICJI = &our_ICorJitInfo; - compileParams.methodInfo = info; - compileParams.flags = flags; - compileParams.nativeEntry = nativeEntry; - compileParams.nativeSizeOfCode = nativeSizeOfCode; - compileParams.result = CORJIT_INTERNALERROR; - - *nativeEntry = nullptr; - *nativeSizeOfCode = 0; - - auto doCompile = [mc, our_ICorJitInfo, this, &compileParams]() - { - PAL_TRY(CompileParams*, pParam, &compileParams) - { - pParam->result = pParam->origComp->compileMethod( - pParam->ourICJI, - pParam->methodInfo, - pParam->flags, - pParam->nativeEntry, - pParam->nativeSizeOfCode); - } - PAL_FINALLY - { - if (!our_ICorJitInfo.SavedCollectionEarly()) - { - finalizeAndCommitCollection(mc, compileParams.result, *compileParams.nativeEntry, *compileParams.nativeSizeOfCode); - } - - delete mc; - } - PAL_ENDTRY; - }; - - doCompile(); - - return compileParams.result; -} - -void interceptor_ICJC::ProcessShutdownWork(ICorStaticInfo* info) -{ - original_ICorJitCompiler->ProcessShutdownWork(info); -} - -void interceptor_ICJC::getVersionIdentifier(GUID* versionIdentifier /* OUT */) -{ - original_ICorJitCompiler->getVersionIdentifier(versionIdentifier); -} diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitcompiler.h b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitcompiler.h deleted file mode 100644 index 56e82ca744237c..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitcompiler.h +++ /dev/null @@ -1,25 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#ifndef _ICorJitCompiler -#define _ICorJitCompiler - -#include "runtimedetails.h" - -class MethodContext; - -class interceptor_ICJC : public ICorJitCompiler -{ - -#include "icorjitcompilerimpl.h" - -public: - // Added to help us track the original icjc and be able to easily indirect to it. - ICorJitCompiler* original_ICorJitCompiler; - HANDLE hFile; - CORINFO_OS currentOs; - - void finalizeAndCommitCollection(MethodContext* mc, CorJitResult result, uint8_t* nativeEntry, uint32_t nativeSizeOfCode); -}; - -#endif diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp deleted file mode 100644 index 4f75497d72f34b..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ /dev/null @@ -1,2091 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "standardpch.h" -#include "icorjitinfo.h" -#include "superpmi-shim-collector.h" -#include "icorjitcompiler.h" -#include "methodcontext.h" -#include "errorhandling.h" -#include "logging.h" - -#define fatMC // this is nice to have on so ildump works... - -// Stuff on ICorStaticInfo -/**********************************************************************************/ -// -// ICorMethodInfo -// -/**********************************************************************************/ - -// Quick check whether the method is a jit intrinsic. Returns the same value as getMethodAttribs(ftn) & -// CORINFO_FLG_INTRINSIC, except faster. -bool interceptor_ICJI::isIntrinsic(CORINFO_METHOD_HANDLE ftn) -{ - mc->cr->AddCall("isIntrinsic"); - bool temp = original_ICorJitInfo->isIntrinsic(ftn); - mc->recIsIntrinsic(ftn, temp); - return temp; -} - -bool interceptor_ICJI::canValueClassInstancePointerEscape(CORINFO_METHOD_HANDLE ftn) -{ - mc->cr->AddCall("canValueClassInstancePointerEscape"); - bool temp = original_ICorJitInfo->canValueClassInstancePointerEscape(ftn); - mc->recCanValueClassInstancePointerEscape(ftn, temp); - return temp; -} - -bool interceptor_ICJI::notifyMethodInfoUsage(CORINFO_METHOD_HANDLE ftn) -{ - mc->cr->AddCall("notifyMethodInfoUsage"); - bool temp = original_ICorJitInfo->notifyMethodInfoUsage(ftn); - mc->recNotifyMethodInfoUsage(ftn, temp); - return temp; -} - -bool interceptor_ICJI::notifyInstructionSetUsage(CORINFO_InstructionSet instructionSet, bool supported, bool preserveNegativeDependency) -{ - mc->cr->AddCall("notifyInstructionSetUsage"); - bool result = original_ICorJitInfo->notifyInstructionSetUsage(instructionSet, supported, preserveNegativeDependency); - mc->recNotifyInstructionSetUsage(instructionSet, supported, preserveNegativeDependency, result); - return result; -} - -// return flags (defined above, CORINFO_FLG_PUBLIC ...) -uint32_t interceptor_ICJI::getMethodAttribs(CORINFO_METHOD_HANDLE ftn /* IN */) -{ - mc->cr->AddCall("getMethodAttribs"); - DWORD temp = original_ICorJitInfo->getMethodAttribs(ftn); - mc->recGetMethodAttribs(ftn, temp); - return temp; -} - -// sets private JIT flags, which can be, retrieved using getAttrib. -void interceptor_ICJI::setMethodAttribs(CORINFO_METHOD_HANDLE ftn, /* IN */ - CorInfoMethodRuntimeFlags attribs /* IN */) -{ - mc->cr->AddCall("setMethodAttribs"); - original_ICorJitInfo->setMethodAttribs(ftn, attribs); - mc->cr->recSetMethodAttribs(ftn, attribs); -} - -// Given a method descriptor ftnHnd, extract signature information into sigInfo -// -// 'memberParent' is typically only set when verifying. It should be the -// result of calling getMemberParent. -void interceptor_ICJI::getMethodSig(CORINFO_METHOD_HANDLE ftn, /* IN */ - CORINFO_SIG_INFO* sig, /* OUT */ - CORINFO_CLASS_HANDLE memberParent /* IN */ - ) -{ - mc->cr->AddCall("getMethodSig"); - original_ICorJitInfo->getMethodSig(ftn, sig, memberParent); - mc->recGetMethodSig(ftn, sig, memberParent); -} - -/********************************************************************* -* Note the following methods can only be used on functions known -* to be IL. This includes the method being compiled and any method -* that 'getMethodInfo' returns true for -*********************************************************************/ -// return information about a method private to the implementation -// returns false if method is not IL, or is otherwise unavailable. -// This method is used to fetch data needed to inline functions -bool interceptor_ICJI::getMethodInfo(CORINFO_METHOD_HANDLE ftn, /* IN */ - CORINFO_METHOD_INFO* info, /* OUT */ - CORINFO_CONTEXT_HANDLE context /* IN */ - ) -{ - bool temp = false; - - RunWithErrorExceptionCodeCaptureAndContinue( - [&]() - { - mc->cr->AddCall("getMethodInfo"); - temp = original_ICorJitInfo->getMethodInfo(ftn, info, context); - }, - [&](DWORD exceptionCode) - { - this->mc->recGetMethodInfo(ftn, info, context, temp, exceptionCode); - }); - - return temp; -} - -bool interceptor_ICJI::haveSameMethodDefinition( - CORINFO_METHOD_HANDLE methHnd1, - CORINFO_METHOD_HANDLE methHnd2) -{ - bool result = original_ICorJitInfo->haveSameMethodDefinition(methHnd1, methHnd2); - mc->recHaveSameMethodDefinition(methHnd1, methHnd2, result); - - return result; -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getTypeDefinition( - CORINFO_CLASS_HANDLE type) -{ - CORINFO_CLASS_HANDLE result = original_ICorJitInfo->getTypeDefinition(type); - mc->recGetTypeDefinition(type, result); - - return result; -} - -// Decides if you have any limitations for inlining. If everything's OK, it will return -// INLINE_PASS. -// -// The callerHnd must be the immediate caller (i.e. when we have a chain of inlined calls) -// -// The inlined method need not be verified - -CorInfoInline interceptor_ICJI::canInline(CORINFO_METHOD_HANDLE callerHnd, /* IN */ - CORINFO_METHOD_HANDLE calleeHnd /* IN */ - ) -{ - CorInfoInline temp = INLINE_NEVER; - - RunWithErrorExceptionCodeCaptureAndContinue( - [&]() - { - mc->cr->AddCall("canInline"); - temp = original_ICorJitInfo->canInline(callerHnd, calleeHnd); - }, - [&](DWORD exceptionCode) - { - this->mc->recCanInline(callerHnd, calleeHnd, temp, exceptionCode); - }); - - return temp; -} - -void interceptor_ICJI::beginInlining(CORINFO_METHOD_HANDLE inlinerHnd, - CORINFO_METHOD_HANDLE inlineeHnd) -{ - mc->cr->AddCall("beginInlining"); - original_ICorJitInfo->beginInlining(inlinerHnd, inlineeHnd); -} - -// Reports whether or not a method can be inlined, and why. canInline is responsible for reporting all -// inlining results when it returns INLINE_FAIL and INLINE_NEVER. All other results are reported by the -// JIT. -void interceptor_ICJI::reportInliningDecision(CORINFO_METHOD_HANDLE inlinerHnd, - CORINFO_METHOD_HANDLE inlineeHnd, - CorInfoInline inlineResult, - const char* reason) -{ - mc->cr->AddCall("reportInliningDecision"); - original_ICorJitInfo->reportInliningDecision(inlinerHnd, inlineeHnd, inlineResult, reason); - mc->cr->recReportInliningDecision(inlinerHnd, inlineeHnd, inlineResult, reason); -} - -// Returns false if the call is across security boundaries thus we cannot tailcall -// -// The callerHnd must be the immediate caller (i.e. when we have a chain of inlined calls) -bool interceptor_ICJI::canTailCall(CORINFO_METHOD_HANDLE callerHnd, /* IN */ - CORINFO_METHOD_HANDLE declaredCalleeHnd, /* IN */ - CORINFO_METHOD_HANDLE exactCalleeHnd, /* IN */ - bool fIsTailPrefix /* IN */ - ) -{ - mc->cr->AddCall("canTailCall"); - bool temp = original_ICorJitInfo->canTailCall(callerHnd, declaredCalleeHnd, exactCalleeHnd, fIsTailPrefix); - mc->recCanTailCall(callerHnd, declaredCalleeHnd, exactCalleeHnd, fIsTailPrefix, temp); - return temp; -} - -// Reports whether or not a method can be tail called, and why. -// canTailCall is responsible for reporting all results when it returns -// false. All other results are reported by the JIT. -void interceptor_ICJI::reportTailCallDecision(CORINFO_METHOD_HANDLE callerHnd, - CORINFO_METHOD_HANDLE calleeHnd, - bool fIsTailPrefix, - CorInfoTailCall tailCallResult, - const char* reason) -{ - mc->cr->AddCall("reportTailCallDecision"); - original_ICorJitInfo->reportTailCallDecision(callerHnd, calleeHnd, fIsTailPrefix, tailCallResult, reason); - mc->cr->recReportTailCallDecision(callerHnd, calleeHnd, fIsTailPrefix, tailCallResult, reason); -} - -// get individual exception handler -void interceptor_ICJI::getEHinfo(CORINFO_METHOD_HANDLE ftn, /* IN */ - unsigned EHnumber, /* IN */ - CORINFO_EH_CLAUSE* clause /* OUT */ - ) -{ - mc->cr->AddCall("getEHinfo"); - original_ICorJitInfo->getEHinfo(ftn, EHnumber, clause); - mc->recGetEHinfo(ftn, EHnumber, clause); -} - -// return class it belongs to -CORINFO_CLASS_HANDLE interceptor_ICJI::getMethodClass(CORINFO_METHOD_HANDLE method) -{ - mc->cr->AddCall("getMethodClass"); - CORINFO_CLASS_HANDLE temp = original_ICorJitInfo->getMethodClass(method); - mc->recGetMethodClass(method, temp); - return temp; -} - -// This function returns the offset of the specified method in the -// vtable of it's owning class or interface. -void interceptor_ICJI::getMethodVTableOffset(CORINFO_METHOD_HANDLE method, /* IN */ - unsigned* offsetOfIndirection, /* OUT */ - unsigned* offsetAfterIndirection, /* OUT */ - bool* isRelative /* OUT */ - ) -{ - mc->cr->AddCall("getMethodVTableOffset"); - original_ICorJitInfo->getMethodVTableOffset(method, offsetOfIndirection, offsetAfterIndirection, isRelative); - mc->recGetMethodVTableOffset(method, offsetOfIndirection, offsetAfterIndirection, isRelative); -} - -bool interceptor_ICJI::resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO * info) -{ - mc->cr->AddCall("resolveVirtualMethod"); - bool result = original_ICorJitInfo->resolveVirtualMethod(info); - mc->recResolveVirtualMethod(info, result); - return result; -} - -CORINFO_METHOD_HANDLE interceptor_ICJI::getAsyncOtherVariant(CORINFO_METHOD_HANDLE ftn, bool* variantIsThunk) -{ - mc->cr->AddCall("getAsyncOtherVariant"); - CORINFO_METHOD_HANDLE result = original_ICorJitInfo->getAsyncOtherVariant(ftn, variantIsThunk); - mc->recGetAsyncOtherVariant(ftn, *variantIsThunk, result); - return result; -} - -// Given T, return the type of the default Comparer. -// Returns null if the type can't be determined exactly. -CORINFO_CLASS_HANDLE interceptor_ICJI::getDefaultComparerClass(CORINFO_CLASS_HANDLE cls) -{ - mc->cr->AddCall("getDefaultComparerClass"); - CORINFO_CLASS_HANDLE result = original_ICorJitInfo->getDefaultComparerClass(cls); - mc->recGetDefaultComparerClass(cls, result); - return result; -} - -// Given T, return the type of the default EqualityComparer. -// Returns null if the type can't be determined exactly. -CORINFO_CLASS_HANDLE interceptor_ICJI::getDefaultEqualityComparerClass(CORINFO_CLASS_HANDLE cls) -{ - mc->cr->AddCall("getDefaultEqualityComparerClass"); - CORINFO_CLASS_HANDLE result = original_ICorJitInfo->getDefaultEqualityComparerClass(cls); - mc->recGetDefaultEqualityComparerClass(cls, result); - return result; -} - -// Given T, return the type of the SZGenericArrayEnumerator. -// Returns null if the type can't be determined exactly. -CORINFO_CLASS_HANDLE interceptor_ICJI::getSZArrayHelperEnumeratorClass(CORINFO_CLASS_HANDLE cls) -{ - mc->cr->AddCall("getSZArrayHelperEnumeratorClass"); - CORINFO_CLASS_HANDLE result = original_ICorJitInfo->getSZArrayHelperEnumeratorClass(cls); - mc->recGetSZArrayHelperEnumeratorClass(cls, result); - return result; -} - -void interceptor_ICJI::expandRawHandleIntrinsic(CORINFO_RESOLVED_TOKEN* pResolvedToken, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_GENERICHANDLE_RESULT* pResult) -{ - mc->cr->AddCall("expandRawHandleIntrinsic"); - original_ICorJitInfo->expandRawHandleIntrinsic(pResolvedToken, callerHandle, pResult); - mc->recExpandRawHandleIntrinsic(pResolvedToken, callerHandle, pResult); -} - -// Is the given type in System.Private.Corelib and marked with IntrinsicAttribute? -bool interceptor_ICJI::isIntrinsicType(CORINFO_CLASS_HANDLE classHnd) -{ - mc->cr->AddCall("isIntrinsicType"); - bool temp = original_ICorJitInfo->isIntrinsicType(classHnd); - mc->recIsIntrinsicType(classHnd, temp); - return temp; -} - -// return the entry point calling convention for any of the following -// - a P/Invoke -// - a method marked with UnmanagedCallersOnly -// - a function pointer with the CORINFO_CALLCONV_UNMANAGED calling convention. -CorInfoCallConvExtension interceptor_ICJI::getUnmanagedCallConv(CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* callSiteSig, bool* pSuppressGCTransition) -{ - mc->cr->AddCall("getUnmanagedCallConv"); - CorInfoCallConvExtension temp = original_ICorJitInfo->getUnmanagedCallConv(method, callSiteSig, pSuppressGCTransition); - mc->recGetUnmanagedCallConv(method, callSiteSig, temp, *pSuppressGCTransition); - return temp; -} - -// return if any marshaling is required for PInvoke methods. Note that -// method == 0 => calli. The call site sig is only needed for the varargs or calli case -bool interceptor_ICJI::pInvokeMarshalingRequired(CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* callSiteSig) -{ - mc->cr->AddCall("pInvokeMarshalingRequired"); - bool temp = original_ICorJitInfo->pInvokeMarshalingRequired(method, callSiteSig); - mc->recPInvokeMarshalingRequired(method, callSiteSig, temp); - return temp; -} - -// Check constraints on method type arguments (only). -bool interceptor_ICJI::satisfiesMethodConstraints(CORINFO_CLASS_HANDLE parent, // the exact parent of the method - CORINFO_METHOD_HANDLE method) -{ - mc->cr->AddCall("satisfiesMethodConstraints"); - bool temp = original_ICorJitInfo->satisfiesMethodConstraints(parent, method); - mc->recSatisfiesMethodConstraints(parent, method, temp); - return temp; -} - -// Returns the global cookie for the /GS unsafe buffer checks -// The cookie might be a constant value (JIT), or a handle to memory location (Ngen) -void interceptor_ICJI::getGSCookie(GSCookie* pCookieVal, // OUT - GSCookie** ppCookieVal // OUT - ) -{ - mc->cr->AddCall("getGSCookie"); - original_ICorJitInfo->getGSCookie(pCookieVal, ppCookieVal); - mc->recGetGSCookie(pCookieVal, ppCookieVal); -} - -// Provide patchpoint info for the method currently being jitted. -void interceptor_ICJI::setPatchpointInfo(PatchpointInfo* patchpointInfo) -{ - mc->cr->AddCall("setPatchpointInfo"); - mc->cr->recSetPatchpointInfo(patchpointInfo); // Since the EE frees, we've gotta record before its sent to the EE. - original_ICorJitInfo->setPatchpointInfo(patchpointInfo); -} - -// Get OSR info for the method currently being jitted -PatchpointInfo* interceptor_ICJI::getOSRInfo(unsigned* ilOffset) -{ - mc->cr->AddCall("getOSRInfo"); - PatchpointInfo* patchpointInfo = original_ICorJitInfo->getOSRInfo(ilOffset); - mc->recGetOSRInfo(patchpointInfo, ilOffset); - return patchpointInfo; -} - -/**********************************************************************************/ -// -// ICorModuleInfo -// -/**********************************************************************************/ -// Resolve metadata token into runtime method handles. -void interceptor_ICJI::resolveToken(/* IN, OUT */ CORINFO_RESOLVED_TOKEN* pResolvedToken) -{ - RunWithErrorExceptionCodeCaptureAndContinue( - [&]() - { - mc->cr->AddCall("resolveToken"); - original_ICorJitInfo->resolveToken(pResolvedToken); - }, - [&](DWORD exceptionCode) - { - this->mc->recResolveToken(pResolvedToken, exceptionCode); - }); -} - -// Signature information about the call sig -void interceptor_ICJI::findSig(CORINFO_MODULE_HANDLE module, /* IN */ - unsigned sigTOK, /* IN */ - CORINFO_CONTEXT_HANDLE context, /* IN */ - CORINFO_SIG_INFO* sig /* OUT */ - ) -{ - mc->cr->AddCall("findSig"); - original_ICorJitInfo->findSig(module, sigTOK, context, sig); - mc->recFindSig(module, sigTOK, context, sig); -} - -// for Varargs, the signature at the call site may differ from -// the signature at the definition. Thus we need a way of -// fetching the call site information -void interceptor_ICJI::findCallSiteSig(CORINFO_MODULE_HANDLE module, /* IN */ - unsigned methTOK, /* IN */ - CORINFO_CONTEXT_HANDLE context, /* IN */ - CORINFO_SIG_INFO* sig /* OUT */ - ) -{ - mc->cr->AddCall("findCallSiteSig"); - original_ICorJitInfo->findCallSiteSig(module, methTOK, context, sig); - mc->recFindCallSiteSig(module, methTOK, context, sig); -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getTokenTypeAsHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken /* IN */) -{ - mc->cr->AddCall("getTokenTypeAsHandle"); - CORINFO_CLASS_HANDLE temp = original_ICorJitInfo->getTokenTypeAsHandle(pResolvedToken); - mc->recGetTokenTypeAsHandle(pResolvedToken, temp); - return temp; -} - -int interceptor_ICJI::getStringLiteral(CORINFO_MODULE_HANDLE module, /* IN */ - unsigned metaTOK, /* IN */ - char16_t* buffer, /* OUT */ - int bufferSize,/* IN */ - int startIndex /* IN */ - ) -{ - mc->cr->AddCall("getStringLiteral"); - int temp = original_ICorJitInfo->getStringLiteral(module, metaTOK, buffer, bufferSize, startIndex); - mc->recGetStringLiteral(module, metaTOK, buffer, bufferSize, startIndex, temp); - return temp; -} - -size_t interceptor_ICJI::printObjectDescription(CORINFO_OBJECT_HANDLE handle, /* IN */ - char* buffer, /* OUT */ - size_t bufferSize, /* IN */ - size_t* pRequiredBufferSize /* OUT */ - ) -{ - mc->cr->AddCall("printObjectDescription"); - size_t temp = original_ICorJitInfo->printObjectDescription(handle, buffer, bufferSize, pRequiredBufferSize); - mc->recPrintObjectDescription(handle, buffer, bufferSize, pRequiredBufferSize, temp); - return temp; -} - -/**********************************************************************************/ -// -// ICorClassInfo -// -/**********************************************************************************/ - -// If the value class 'cls' is isomorphic to a primitive type it will -// return that type, otherwise it will return CORINFO_TYPE_VALUECLASS -CorInfoType interceptor_ICJI::asCorInfoType(CORINFO_CLASS_HANDLE cls) -{ - mc->cr->AddCall("asCorInfoType"); - CorInfoType temp = original_ICorJitInfo->asCorInfoType(cls); - mc->recAsCorInfoType(cls, temp); - return temp; -} - -const char* interceptor_ICJI::getClassNameFromMetadata(CORINFO_CLASS_HANDLE cls, const char** namespaceName) -{ - mc->cr->AddCall("getClassNameFromMetadata"); - const char* temp = original_ICorJitInfo->getClassNameFromMetadata(cls, namespaceName); - mc->recGetClassNameFromMetadata(cls, (char*)temp, namespaceName); - return temp; -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getTypeInstantiationArgument(CORINFO_CLASS_HANDLE cls, unsigned index) -{ - mc->cr->AddCall("getTypeInstantiationArgument"); - CORINFO_CLASS_HANDLE result = original_ICorJitInfo->getTypeInstantiationArgument(cls, index); - mc->recGetTypeInstantiationArgument(cls, index, result); - return result; -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getMethodInstantiationArgument(CORINFO_METHOD_HANDLE ftn, unsigned index) -{ - mc->cr->AddCall("getMethodInstantiationArgument"); - CORINFO_CLASS_HANDLE result = original_ICorJitInfo->getMethodInstantiationArgument(ftn, index); - mc->recGetMethodInstantiationArgument(ftn, index, result); - return result; -} - -size_t interceptor_ICJI::printClassName(CORINFO_CLASS_HANDLE cls, char* buffer, size_t bufferSize, size_t* pRequiredBufferSize) -{ - mc->cr->AddCall("printClassName"); - size_t bytesWritten = original_ICorJitInfo->printClassName(cls, buffer, bufferSize, pRequiredBufferSize); - mc->recPrintClassName(cls, buffer, bufferSize, pRequiredBufferSize, bytesWritten); - return bytesWritten; -} - -// Quick check whether the type is a value class. Returns the same value as getClassAttribs(cls) & -// CORINFO_FLG_VALUECLASS, except faster. -bool interceptor_ICJI::isValueClass(CORINFO_CLASS_HANDLE cls) -{ - mc->cr->AddCall("isValueClass"); - bool temp = original_ICorJitInfo->isValueClass(cls); - mc->recIsValueClass(cls, temp); - return temp; -} - -bool interceptor_ICJI::isByRefLike(CORINFO_CLASS_HANDLE cls) -{ - mc->cr->AddCall("isByRefLike"); - bool result = original_ICorJitInfo->isByRefLike(cls); - mc->recIsByRefLike(cls, result); - return result; -} - -bool interceptor_ICJI::isSharedInst(CORINFO_CLASS_HANDLE cls) -{ - mc->cr->AddCall("isSharedInst"); - bool result = original_ICorJitInfo->isSharedInst(cls); - mc->recIsSharedInst(cls, result); - return result; -} - -// return flags (defined above, CORINFO_FLG_PUBLIC ...) -uint32_t interceptor_ICJI::getClassAttribs(CORINFO_CLASS_HANDLE cls) -{ - mc->cr->AddCall("getClassAttribs"); - DWORD temp = original_ICorJitInfo->getClassAttribs(cls); - mc->recGetClassAttribs(cls, temp); - return temp; -} - -// Returns the assembly name of the class "cls". -const char* interceptor_ICJI::getClassAssemblyName(CORINFO_CLASS_HANDLE cls) -{ - mc->cr->AddCall("getClassAssemblyName"); - const char* temp = original_ICorJitInfo->getClassAssemblyName(cls); - mc->recGetClassAssemblyName(cls, temp); - return temp; -} - -// Allocate and delete process-lifetime objects. Should only be -// referred to from static fields, lest a leak occur. -// Note that "LongLifetimeFree" does not execute destructors, if "obj" -// is an array of a struct type with a destructor. -void* interceptor_ICJI::LongLifetimeMalloc(size_t sz) -{ - mc->cr->AddCall("LongLifetimeMalloc"); - return original_ICorJitInfo->LongLifetimeMalloc(sz); -} - -void interceptor_ICJI::LongLifetimeFree(void* obj) -{ - mc->cr->AddCall("LongLifetimeFree"); - original_ICorJitInfo->LongLifetimeFree(obj); -} - - -bool interceptor_ICJI::getIsClassInitedFlagAddress(CORINFO_CLASS_HANDLE cls, - CORINFO_CONST_LOOKUP* addr, - int* offset) -{ - mc->cr->AddCall("getIsClassInitedFlagAddress"); - bool temp = original_ICorJitInfo->getIsClassInitedFlagAddress(cls, addr, offset); - mc->recGetIsClassInitedFlagAddress(cls, addr, offset, temp); - return temp; -} - -bool interceptor_ICJI::getStaticBaseAddress(CORINFO_CLASS_HANDLE cls, - bool isGc, - CORINFO_CONST_LOOKUP* addr) -{ - mc->cr->AddCall("getStaticBaseAddress"); - bool temp = original_ICorJitInfo->getStaticBaseAddress(cls, isGc, addr); - mc->recGetStaticBaseAddress(cls, isGc, addr, temp); - return temp; -} - -// return the number of bytes needed by an instance of the class -unsigned interceptor_ICJI::getClassSize(CORINFO_CLASS_HANDLE cls) -{ - mc->cr->AddCall("getClassSize"); - unsigned temp = original_ICorJitInfo->getClassSize(cls); - mc->recGetClassSize(cls, temp); - return temp; -} - -// return the number of bytes needed by an instance of the class allocated on the heap -unsigned interceptor_ICJI::getHeapClassSize(CORINFO_CLASS_HANDLE cls) -{ - mc->cr->AddCall("getHeapClassSize"); - unsigned temp = original_ICorJitInfo->getHeapClassSize(cls); - mc->recGetHeapClassSize(cls, temp); - return temp; -} - -bool interceptor_ICJI::canAllocateOnStack(CORINFO_CLASS_HANDLE cls) -{ - mc->cr->AddCall("canAllocateOnStack"); - bool temp = original_ICorJitInfo->canAllocateOnStack(cls); - mc->recCanAllocateOnStack(cls, temp); - return temp; -} - -unsigned interceptor_ICJI::getClassAlignmentRequirement(CORINFO_CLASS_HANDLE cls, bool fDoubleAlignHint) -{ - mc->cr->AddCall("getClassAlignmentRequirement"); - unsigned temp = original_ICorJitInfo->getClassAlignmentRequirement(cls, fDoubleAlignHint); - mc->recGetClassAlignmentRequirement(cls, fDoubleAlignHint, temp); - return temp; -} - -// This is called for ref and value classes. It returns a boolean array -// in representing of 'cls' from a GC perspective. The class is -// assumed to be an array of machine words -// (of length // getClassSize(cls) / TARGET_POINTER_SIZE), -// 'gcPtrs' is a pointer to an array of BYTEs of this length. -// getClassGClayout fills in this array so that gcPtrs[i] is set -// to one of the CorInfoGCType values which is the GC type of -// the i-th machine word of an object of type 'cls' -// returns the number of GC pointers in the array -unsigned interceptor_ICJI::getClassGClayout(CORINFO_CLASS_HANDLE cls, /* IN */ - BYTE* gcPtrs /* OUT */ - ) -{ - mc->cr->AddCall("getClassGClayout"); - unsigned temp = original_ICorJitInfo->getClassGClayout(cls, gcPtrs); - - // Use the target's pointer size, not the host's, so cross-target collections - // (e.g., wasm32 on an x64 host) record the full GC-layout buffer. - unsigned targetPointerSize; - switch (original_ICorJitInfo->getExpectedTargetArchitecture()) - { - case CORINFO_ARCH_X86: - case CORINFO_ARCH_ARM: - case CORINFO_ARCH_WASM32: - targetPointerSize = 4; - break; - default: - targetPointerSize = 8; - break; - } - - unsigned len = 0; - if (isValueClass(cls)) - { - len = (getClassSize(cls) + targetPointerSize - 1) / targetPointerSize; - } - else - { - len = (getHeapClassSize(cls) + targetPointerSize - 1) / targetPointerSize; - } - mc->recGetClassGClayout(cls, gcPtrs, len, temp); - return temp; -} - -// returns the number of instance fields in a class -unsigned interceptor_ICJI::getClassNumInstanceFields(CORINFO_CLASS_HANDLE cls /* IN */ - ) -{ - mc->cr->AddCall("getClassNumInstanceFields"); - unsigned temp = original_ICorJitInfo->getClassNumInstanceFields(cls); - mc->recGetClassNumInstanceFields(cls, temp); - return temp; -} - -CORINFO_FIELD_HANDLE interceptor_ICJI::getFieldInClass(CORINFO_CLASS_HANDLE clsHnd, INT num) -{ - mc->cr->AddCall("getFieldInClass"); - CORINFO_FIELD_HANDLE temp = original_ICorJitInfo->getFieldInClass(clsHnd, num); - mc->recGetFieldInClass(clsHnd, num, temp); - return temp; -} - -GetTypeLayoutResult interceptor_ICJI::getTypeLayout( - CORINFO_CLASS_HANDLE typeHnd, - CORINFO_TYPE_LAYOUT_NODE* nodes, - size_t* numNodes) -{ - mc->cr->AddCall("getTypeLayout"); - GetTypeLayoutResult result = original_ICorJitInfo->getTypeLayout(typeHnd, nodes, numNodes); - mc->recGetTypeLayout(result, typeHnd, nodes, *numNodes); - return result; -} - -bool interceptor_ICJI::checkMethodModifier(CORINFO_METHOD_HANDLE hMethod, LPCSTR modifier, bool fOptional) -{ - mc->cr->AddCall("checkMethodModifier"); - bool result = original_ICorJitInfo->checkMethodModifier(hMethod, modifier, fOptional); - mc->recCheckMethodModifier(hMethod, modifier, fOptional, result); - return result; -} - -// returns the "NEW" helper optimized for "newCls." -CorInfoHelpFunc interceptor_ICJI::getNewHelper(CORINFO_CLASS_HANDLE classHandle, - bool* pHasSideEffects) -{ - CorInfoHelpFunc result = CORINFO_HELP_UNDEF; - bool hasSideEffects = false; - - RunWithErrorExceptionCodeCaptureAndContinue( - [&]() - { - mc->cr->AddCall("getNewHelper"); - result = original_ICorJitInfo->getNewHelper(classHandle, &hasSideEffects); - }, - [&](DWORD exceptionCode) - { - mc->recGetNewHelper(classHandle, hasSideEffects, result, exceptionCode); - }); - - if (pHasSideEffects != nullptr) - { - *pHasSideEffects = hasSideEffects; - } - - return result; -} - -// returns the newArr (1-Dim array) helper optimized for "arrayCls." -CorInfoHelpFunc interceptor_ICJI::getNewArrHelper(CORINFO_CLASS_HANDLE arrayCls) -{ - mc->cr->AddCall("getNewArrHelper"); - CorInfoHelpFunc temp = original_ICorJitInfo->getNewArrHelper(arrayCls); - mc->recGetNewArrHelper(arrayCls, temp); - return temp; -} - -// returns the optimized "IsInstanceOf" or "ChkCast" helper -CorInfoHelpFunc interceptor_ICJI::getCastingHelper(CORINFO_RESOLVED_TOKEN* pResolvedToken, bool fThrowing) -{ - mc->cr->AddCall("getCastingHelper"); - CorInfoHelpFunc temp = original_ICorJitInfo->getCastingHelper(pResolvedToken, fThrowing); - mc->recGetCastingHelper(pResolvedToken, fThrowing, temp); - return temp; -} - -// returns helper to trigger static constructor -CorInfoHelpFunc interceptor_ICJI::getSharedCCtorHelper(CORINFO_CLASS_HANDLE clsHnd) -{ - mc->cr->AddCall("getSharedCCtorHelper"); - CorInfoHelpFunc temp = original_ICorJitInfo->getSharedCCtorHelper(clsHnd); - mc->recGetSharedCCtorHelper(clsHnd, temp); - return temp; -} - -// This is not pretty. Boxing nullable actually returns -// a boxed not a boxed Nullable. This call allows the verifier -// to call back to the EE on the 'box' instruction and get the transformed -// type to use for verification. -CORINFO_CLASS_HANDLE interceptor_ICJI::getTypeForBox(CORINFO_CLASS_HANDLE cls) -{ - mc->cr->AddCall("getTypeForBox"); - CORINFO_CLASS_HANDLE temp = original_ICorJitInfo->getTypeForBox(cls); - mc->recGetTypeForBox(cls, temp); - return temp; -} - -// returns the correct box helper for a particular class. Note -// that if this returns CORINFO_HELP_BOX, the JIT can assume -// 'standard' boxing (allocate object and copy), and optimize -CorInfoHelpFunc interceptor_ICJI::getBoxHelper(CORINFO_CLASS_HANDLE cls) -{ - mc->cr->AddCall("getBoxHelper"); - CorInfoHelpFunc temp = original_ICorJitInfo->getBoxHelper(cls); - mc->recGetBoxHelper(cls, temp); - return temp; -} - -// returns the unbox helper. If 'helperCopies' points to a true -// value it means the JIT is requesting a helper that unboxes the -// value into a particular location and thus has the signature -// void unboxHelper(void* dest, CORINFO_CLASS_HANDLE cls, Object* obj) -// Otherwise (it is null or points at a FALSE value) it is requesting -// a helper that returns a pointer to the unboxed data -// void* unboxHelper(CORINFO_CLASS_HANDLE cls, Object* obj) -// The EE has the option of NOT returning the copy style helper -// (But must be able to always honor the non-copy style helper) -// The EE set 'helperCopies' on return to indicate what kind of -// helper has been created. -CorInfoHelpFunc interceptor_ICJI::getUnBoxHelper(CORINFO_CLASS_HANDLE cls) -{ - mc->cr->AddCall("getUnBoxHelper"); - CorInfoHelpFunc temp = original_ICorJitInfo->getUnBoxHelper(cls); - mc->recGetUnBoxHelper(cls, temp); - return temp; -} - -CORINFO_OBJECT_HANDLE interceptor_ICJI::getRuntimeTypePointer(CORINFO_CLASS_HANDLE cls) -{ - mc->cr->AddCall("getRuntimeTypePointer"); - CORINFO_OBJECT_HANDLE temp = original_ICorJitInfo->getRuntimeTypePointer(cls); - mc->recGetRuntimeTypePointer(cls, temp); - return temp; -} - -bool interceptor_ICJI::isObjectImmutable(CORINFO_OBJECT_HANDLE typeObj) -{ - mc->cr->AddCall("isObjectImmutable"); - bool temp = original_ICorJitInfo->isObjectImmutable(typeObj); - mc->recIsObjectImmutable(typeObj, temp); - return temp; -} - -bool interceptor_ICJI::getStringChar(CORINFO_OBJECT_HANDLE strObj, int index, uint16_t* value) -{ - mc->cr->AddCall("getStringChar"); - bool temp = original_ICorJitInfo->getStringChar(strObj, index, value); - mc->recGetStringChar(strObj, index, value, temp); - return temp; -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getObjectType(CORINFO_OBJECT_HANDLE typeObj) -{ - mc->cr->AddCall("getObjectType"); - CORINFO_CLASS_HANDLE temp = original_ICorJitInfo->getObjectType(typeObj); - mc->recGetObjectType(typeObj, temp); - return temp; -} - -bool interceptor_ICJI::getReadyToRunHelper(CORINFO_RESOLVED_TOKEN* pResolvedToken, - CorInfoHelpFunc id, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_CONST_LOOKUP* pLookup) -{ - mc->cr->AddCall("getReadyToRunHelper"); - bool result = original_ICorJitInfo->getReadyToRunHelper(pResolvedToken, id, callerHandle, pLookup); - mc->recGetReadyToRunHelper(pResolvedToken, id, callerHandle, pLookup, result); - return result; -} - -void interceptor_ICJI::getReadyToRunDelegateCtorHelper(CORINFO_RESOLVED_TOKEN* pTargetMethod, - mdToken targetConstraint, - CORINFO_CLASS_HANDLE delegateType, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_LOOKUP* pLookup) -{ - mc->cr->AddCall("getReadyToRunDelegateCtorHelper"); - original_ICorJitInfo->getReadyToRunDelegateCtorHelper(pTargetMethod, targetConstraint, delegateType, callerHandle, pLookup); - mc->recGetReadyToRunDelegateCtorHelper(pTargetMethod, targetConstraint, delegateType, callerHandle, pLookup); -} - -// This function tries to initialize the class (run the class constructor). -// this function returns whether the JIT must insert helper calls before -// accessing static field or method. -// -// See code:ICorClassInfo#ClassConstruction. -CorInfoInitClassResult interceptor_ICJI::initClass( - CORINFO_FIELD_HANDLE field, // Non-nullptr - inquire about cctor trigger before static field access - // nullptr - inquire about cctor trigger in method prolog - CORINFO_METHOD_HANDLE method, // Method referencing the field or prolog - CORINFO_CONTEXT_HANDLE context // Exact context of method - ) -{ - mc->cr->AddCall("initClass"); - CorInfoInitClassResult temp = original_ICorJitInfo->initClass(field, method, context); - mc->recInitClass(field, method, context, temp); - return temp; -} - -// returns the class handle for the special builtin classes -CORINFO_CLASS_HANDLE interceptor_ICJI::getBuiltinClass(CorInfoClassId classId) -{ - mc->cr->AddCall("getBuiltinClass"); - CORINFO_CLASS_HANDLE temp = original_ICorJitInfo->getBuiltinClass(classId); - mc->recGetBuiltinClass(classId, temp); - return temp; -} - -// "System.Int32" ==> CORINFO_TYPE_INT.. -CorInfoType interceptor_ICJI::getTypeForPrimitiveValueClass(CORINFO_CLASS_HANDLE cls) -{ - mc->cr->AddCall("getTypeForPrimitiveValueClass"); - CorInfoType temp = original_ICorJitInfo->getTypeForPrimitiveValueClass(cls); - mc->recGetTypeForPrimitiveValueClass(cls, temp); - return temp; -} - -// "System.Int32" ==> CORINFO_TYPE_INT.. -// "System.UInt32" ==> CORINFO_TYPE_UINT.. -CorInfoType interceptor_ICJI::getTypeForPrimitiveNumericClass(CORINFO_CLASS_HANDLE cls) -{ - mc->cr->AddCall("getTypeForPrimitiveNumericClass"); - CorInfoType temp = original_ICorJitInfo->getTypeForPrimitiveNumericClass(cls); - mc->recGetTypeForPrimitiveNumericClass(cls, temp); - return temp; -} - -// TRUE if child is a subtype of parent -// if parent is an interface, then does child implement / extend parent -bool interceptor_ICJI::canCast(CORINFO_CLASS_HANDLE child, // subtype (extends parent) - CORINFO_CLASS_HANDLE parent // base type - ) -{ - mc->cr->AddCall("canCast"); - bool temp = original_ICorJitInfo->canCast(child, parent); - mc->recCanCast(child, parent, temp); - return temp; -} - -// See if a cast from fromClass to toClass will succeed, fail, or needs -// to be resolved at runtime. -TypeCompareState interceptor_ICJI::compareTypesForCast(CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass) -{ - mc->cr->AddCall("compareTypesForCast"); - TypeCompareState temp = original_ICorJitInfo->compareTypesForCast(fromClass, toClass); - mc->recCompareTypesForCast(fromClass, toClass, temp); - return temp; -} - -// See if types represented by cls1 and cls2 compare equal, not -// equal, or the comparison needs to be resolved at runtime. -TypeCompareState interceptor_ICJI::compareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2) -{ - mc->cr->AddCall("compareTypesForEquality"); - TypeCompareState temp = original_ICorJitInfo->compareTypesForEquality(cls1, cls2); - mc->recCompareTypesForEquality(cls1, cls2, temp); - return temp; -} - -// Returns true if cls2 is known to be a more specific type than cls1. -bool interceptor_ICJI::isMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2) -{ - mc->cr->AddCall("isMoreSpecificType"); - bool temp = original_ICorJitInfo->isMoreSpecificType(cls1, cls2); - mc->recIsMoreSpecificType(cls1, cls2, temp); - return temp; -} - -// Returns true if a class handle can only describe values of exactly one type. -bool interceptor_ICJI::isExactType(CORINFO_CLASS_HANDLE cls) -{ - mc->cr->AddCall("isExactType"); - bool temp = original_ICorJitInfo->isExactType(cls); - mc->recIsExactType(cls, temp); - return temp; -} - -// Returns whether a class handle represents a generic type, if that can be statically determined. -TypeCompareState interceptor_ICJI::isGenericType(CORINFO_CLASS_HANDLE cls) -{ - mc->cr->AddCall("isGenericType"); - TypeCompareState temp = original_ICorJitInfo->isGenericType(cls); - mc->recIsGenericType(cls, temp); - return temp; -} - -// Returns whether a class handle represents a Nullable type, if that can be statically determined. -TypeCompareState interceptor_ICJI::isNullableType(CORINFO_CLASS_HANDLE cls) -{ - mc->cr->AddCall("isNullableType"); - TypeCompareState temp = original_ICorJitInfo->isNullableType(cls); - mc->recIsNullableType(cls, temp); - return temp; -} - -// Returns TypeCompareState::Must if cls is known to be an enum. -// For enums with known exact type returns the underlying -// type in underlyingType when the provided pointer is -// non-NULL. -// Returns TypeCompareState::May when a runtime check is required. -TypeCompareState interceptor_ICJI::isEnum(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE* underlyingType) -{ - mc->cr->AddCall("isEnum"); - CORINFO_CLASS_HANDLE tempUnderlyingType = nullptr; - TypeCompareState temp = original_ICorJitInfo->isEnum(cls, &tempUnderlyingType); - mc->recIsEnum(cls, tempUnderlyingType, temp); - if (underlyingType != nullptr) - { - *underlyingType = tempUnderlyingType; - } - return temp; -} - -// Given a class handle, returns the Parent type. -// For COMObjectType, it returns Class Handle of System.Object. -// Returns 0 if System.Object is passed in. -CORINFO_CLASS_HANDLE interceptor_ICJI::getParentType(CORINFO_CLASS_HANDLE cls) -{ - mc->cr->AddCall("getParentType"); - CORINFO_CLASS_HANDLE temp = original_ICorJitInfo->getParentType(cls); - mc->recGetParentType(cls, temp); - return temp; -} - -// Returns the CorInfoType of the "child type". If the child type is -// not a primitive type, *clsRet will be set. -// Given an Array of Type Foo, returns Foo. -// Given BYREF Foo, returns Foo -CorInfoType interceptor_ICJI::getChildType(CORINFO_CLASS_HANDLE clsHnd, CORINFO_CLASS_HANDLE* clsRet) -{ - mc->cr->AddCall("getChildType"); - CorInfoType temp = original_ICorJitInfo->getChildType(clsHnd, clsRet); - mc->recGetChildType(clsHnd, clsRet, temp); - return temp; -} - -// Check if this is a single dimensional array type -bool interceptor_ICJI::isSDArray(CORINFO_CLASS_HANDLE cls) -{ - mc->cr->AddCall("isSDArray"); - bool temp = original_ICorJitInfo->isSDArray(cls); - mc->recIsSDArray(cls, temp); - return temp; -} - -// Get the numbmer of dimensions in an array -unsigned interceptor_ICJI::getArrayRank(CORINFO_CLASS_HANDLE cls) -{ - mc->cr->AddCall("getArrayRank"); - unsigned result = original_ICorJitInfo->getArrayRank(cls); - mc->recGetArrayRank(cls, result); - return result; -} - -// Get the index of runtime provided array method -CorInfoArrayIntrinsic interceptor_ICJI::getArrayIntrinsicID(CORINFO_METHOD_HANDLE ftn) -{ - mc->cr->AddCall("getArrayIntrinsicID"); - CorInfoArrayIntrinsic result = original_ICorJitInfo->getArrayIntrinsicID(ftn); - mc->recGetArrayIntrinsicID(ftn, result); - return result; -} - -// Get static field data for an array -void* interceptor_ICJI::getArrayInitializationData(CORINFO_FIELD_HANDLE field, uint32_t size) -{ - mc->cr->AddCall("getArrayInitializationData"); - void* temp = original_ICorJitInfo->getArrayInitializationData(field, size); - mc->recGetArrayInitializationData(field, size, temp); - return temp; -} - -// Check Visibility rules. -CorInfoIsAccessAllowedResult interceptor_ICJI::canAccessClass( - CORINFO_RESOLVED_TOKEN* pResolvedToken, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_HELPER_DESC* pAccessHelper /* If canAccessMethod returns something other - than ALLOWED, then this is filled in. */ - ) -{ - mc->cr->AddCall("canAccessClass"); - CorInfoIsAccessAllowedResult temp = - original_ICorJitInfo->canAccessClass(pResolvedToken, callerHandle, pAccessHelper); - mc->recCanAccessClass(pResolvedToken, callerHandle, pAccessHelper, temp); - return temp; -} - -/**********************************************************************************/ -// -// ICorFieldInfo -// -/**********************************************************************************/ - -size_t interceptor_ICJI::printFieldName(CORINFO_FIELD_HANDLE ftn, char* buffer, size_t bufferSize, size_t* pRequiredBufferSize) -{ - mc->cr->AddCall("printFieldName"); - size_t temp = original_ICorJitInfo->printFieldName(ftn, buffer, bufferSize, pRequiredBufferSize); - mc->recPrintFieldName(ftn, buffer, bufferSize, pRequiredBufferSize, temp); - return temp; -} - -// return class it belongs to -CORINFO_CLASS_HANDLE interceptor_ICJI::getFieldClass(CORINFO_FIELD_HANDLE field) -{ - mc->cr->AddCall("getFieldClass"); - CORINFO_CLASS_HANDLE temp = original_ICorJitInfo->getFieldClass(field); - mc->recGetFieldClass(field, temp); - return temp; -} - -// Return the field's type, if it is CORINFO_TYPE_VALUECLASS 'structType' is set -// the field's value class (if 'structType' == 0, then don't bother -// the structure info). -// -// 'fieldOwnerHint' is, potentially, a more exact owner of the field. -// it's fine for it to be non-precise, it's just a hint. -CorInfoType interceptor_ICJI::getFieldType(CORINFO_FIELD_HANDLE field, - CORINFO_CLASS_HANDLE* structType, - CORINFO_CLASS_HANDLE fieldOwnerHint /* IN */ - ) -{ - mc->cr->AddCall("getFieldType"); - CorInfoType temp = original_ICorJitInfo->getFieldType(field, structType, fieldOwnerHint); - mc->recGetFieldType(field, structType, fieldOwnerHint, temp); - return temp; -} - -// return the data member's instance offset -unsigned interceptor_ICJI::getFieldOffset(CORINFO_FIELD_HANDLE field) -{ - mc->cr->AddCall("getFieldOffset"); - unsigned temp = original_ICorJitInfo->getFieldOffset(field); - mc->recGetFieldOffset(field, temp); - return temp; -} - -void interceptor_ICJI::getFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_ACCESS_FLAGS flags, - CORINFO_FIELD_INFO* pResult) -{ - mc->cr->AddCall("getFieldInfo"); - original_ICorJitInfo->getFieldInfo(pResolvedToken, callerHandle, flags, pResult); - mc->recGetFieldInfo(pResolvedToken, callerHandle, flags, pResult); -} - -uint32_t interceptor_ICJI::getThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, bool isGCType) -{ - mc->cr->AddCall("getThreadLocalFieldInfo"); - uint32_t result = original_ICorJitInfo->getThreadLocalFieldInfo(field, isGCType); - mc->recGetThreadLocalFieldInfo(field, isGCType, result); - return result; -} - -void interceptor_ICJI::getThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) -{ - mc->cr->AddCall("getThreadLocalStaticBlocksInfo"); - original_ICorJitInfo->getThreadLocalStaticBlocksInfo(pInfo); - mc->recGetThreadLocalStaticBlocksInfo(pInfo); -} - -void interceptor_ICJI::getThreadLocalStaticInfo_NativeAOT(CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo) -{ - mc->cr->AddCall("getThreadLocalStaticInfo_NativeAOT"); - original_ICorJitInfo->getThreadLocalStaticInfo_NativeAOT(pInfo); - mc->recGetThreadLocalStaticInfo_NativeAOT(pInfo); -} - -// Returns true iff "fldHnd" represents a static field. -bool interceptor_ICJI::isFieldStatic(CORINFO_FIELD_HANDLE fldHnd) -{ - mc->cr->AddCall("isFieldStatic"); - bool result = original_ICorJitInfo->isFieldStatic(fldHnd); - mc->recIsFieldStatic(fldHnd, result); - return result; -} - -int interceptor_ICJI::getArrayOrStringLength(CORINFO_OBJECT_HANDLE objHnd) -{ - mc->cr->AddCall("getArrayOrStringLength"); - int result = original_ICorJitInfo->getArrayOrStringLength(objHnd); - mc->recGetArrayOrStringLength(objHnd, result); - return result; -} - -/*********************************************************************************/ -// -// ICorDebugInfo -// -/*********************************************************************************/ -// Query the EE to find out where interesting break points -// in the code are. The native compiler will ensure that these places -// have a corresponding break point in native code. -// -// Note that unless CORJIT_FLAG_DEBUG_CODE is specified, this function will -// be used only as a hint and the native compiler should not change its -// code generation. -void interceptor_ICJI::getBoundaries(CORINFO_METHOD_HANDLE ftn, // [IN] method of interest - unsigned int* cILOffsets, // [OUT] size of pILOffsets - uint32_t** pILOffsets, // [OUT] IL offsets of interest - // jit MUST free with freeArray! - ICorDebugInfo::BoundaryTypes* implicitBoundaries // [OUT] tell jit, all boundaries of - // this type - ) -{ - mc->cr->AddCall("getBoundaries"); - original_ICorJitInfo->getBoundaries(ftn, cILOffsets, pILOffsets, implicitBoundaries); - mc->recGetBoundaries(ftn, cILOffsets, pILOffsets, implicitBoundaries); -} - -// Report back the mapping from IL to native code, -// this map should include all boundaries that 'getBoundaries' -// reported as interesting to the debugger. - -// Note that debugger (and profiler) is assuming that all of the -// offsets form a contiguous block of memory, and that the -// OffsetMapping is sorted in order of increasing native offset. -// Note - Ownership of pMap is transferred with this call. We need to record it before its passed on to the EE. -void interceptor_ICJI::setBoundaries(CORINFO_METHOD_HANDLE ftn, // [IN] method of interest - ULONG32 cMap, // [IN] size of pMap - ICorDebugInfo::OffsetMapping* pMap // [IN] map including all points of interest. - // jit allocated with allocateArray, EE - // frees - ) -{ - mc->cr->AddCall("setBoundaries"); - mc->cr->recSetBoundaries(ftn, cMap, pMap); // Since the EE frees, we've gotta record before its sent to the EE. - original_ICorJitInfo->setBoundaries(ftn, cMap, pMap); -} - -// Query the EE to find out the scope of local variables. -// normally the JIT would trash variables after last use, but -// under debugging, the JIT needs to keep them live over their -// entire scope so that they can be inspected. -// -// Note that unless CORJIT_FLAG_DEBUG_CODE is specified, this function will -// be used only as a hint and the native compiler should not change its -// code generation. -void interceptor_ICJI::getVars(CORINFO_METHOD_HANDLE ftn, // [IN] method of interest - ULONG32* cVars, // [OUT] size of 'vars' - ICorDebugInfo::ILVarInfo** vars, // [OUT] scopes of variables of interest - // jit MUST free with freeArray! - bool* extendOthers // [OUT] it TRUE, then assume the scope - // of unmentioned vars is entire method - ) -{ - mc->cr->AddCall("getVars"); - original_ICorJitInfo->getVars(ftn, cVars, vars, extendOthers); - mc->recGetVars(ftn, cVars, vars, extendOthers); -} - -// Report back to the EE the location of every variable. -// note that the JIT might split lifetimes into different -// locations etc. -// Note - Ownership of vars is transferred with this call. We need to record it before its passed on to the EE. -void interceptor_ICJI::setVars(CORINFO_METHOD_HANDLE ftn, // [IN] method of interest - ULONG32 cVars, // [IN] size of 'vars' - ICorDebugInfo::NativeVarInfo* vars // [IN] map telling where local vars are stored at - // what points - // jit allocated with allocateArray, EE frees - ) -{ - mc->cr->AddCall("setVars"); - mc->cr->recSetVars(ftn, cVars, vars); // Since the EE frees, we've gotta record before its sent to the EE. - original_ICorJitInfo->setVars(ftn, cVars, vars); -} - -void interceptor_ICJI::reportRichMappings(ICorDebugInfo::InlineTreeNode* inlineTreeNodes, - uint32_t numInlineTreeNodes, - ICorDebugInfo::RichOffsetMapping* mappings, - uint32_t numMappings) -{ - mc->cr->AddCall("reportRichMappings"); - // Compile output that we do not currently save - original_ICorJitInfo->reportRichMappings(inlineTreeNodes, numInlineTreeNodes, mappings, numMappings); -} - -void interceptor_ICJI::reportAsyncDebugInfo(ICorDebugInfo::AsyncInfo* asyncInfo, - ICorDebugInfo::AsyncSuspensionPoint* suspensionPoints, - ICorDebugInfo::AsyncContinuationVarInfo* vars, - uint32_t numVars) -{ - mc->cr->AddCall("reportAsyncDebugInfo"); - // Compile output that we do not currently save - original_ICorJitInfo->reportAsyncDebugInfo(asyncInfo, suspensionPoints, vars, numVars); -} - -void interceptor_ICJI::reportMetadata(const char* key, const void* value, size_t length) -{ - mc->cr->AddCall("reportMetadata"); - original_ICorJitInfo->reportMetadata(key, value, length); -} - -/*-------------------------- Misc ---------------------------------------*/ -// Used to allocate memory that needs to handed to the EE. -// For eg, use this to allocated memory for reporting debug info, -// which will be handed to the EE by setVars() and setBoundaries() -void* interceptor_ICJI::allocateArray(size_t cBytes) -{ - mc->cr->AddCall("allocateArray"); - return original_ICorJitInfo->allocateArray(cBytes); -} - -// JitCompiler will free arrays passed by the EE using this -// For eg, The EE returns memory in getVars() and getBoundaries() -// to the JitCompiler, which the JitCompiler should release using -// freeArray() -void interceptor_ICJI::freeArray(void* array) -{ - mc->cr->AddCall("freeArray"); - original_ICorJitInfo->freeArray(array); -} - -/*********************************************************************************/ -// -// ICorArgInfo -// -/*********************************************************************************/ -// advance the pointer to the argument list. -// a ptr of 0, is special and always means the first argument -CORINFO_ARG_LIST_HANDLE interceptor_ICJI::getArgNext(CORINFO_ARG_LIST_HANDLE args /* IN */ - ) -{ - mc->cr->AddCall("getArgNext"); - CORINFO_ARG_LIST_HANDLE temp = original_ICorJitInfo->getArgNext(args); - mc->recGetArgNext(args, temp); - return temp; -} - -// Get the type of a particular argument -// CORINFO_TYPE_UNDEF is returned when there are no more arguments -// If the type returned is a primitive type (or an enum) *vcTypeRet set to nullptr -// otherwise it is set to the TypeHandle associted with the type -// Enumerations will always look their underlying type (probably should fix this) -// Otherwise vcTypeRet is the type as would be seen by the IL, -// The return value is the type that is used for calling convention purposes -// (Thus if the EE wants a value class to be passed like an int, then it will -// return CORINFO_TYPE_INT -CorInfoTypeWithMod interceptor_ICJI::getArgType(CORINFO_SIG_INFO* sig, /* IN */ - CORINFO_ARG_LIST_HANDLE args, /* IN */ - CORINFO_CLASS_HANDLE* vcTypeRet /* OUT */ - ) -{ - CorInfoTypeWithMod temp = (CorInfoTypeWithMod)CORINFO_TYPE_UNDEF; - - RunWithErrorExceptionCodeCaptureAndContinue( - [&]() - { - mc->cr->AddCall("getArgType"); - temp = - original_ICorJitInfo->getArgType(sig, args, vcTypeRet); - -#ifdef fatMC - CORINFO_CLASS_HANDLE temp3 = getArgClass(sig, args); -#endif - }, - [&](DWORD exceptionCode) - { - this->mc->recGetArgType(sig, args, vcTypeRet, temp, exceptionCode); - }); - - return temp; -} - -int interceptor_ICJI::getExactClasses(CORINFO_CLASS_HANDLE baseType, /* IN */ - int maxExactClasses, /* IN */ - CORINFO_CLASS_HANDLE* exactClsRet) /* OUT */ -{ - mc->cr->AddCall("getExactClasses"); - int result = original_ICorJitInfo->getExactClasses(baseType, maxExactClasses, exactClsRet); - this->mc->recGetExactClasses(baseType, maxExactClasses, exactClsRet, result); - return result; -} - -// If the Arg is a CORINFO_TYPE_CLASS fetch the class handle associated with it -CORINFO_CLASS_HANDLE interceptor_ICJI::getArgClass(CORINFO_SIG_INFO* sig, /* IN */ - CORINFO_ARG_LIST_HANDLE args /* IN */ - ) -{ - CORINFO_CLASS_HANDLE temp = 0; - - RunWithErrorExceptionCodeCaptureAndContinue( - [&]() - { - mc->cr->AddCall("getArgClass"); - temp = original_ICorJitInfo->getArgClass(sig, args); - }, - [&](DWORD exceptionCode) - { - this->mc->recGetArgClass(sig, args, temp, exceptionCode); - }); - - return temp; -} - -// Returns type of HFA for valuetype -CorInfoHFAElemType interceptor_ICJI::getHFAType(CORINFO_CLASS_HANDLE hClass) -{ - mc->cr->AddCall("getHFAType"); - CorInfoHFAElemType temp = original_ICorJitInfo->getHFAType(hClass); - this->mc->recGetHFAType(hClass, temp); - return temp; -} - -/***************************************************************************** - * ICorStaticInfo contains EE interface methods which return values that are - * constant from invocation to invocation. Thus they may be embedded in - * persisted information like statically generated code. (This is of course - * assuming that all code versions are identical each time.) - *****************************************************************************/ -// Return details about EE internal data structures -void interceptor_ICJI::getEEInfo(CORINFO_EE_INFO* pEEInfoOut) -{ - mc->cr->AddCall("getEEInfo"); - original_ICorJitInfo->getEEInfo(pEEInfoOut); - mc->recGetEEInfo(pEEInfoOut); -} - -void interceptor_ICJI::getAsyncInfo(CORINFO_ASYNC_INFO* pAsyncInfo) -{ - mc->cr->AddCall("getAsyncInfo"); - original_ICorJitInfo->getAsyncInfo(pAsyncInfo); - mc->recGetAsyncInfo(pAsyncInfo); -} - -void interceptor_ICJI::getWasmWellKnownGlobals(CORINFO_WASM_WELLKNOWN_GLOBALS* pWellKnownGlobalsOut) -{ - mc->cr->AddCall("getWasmWellKnownGlobals"); - original_ICorJitInfo->getWasmWellKnownGlobals(pWellKnownGlobalsOut); - mc->recGetWasmWellKnownGlobals(pWellKnownGlobalsOut); -} -CORINFO_METHOD_HANDLE interceptor_ICJI::getAwaitReturnCall(CORINFO_METHOD_HANDLE callerHandle, CORINFO_CONTEXT_HANDLE* contextHandle, CORINFO_LOOKUP* instArg) -{ - mc->cr->AddCall("getAwaitReturnCall"); - CORINFO_METHOD_HANDLE result = original_ICorJitInfo->getAwaitReturnCall(callerHandle, contextHandle, instArg); - mc->recGetAwaitReturnCall(callerHandle, contextHandle, instArg, result); - return result; -} - -CORINFO_METHOD_HANDLE interceptor_ICJI::getAwaitAwaiterInContinuationCall( - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_RESOLVED_TOKEN* pResolvedToken, - bool isUnsafe, - CORINFO_CONTEXT_HANDLE* contextHandle, - CORINFO_LOOKUP* instArg) -{ - mc->cr->AddCall("getAwaitAwaiterInContinuationCall"); - CORINFO_METHOD_HANDLE result = original_ICorJitInfo->getAwaitAwaiterInContinuationCall( - callerHandle, pResolvedToken, isUnsafe, contextHandle, instArg); - mc->recGetAwaitAwaiterInContinuationCall(callerHandle, pResolvedToken, isUnsafe, contextHandle, instArg, result); - return result; -} - -/*********************************************************************************/ -// -// Diagnostic methods -// -/*********************************************************************************/ -// this function is for debugging only. Returns method token. -// Returns mdMethodDefNil for dynamic methods. -mdMethodDef interceptor_ICJI::getMethodDefFromMethod(CORINFO_METHOD_HANDLE hMethod) -{ - mc->cr->AddCall("getMethodDefFromMethod"); - mdMethodDef result = original_ICorJitInfo->getMethodDefFromMethod(hMethod); - mc->recGetMethodDefFromMethod(hMethod, result); - return result; -} - -size_t interceptor_ICJI::printMethodName(CORINFO_METHOD_HANDLE ftn, char* buffer, size_t bufferSize, size_t* pRequiredBufferSize) -{ - mc->cr->AddCall("printMethodName"); - size_t temp = original_ICorJitInfo->printMethodName(ftn, buffer, bufferSize, pRequiredBufferSize); - mc->recPrintMethodName(ftn, buffer, bufferSize, pRequiredBufferSize, temp); - return temp; -} - -const char* interceptor_ICJI::getMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftn, /* IN */ - const char** className, /* OUT */ - const char** namespaceName, /* OUT */ - const char** enclosingClassNames, /* OUT */ - size_t maxEnclosingClassNames - ) -{ - mc->cr->AddCall("getMethodNameFromMetadata"); - const char* temp = original_ICorJitInfo->getMethodNameFromMetadata(ftn, className, namespaceName, enclosingClassNames, maxEnclosingClassNames); - mc->recGetMethodNameFromMetadata(ftn, (char*)temp, className, namespaceName, enclosingClassNames, maxEnclosingClassNames); - return temp; -} - -// this function is for debugging only. It returns a value that -// is will always be the same for a given method. It is used -// to implement the 'jitRange' functionality -unsigned interceptor_ICJI::getMethodHash(CORINFO_METHOD_HANDLE ftn /* IN */ - ) -{ - mc->cr->AddCall("getMethodHash"); - unsigned temp = original_ICorJitInfo->getMethodHash(ftn); - mc->recGetMethodHash(ftn, temp); - return temp; -} - -bool interceptor_ICJI::getSystemVAmd64PassStructInRegisterDescriptor( - /* IN */ CORINFO_CLASS_HANDLE structHnd, - /* OUT */ SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr) -{ - mc->cr->AddCall("getSystemVAmd64PassStructInRegisterDescriptor"); - bool result = - original_ICorJitInfo->getSystemVAmd64PassStructInRegisterDescriptor(structHnd, structPassInRegDescPtr); - mc->recGetSystemVAmd64PassStructInRegisterDescriptor(structHnd, structPassInRegDescPtr, result); - return result; -} - -void interceptor_ICJI::getSwiftLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_SWIFT_LOWERING* pLowering) -{ - mc->cr->AddCall("getSwiftLowering"); - original_ICorJitInfo->getSwiftLowering(structHnd, pLowering); - mc->recGetSwiftLowering(structHnd, pLowering); -} - -void interceptor_ICJI::getFpStructLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_FPSTRUCT_LOWERING* pLowering) -{ - mc->cr->AddCall("getFpStructLowering"); - original_ICorJitInfo->getFpStructLowering(structHnd, pLowering); - mc->recGetFpStructLowering(structHnd, pLowering); -} - -CorInfoWasmType interceptor_ICJI::getWasmLowering(CORINFO_CLASS_HANDLE structHnd) -{ - mc->cr->AddCall("getWasmLowering"); - CorInfoWasmType result = original_ICorJitInfo->getWasmLowering(structHnd); - mc->recGetWasmLowering(structHnd, result); - return result; -} - -// Stuff on ICorDynamicInfo -uint32_t interceptor_ICJI::getThreadTLSIndex(void** ppIndirection) -{ - mc->cr->AddCall("getThreadTLSIndex"); - uint32_t temp = original_ICorJitInfo->getThreadTLSIndex(ppIndirection); - mc->recGetThreadTLSIndex(ppIndirection, temp); - return temp; -} - -int32_t* interceptor_ICJI::getAddrOfCaptureThreadGlobal(void** ppIndirection) -{ - mc->cr->AddCall("getAddrOfCaptureThreadGlobal"); - int32_t* temp = original_ICorJitInfo->getAddrOfCaptureThreadGlobal(ppIndirection); - mc->recGetAddrOfCaptureThreadGlobal(ppIndirection, temp); - return temp; -} - -// return the native entry point to an EE helper (see CorInfoHelpFunc) -void interceptor_ICJI::getHelperFtn(CorInfoHelpFunc ftnNum, CORINFO_CONST_LOOKUP *pNativeEntrypoint, CORINFO_METHOD_HANDLE *methodHandle) -{ - mc->cr->AddCall("getHelperFtn"); - CORINFO_CONST_LOOKUP localNativeEntrypoint; - CORINFO_METHOD_HANDLE localMethodHandle; - original_ICorJitInfo->getHelperFtn(ftnNum, &localNativeEntrypoint, &localMethodHandle); - mc->recGetHelperFtn(ftnNum, localNativeEntrypoint, localMethodHandle); - if (pNativeEntrypoint != nullptr) - { - *pNativeEntrypoint = localNativeEntrypoint; - } - if (methodHandle != nullptr) - { - *methodHandle = localMethodHandle; - } -} - -// return a callable address of the function (native code). This function -// may return a different value (depending on whether the method has -// been JITed or not. -void interceptor_ICJI::getFunctionEntryPoint(CORINFO_METHOD_HANDLE ftn, /* IN */ - CORINFO_CONST_LOOKUP* pResult, /* OUT */ - CORINFO_ACCESS_FLAGS accessFlags) -{ - mc->cr->AddCall("getFunctionEntryPoint"); - original_ICorJitInfo->getFunctionEntryPoint(ftn, pResult, accessFlags); - mc->recGetFunctionEntryPoint(ftn, pResult, accessFlags); -} - -// return a directly callable address. This can be used similarly to the -// value returned by getFunctionEntryPoint() except that it is -// guaranteed to be multi callable entrypoint. -void interceptor_ICJI::getFunctionFixedEntryPoint( - CORINFO_METHOD_HANDLE ftn, - bool isUnsafeFunctionPointer, - CORINFO_CONST_LOOKUP* pResult) -{ - mc->cr->AddCall("getFunctionFixedEntryPoint"); - original_ICorJitInfo->getFunctionFixedEntryPoint(ftn, isUnsafeFunctionPointer, pResult); - mc->recGetFunctionFixedEntryPoint(ftn, pResult); -} - -// These entry points must be called if a handle is being embedded in -// the code to be passed to a JIT helper function. (as opposed to just -// being passed back into the ICorInfo interface.) - -CORINFO_MODULE_HANDLE interceptor_ICJI::embedModuleHandle(CORINFO_MODULE_HANDLE handle, void** ppIndirection) -{ - mc->cr->AddCall("embedModuleHandle"); - CORINFO_MODULE_HANDLE temp = original_ICorJitInfo->embedModuleHandle(handle, ppIndirection); - mc->recEmbedModuleHandle(handle, ppIndirection, temp); - return temp; -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::embedClassHandle(CORINFO_CLASS_HANDLE handle, void** ppIndirection) -{ - mc->cr->AddCall("embedClassHandle"); - CORINFO_CLASS_HANDLE temp = original_ICorJitInfo->embedClassHandle(handle, ppIndirection); - mc->recEmbedClassHandle(handle, ppIndirection, temp); - return temp; -} - -CORINFO_METHOD_HANDLE interceptor_ICJI::embedMethodHandle(CORINFO_METHOD_HANDLE handle, void** ppIndirection) -{ - mc->cr->AddCall("embedMethodHandle"); - CORINFO_METHOD_HANDLE temp = original_ICorJitInfo->embedMethodHandle(handle, ppIndirection); - mc->recEmbedMethodHandle(handle, ppIndirection, temp); - return temp; -} - -CORINFO_FIELD_HANDLE interceptor_ICJI::embedFieldHandle(CORINFO_FIELD_HANDLE handle, void** ppIndirection) -{ - mc->cr->AddCall("embedFieldHandle"); - CORINFO_FIELD_HANDLE temp = original_ICorJitInfo->embedFieldHandle(handle, ppIndirection); - mc->recEmbedFieldHandle(handle, ppIndirection, temp); - return temp; -} - -// Given a module scope (module), a method handle (context) and -// a metadata token (metaTOK), fetch the handle -// (type, field or method) associated with the token. -// If this is not possible at compile-time (because the current method's -// code is shared and the token contains generic parameters) -// then indicate how the handle should be looked up at run-time. -// -void interceptor_ICJI::embedGenericHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken, - bool fEmbedParent, // TRUE - embeds parent type handle of the field/method - // handle - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_GENERICHANDLE_RESULT* pResult) -{ - mc->cr->AddCall("embedGenericHandle"); - original_ICorJitInfo->embedGenericHandle(pResolvedToken, fEmbedParent, callerHandle, pResult); - mc->recEmbedGenericHandle(pResolvedToken, fEmbedParent, callerHandle, pResult); -} - -// Return information used to locate the exact enclosing type of the current method. -// Used only to invoke .cctor method from code shared across generic instantiations -// !needsRuntimeLookup statically known (enclosing type of method itself) -// needsRuntimeLookup: -// CORINFO_LOOKUP_THISOBJ use vtable pointer of 'this' param -// CORINFO_LOOKUP_CLASSPARAM use vtable hidden param -// CORINFO_LOOKUP_METHODPARAM use enclosing type of method-desc hidden param -void interceptor_ICJI::getLocationOfThisType(CORINFO_METHOD_HANDLE context, CORINFO_LOOKUP_KIND* pLookupKind) -{ - mc->cr->AddCall("getLocationOfThisType"); - original_ICorJitInfo->getLocationOfThisType(context, pLookupKind); - mc->recGetLocationOfThisType(context, pLookupKind); -} - -// return address of fixup area for late-bound PInvoke calls. -void interceptor_ICJI::getAddressOfPInvokeTarget(CORINFO_METHOD_HANDLE method, CORINFO_CONST_LOOKUP* pLookup) -{ - mc->cr->AddCall("getAddressOfPInvokeTarget"); - original_ICorJitInfo->getAddressOfPInvokeTarget(method, pLookup); - mc->recGetAddressOfPInvokeTarget(method, pLookup); -} - -// Generate a cookie based on the signature to pass to INTOP_CALLI -LPVOID interceptor_ICJI::GetCookieForInterpreterCalliSig(CORINFO_SIG_INFO* szMetaSig) -{ - mc->cr->AddCall("GetCookieForInterpreterCalliSig"); - LPVOID temp = original_ICorJitInfo->GetCookieForInterpreterCalliSig(szMetaSig); - mc->recGetCookieForInterpreterCalliSig(szMetaSig, temp); - return temp; -} - -// Gets a handle that is checked to see if the current method is -// included in "JustMyCode" -CORINFO_JUST_MY_CODE_HANDLE interceptor_ICJI::getJustMyCodeHandle(CORINFO_METHOD_HANDLE method, - CORINFO_JUST_MY_CODE_HANDLE** ppIndirection) -{ - mc->cr->AddCall("getJustMyCodeHandle"); - CORINFO_JUST_MY_CODE_HANDLE temp = original_ICorJitInfo->getJustMyCodeHandle(method, ppIndirection); - mc->recGetJustMyCodeHandle(method, ppIndirection, temp); - return temp; -} - -// Gets a method handle that can be used to correlate profiling data. -// This is the IP of a native method, or the address of the descriptor struct -// for IL. Always guaranteed to be unique per process, and not to move. */ -void interceptor_ICJI::GetProfilingHandle(bool* pbHookFunction, void** pProfilerHandle, bool* pbIndirectedHandles) -{ - mc->cr->AddCall("GetProfilingHandle"); - original_ICorJitInfo->GetProfilingHandle(pbHookFunction, pProfilerHandle, pbIndirectedHandles); - mc->recGetProfilingHandle(pbHookFunction, pProfilerHandle, pbIndirectedHandles); -} - -// Returns instructions on how to make the call. See code:CORINFO_CALL_INFO for possible return values. -void interceptor_ICJI::getCallInfo( - // Token info - CORINFO_RESOLVED_TOKEN* pResolvedToken, - // Generics info - CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, - // Security info - CORINFO_METHOD_HANDLE callerHandle, - // Jit info - CORINFO_CALLINFO_FLAGS flags, - // out params - CORINFO_CALL_INFO* pResult) -{ - RunWithErrorExceptionCodeCaptureAndContinue( - [&]() - { - mc->cr->AddCall("getCallInfo"); - original_ICorJitInfo->getCallInfo(pResolvedToken, pConstrainedResolvedToken, - callerHandle, flags, pResult); - }, - [&](DWORD exceptionCode) - { - mc->recGetCallInfo(pResolvedToken, pConstrainedResolvedToken, callerHandle, flags, pResult, - exceptionCode); - }); -} - -void* interceptor_ICJI::getClassStaticDynamicInfo(CORINFO_CLASS_HANDLE cls) -{ - mc->cr->AddCall("getClassStaticDynamicInfo"); - void* temp = original_ICorJitInfo->getClassStaticDynamicInfo(cls); - mc->recGetClassStaticDynamicInfo(cls, temp); - return temp; -} - -void* interceptor_ICJI::getClassThreadStaticDynamicInfo(CORINFO_CLASS_HANDLE cls) -{ - mc->cr->AddCall("getClassThreadStaticDynamicInfo"); - void* temp = original_ICorJitInfo->getClassThreadStaticDynamicInfo(cls); - mc->recGetClassThreadStaticDynamicInfo(cls, temp); - return temp; -} - -bool interceptor_ICJI::getStaticFieldContent(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects) -{ - mc->cr->AddCall("getStaticFieldContent"); - bool result = original_ICorJitInfo->getStaticFieldContent(field, buffer, bufferSize, valueOffset, ignoreMovableObjects); - mc->recGetStaticFieldContent(field, buffer, bufferSize, valueOffset, ignoreMovableObjects, result); - return result; -} - -bool interceptor_ICJI::getObjectContent(CORINFO_OBJECT_HANDLE obj, uint8_t* buffer, int bufferSize, int valueOffset) -{ - mc->cr->AddCall("getObjectContent"); - bool result = original_ICorJitInfo->getObjectContent(obj, buffer, bufferSize, valueOffset); - mc->recGetObjectContent(obj, buffer, bufferSize, valueOffset, result); - return result; -} - -// return the class handle for the current value of a static field -CORINFO_CLASS_HANDLE interceptor_ICJI::getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE field, bool* pIsSpeculative) -{ - mc->cr->AddCall("getStaticFieldCurrentClass"); - CORINFO_CLASS_HANDLE result = original_ICorJitInfo->getStaticFieldCurrentClass(field, pIsSpeculative); - mc->recGetStaticFieldCurrentClass(field, pIsSpeculative, result); - return result; -} - -// registers a vararg sig & returns a VM cookie for it (which can contain other stuff) -CORINFO_VARARGS_HANDLE interceptor_ICJI::getVarArgsHandle(CORINFO_SIG_INFO* pSig, CORINFO_METHOD_HANDLE methHnd, void** ppIndirection) -{ - mc->cr->AddCall("getVarArgsHandle"); - CORINFO_VARARGS_HANDLE temp = original_ICorJitInfo->getVarArgsHandle(pSig, methHnd, ppIndirection); - mc->recGetVarArgsHandle(pSig, methHnd, ppIndirection, temp); - return temp; -} - -// Allocate a string literal on the heap and return a handle to it -InfoAccessType interceptor_ICJI::constructStringLiteral(CORINFO_MODULE_HANDLE module, mdToken metaTok, void** ppValue) -{ - mc->cr->AddCall("constructStringLiteral"); - InfoAccessType temp = original_ICorJitInfo->constructStringLiteral(module, metaTok, ppValue); - mc->recConstructStringLiteral(module, metaTok, *ppValue, temp); - return temp; -} - -bool interceptor_ICJI::convertPInvokeCalliToCall(CORINFO_RESOLVED_TOKEN* pResolvedToken, bool fMustConvert) -{ - mc->cr->AddCall("convertPInvokeCalliToCall"); - bool result = original_ICorJitInfo->convertPInvokeCalliToCall(pResolvedToken, fMustConvert); - mc->recConvertPInvokeCalliToCall(pResolvedToken, fMustConvert, result); - return result; -} - -InfoAccessType interceptor_ICJI::emptyStringLiteral(void** ppValue) -{ - mc->cr->AddCall("emptyStringLiteral"); - InfoAccessType temp = original_ICorJitInfo->emptyStringLiteral(ppValue); - mc->recEmptyStringLiteral(ppValue, temp); - return temp; -} - -// (static fields only) given that 'field' refers to thread local store, -// return the ID (TLS index), which is used to find the beginning of the -// TLS data area for the particular DLL 'field' is associated with. -uint32_t interceptor_ICJI::getFieldThreadLocalStoreID(CORINFO_FIELD_HANDLE field, void** ppIndirection) -{ - mc->cr->AddCall("getFieldThreadLocalStoreID"); - uint32_t temp = original_ICorJitInfo->getFieldThreadLocalStoreID(field, ppIndirection); - mc->recGetFieldThreadLocalStoreID(field, ppIndirection, temp); - return temp; -} - -CORINFO_METHOD_HANDLE interceptor_ICJI::GetDelegateCtor(CORINFO_METHOD_HANDLE methHnd, - CORINFO_CLASS_HANDLE clsHnd, - CORINFO_METHOD_HANDLE targetMethodHnd, - DelegateCtorArgs* pCtorData) -{ - mc->cr->AddCall("GetDelegateCtor"); - CORINFO_METHOD_HANDLE temp = original_ICorJitInfo->GetDelegateCtor(methHnd, clsHnd, targetMethodHnd, pCtorData); - mc->recGetDelegateCtor(methHnd, clsHnd, targetMethodHnd, pCtorData, temp); - return temp; -} - -void interceptor_ICJI::MethodCompileComplete(CORINFO_METHOD_HANDLE methHnd) -{ - mc->cr->AddCall("MethodCompileComplete"); - original_ICorJitInfo->MethodCompileComplete(methHnd); -} - -bool interceptor_ICJI::getTailCallHelpers( - CORINFO_RESOLVED_TOKEN* callToken, - CORINFO_SIG_INFO* sig, - CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, - CORINFO_TAILCALL_HELPERS* pResult) -{ - mc->cr->AddCall("getTailCallHelpers"); - bool result = original_ICorJitInfo->getTailCallHelpers(callToken, sig, flags, pResult); - if (result) - mc->recGetTailCallHelpers(callToken, sig, flags, pResult); - else - mc->recGetTailCallHelpers(callToken, sig, flags, nullptr); - return result; -} - -CORINFO_METHOD_HANDLE interceptor_ICJI::getAsyncResumptionStub(void** entryPoint) -{ - mc->cr->AddCall("getAsyncResumptionStub"); - CORINFO_METHOD_HANDLE stub = original_ICorJitInfo->getAsyncResumptionStub(entryPoint); - mc->recGetAsyncResumptionStub(stub, *entryPoint); - return stub; -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getContinuationType(size_t dataSize, bool* objRefs, size_t objRefsSize) -{ - mc->cr->AddCall("getContinuationType"); - CORINFO_CLASS_HANDLE result = original_ICorJitInfo->getContinuationType(dataSize, objRefs, objRefsSize); - mc->recGetContinuationType(dataSize, objRefs, objRefsSize, result); - return result; -} - -void interceptor_ICJI::updateEntryPointForTailCall(CORINFO_CONST_LOOKUP* entryPoint) -{ - mc->cr->AddCall("updateEntryPointForTailCall"); - CORINFO_CONST_LOOKUP origEntryPoint = *entryPoint; - original_ICorJitInfo->updateEntryPointForTailCall(entryPoint); - mc->recUpdateEntryPointForTailCall(origEntryPoint, *entryPoint); -} - -// Stuff directly on ICorJitInfo - -// Returns extended flags for a particular compilation instance. -uint32_t interceptor_ICJI::getJitFlags(CORJIT_FLAGS* jitFlags, uint32_t sizeInBytes) -{ - mc->cr->AddCall("getJitFlags"); - uint32_t result = original_ICorJitInfo->getJitFlags(jitFlags, sizeInBytes); - mc->recGetJitFlags(jitFlags, sizeInBytes, result); - return result; -} - -// Runs the given function with the given parameter under an error trap -// and returns true if the function completes successfully. We don't -// record the results of the call: when this call gets played back, -// its result will depend on whether or not `function` calls something -// that throws at playback time rather than at capture time. -bool interceptor_ICJI::runWithErrorTrap(void (*function)(void*), void* param) -{ - mc->cr->AddCall("runWithErrorTrap"); - return original_ICorJitInfo->runWithErrorTrap(function, param); -} - -// Runs the given function with the given parameter under an error trap -// and returns true if the function completes successfully. We don't -// record the results of the call: when this call gets played back, -// its result will depend on whether or not `function` calls something -// that throws at playback time rather than at capture time. -bool interceptor_ICJI::runWithSPMIErrorTrap(void (*function)(void*), void* param) -{ - return RunWithSPMIErrorTrap(function, param); -} - -// get a block of memory for the code, readonly data, and read-write data -void interceptor_ICJI::allocMem(AllocMemArgs *pArgs) -{ - mc->cr->AddCall("allocMem"); - original_ICorJitInfo->allocMem(pArgs); -} - -// Reserve memory for the method/funclet's unwind information. -// Note that this must be called before allocMem. It should be -// called once for the main method, once for every funclet, and -// once for every block of cold code for which allocUnwindInfo -// will be called. -// -// This is necessary because jitted code must allocate all the -// memory needed for the unwindInfo at the allocMem call. -// For prejitted code we split up the unwinding information into -// separate sections .rdata and .pdata. -// -void interceptor_ICJI::reserveUnwindInfo(bool isFunclet, /* IN */ - bool isColdCode, /* IN */ - uint32_t unwindSize /* IN */ - ) -{ - mc->cr->AddCall("reserveUnwindInfo"); - original_ICorJitInfo->reserveUnwindInfo(isFunclet, isColdCode, unwindSize); - mc->cr->recReserveUnwindInfo(isFunclet, isColdCode, unwindSize); -} - -// Allocate and initialize the .rdata and .pdata for this method or -// funclet, and get the block of memory needed for the machine-specific -// unwind information (the info for crawling the stack frame). -// Note that allocMem must be called first. -// -// Parameters: -// -// pHotCode main method code buffer, always filled in -// pColdCode cold code buffer, only filled in if this is cold code, -// null otherwise -// startOffset start of code block, relative to appropriate code buffer -// (e.g. pColdCode if cold, pHotCode if hot). -// endOffset end of code block, relative to appropriate code buffer -// unwindSize size of unwind info pointed to by pUnwindBlock -// pUnwindBlock pointer to unwind info -// funcKind type of funclet (main method code, handler, filter) -// -void interceptor_ICJI::allocUnwindInfo(uint8_t* pHotCode, /* IN */ - uint8_t* pColdCode, /* IN */ - uint32_t startOffset, /* IN */ - uint32_t endOffset, /* IN */ - uint32_t unwindSize, /* IN */ - uint8_t* pUnwindBlock, /* IN */ - CorJitFuncKind funcKind /* IN */ - ) -{ - mc->cr->AddCall("allocUnwindInfo"); - original_ICorJitInfo->allocUnwindInfo(pHotCode, pColdCode, startOffset, endOffset, unwindSize, pUnwindBlock, - funcKind); - mc->cr->recAllocUnwindInfo(pHotCode, pColdCode, startOffset, endOffset, unwindSize, pUnwindBlock, funcKind); -} - -// Get a block of memory needed for the code manager information, -// (the info for enumerating the GC pointers while crawling the -// stack frame). -// Note that allocMem must be called first -void* interceptor_ICJI::allocGCInfo(size_t size /* IN */) -{ - mc->cr->AddCall("allocGCInfo"); - void* temp = original_ICorJitInfo->allocGCInfo(size); - mc->cr->recAllocGCInfo(size, temp); - return temp; -} - -// Indicate how many exception handler blocks are to be returned. -// This is guaranteed to be called before any 'setEHinfo' call. -// Note that allocMem must be called before this method can be called. -void interceptor_ICJI::setEHcount(unsigned cEH /* IN */) -{ - mc->cr->AddCall("setEHcount"); - original_ICorJitInfo->setEHcount(cEH); - mc->cr->recSetEHcount(cEH); -} - -// Set the values for one particular exception handler block. -// Handler regions should be lexically contiguous. -// This is because FinallyIsUnwinding() uses lexicality to -// determine if a "finally" clause is executing. -void interceptor_ICJI::setEHinfo(unsigned EHnumber, /* IN */ - const CORINFO_EH_CLAUSE* clause /* IN */ - ) -{ - mc->cr->AddCall("setEHinfo"); - original_ICorJitInfo->setEHinfo(EHnumber, clause); - mc->cr->recSetEHinfo(EHnumber, clause); -} - -// Level 1 -> fatalError, Level 2 -> Error, Level 3 -> Warning -// Level 4 means happens 10 times in a run, level 5 means 100, level 6 means 1000 ... -// returns non-zero if the logging succeeded -bool interceptor_ICJI::logMsg(unsigned level, const char* fmt, va_list args) -{ - mc->cr->AddCall("logMsg"); - return original_ICorJitInfo->logMsg(level, fmt, args); -} - -// do an assert. will return true if the code should retry (DebugBreak) -// returns false, if the assert should be ignored. -int interceptor_ICJI::doAssert(const char* szFile, int iLine, const char* szExpr) -{ - mc->cr->AddCall("doAssert"); - - m_compiler->finalizeAndCommitCollection(mc, CORJIT_INTERNALERROR, nullptr, 0); - // The following assert may not always fail fast, so make sure we do not - // save the collection twice if it throws an unwindable exception. - m_savedCollectionEarly = true; - - return original_ICorJitInfo->doAssert(szFile, iLine, szExpr); -} - -void interceptor_ICJI::reportFatalError(CorJitResult result) -{ - mc->cr->AddCall("reportFatalError"); - original_ICorJitInfo->reportFatalError(result); - mc->cr->recReportFatalError(result); -} - -// allocate a basic block profile buffer where execution counts will be stored -// for jitted basic blocks. -HRESULT interceptor_ICJI::allocPgoInstrumentationBySchema(CORINFO_METHOD_HANDLE ftnHnd, - PgoInstrumentationSchema* pSchema, - uint32_t countSchemaItems, - uint8_t** pInstrumentationData) -{ - mc->cr->AddCall("allocPgoInstrumentationBySchema"); - HRESULT result = original_ICorJitInfo->allocPgoInstrumentationBySchema(ftnHnd, pSchema, countSchemaItems, pInstrumentationData); - mc->recAllocPgoInstrumentationBySchema(ftnHnd, pSchema, countSchemaItems, pInstrumentationData, result); - return result; -} - -// get profile information to be used for optimizing the current method. The format -// of the buffer is the same as the format the JIT passes to allocMethodBlockCounts. -HRESULT interceptor_ICJI::getPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftnHnd, - PgoInstrumentationSchema **pSchema, // pointer to the schema table which describes the instrumentation results (pointer will not remain valid after jit completes) - uint32_t * pCountSchemaItems, // pointer to the count schema items - uint8_t ** pInstrumentationData, // pointer to the actual instrumentation data (pointer will not remain valid after jit completes) - PgoSource* pPgoSource, - bool* pDynamicPgo) -{ - mc->cr->AddCall("getPgoInstrumentationResults"); - HRESULT temp = original_ICorJitInfo->getPgoInstrumentationResults(ftnHnd, pSchema, pCountSchemaItems, pInstrumentationData, pPgoSource, pDynamicPgo); - mc->recGetPgoInstrumentationResults(ftnHnd, pSchema, pCountSchemaItems, pInstrumentationData, pPgoSource, pDynamicPgo, temp); - return temp; -} - -// Associates a native call site, identified by its offset in the native code stream, with -// the signature information and method handle the JIT used to lay out the call site. If -// the call site has no signature information (e.g. a helper call) or has no method handle -// (e.g. a CALLI P/Invoke), then null should be passed instead. -void interceptor_ICJI::recordCallSite(uint32_t instrOffset, /* IN */ - CORINFO_SIG_INFO* callSig, /* IN */ - CORINFO_METHOD_HANDLE methodHandle /* IN */ - ) -{ - mc->cr->AddCall("recordCallSite"); - original_ICorJitInfo->recordCallSite(instrOffset, callSig, methodHandle); - mc->cr->recRecordCallSite(instrOffset, callSig, methodHandle); -} - -void interceptor_ICJI::recordWasmManagedCallSig(CORINFO_SIG_INFO* callSig /* IN */) -{ - mc->cr->AddCall("recordWasmManagedCallSig"); - original_ICorJitInfo->recordWasmManagedCallSig(callSig); - // No-op in the VM, nothing to record for replay. -} - -// A relocation is recorded if we are pre-jitting. -// A jump thunk may be inserted if we are jitting -void interceptor_ICJI::recordRelocation(void* location, /* IN */ - void* locationRW, /* IN */ - void* target, /* IN */ - CorInfoReloc fRelocType, /* IN */ - int32_t addlDelta /* IN */ - ) -{ - mc->cr->AddCall("recordRelocation"); - original_ICorJitInfo->recordRelocation(location, locationRW, target, fRelocType, addlDelta); - mc->cr->recRecordRelocation(location, target, fRelocType, addlDelta); -} - -CorInfoReloc interceptor_ICJI::getRelocTypeHint(void* target) -{ - mc->cr->AddCall("getRelocTypeHint"); - CorInfoReloc result = original_ICorJitInfo->getRelocTypeHint(target); - mc->recGetRelocTypeHint(target, result); - return result; -} - -uint32_t interceptor_ICJI::getAddressAlignment(void* address) -{ - mc->cr->AddCall("getAddressAlignment"); - uint32_t result = original_ICorJitInfo->getAddressAlignment(address); - mc->recGetAddressAlignment(address, result); - return result; -} - -// For what machine does the VM expect the JIT to generate code? The VM -// returns one of the IMAGE_FILE_MACHINE_* values. Note that if the VM -// is cross-compiling (such as the case for crossgen2), it will return a -// different value than if it was compiling for the host architecture. -// -uint32_t interceptor_ICJI::getExpectedTargetArchitecture() -{ - mc->cr->AddCall("getExpectedTargetArchitecture"); - DWORD result = original_ICorJitInfo->getExpectedTargetArchitecture(); - mc->recGetExpectedTargetArchitecture(result); - return result; -} - -CORINFO_WASM_TYPE_SYMBOL_HANDLE interceptor_ICJI::getWasmTypeSymbol(CorInfoWasmType* types, size_t typesSize) -{ - mc->cr->AddCall("getWasmTypeSymbol"); - CORINFO_WASM_TYPE_SYMBOL_HANDLE temp = original_ICorJitInfo->getWasmTypeSymbol(types, typesSize); - mc->recGetWasmTypeSymbol(types, typesSize, temp); - return temp; -} - -CORINFO_METHOD_HANDLE interceptor_ICJI::getSpecialCopyHelper(CORINFO_CLASS_HANDLE type) -{ - mc->cr->AddCall("getSpecialCopyHelper"); - CORINFO_METHOD_HANDLE temp = original_ICorJitInfo->getSpecialCopyHelper(type); - mc->recGetSpecialCopyHelper(type, temp); - return temp; -} diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.h b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.h deleted file mode 100644 index 50733bea64b752..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.h +++ /dev/null @@ -1,35 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#ifndef _ICorJitInfo -#define _ICorJitInfo - -#include "runtimedetails.h" -#include "methodcontext.h" - -class interceptor_ICJC; - -class interceptor_ICJI : public ICorJitInfo -{ - -#include "icorjitinfoimpl.h" - -private: - interceptor_ICJC* m_compiler; - ICorJitInfo* original_ICorJitInfo; - MethodContext* mc; - bool m_savedCollectionEarly; - -public: - interceptor_ICJI(interceptor_ICJC* compiler, ICorJitInfo* original, MethodContext* mc) - : m_compiler(compiler) - , original_ICorJitInfo(original) - , mc(mc) - , m_savedCollectionEarly(false) - { - } - - bool SavedCollectionEarly() const { return m_savedCollectionEarly; } -}; - -#endif diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/jithost.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/jithost.cpp deleted file mode 100644 index 3bb1c6c69a142d..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/jithost.cpp +++ /dev/null @@ -1,159 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "standardpch.h" -#include "runtimedetails.h" -#include "spmiutil.h" -#include "jithost.h" - -// There is a single JitHost object created during the one-time initialization of the JIT (function jitStartup), -// and shared amongst all subsequent compilations. Any calls to the getIntConfigValue/getStringConfigValue -// APIs get recorded in a single, global MethodContext/CompileResult, and are copied to the -// per-compilation MethodContext in the shim implementation of compileMethod (using recGlobalContext()). -// This works because the JIT eagerly asks for all config values once, in the one-time jitStartup -// function. If the JIT were to ask for config values later, during the per-compilation phase, -// they would get recorded here in the global MethodContext, and copied to all subsequent -// compilation MethodContexts. This would be incorrect. A solution would be to use a per-compilation -// MethodContext in addition to the global MethodContext, but we have to allow for multi-threading. That is, -// there could be multiple JIT compilations happening concurrently, so we can't just replace the global -// MethodContext with a per-compilation MethodContext. Perhaps per-compilation MethodContext could be -// stored in a map from OS thread id to MethodContext, and looked up here based on thread id. The host APIs -// have no per-compilation knowledge. - -JitHost* g_ourJitHost; - -// RecordVariable: return `true` if the given DOTNET variable `key` should be recorded -// in the method context. -bool RecordVariable(const char* key) -{ - // Special cases: we don't want to store some DOTNET variables during - // collections, typically when they refer to file paths or simply because - // it does not make sense to replay with it. - - static const char* s_ignoredVars[] = { - "EnableExtraSuperPmiQueries", - "JitDisasm", - "JitDump", - "JitDisasmWithAlignmentBoundaries", - "JitDumpASCII", - "JitHashBreak", - "JitHashDump", - "JitHashHalt", - "JitOrder", - "JitPrintInlinedMethods", - "JitPrintDevirtualizedMethods", - "JitBreak", - "JitDebugBreak", - "JitDisasmAssemblies", - "JitDisasmWithGC", - "JitDisasmWithDebugInfo", - "JitDisasmSpilled", - "JitDumpTier0", - "JitDumpAtOSROffset", - "JitDumpInlinePhases", - "JitEHDump", - "JitExclude", - "JitGCDump", - "JitDebugDump", - "JitHalt", - "JitImportBreak", - "JitInclude", - "JitLateDisasm", - "JitUnwindDump", - "JitDumpFg", - "JitDumpFgDir", - "JitDumpFgPhase", - "JitDumpFgPrePhase", - "JitDumpFgDot", - "JitDumpFgEH", - "JitDumpFgLoops", - "JitDumpFgConstrained", - "JitDumpFgBlockID", - "JitDumpFgBlockFlags", - "JitDumpFgLoopFlags", - "JitDumpFgBlockOrder", - "JITLateDisasmTo", - "JitDisasmSummary", - "JitStdOutFile", - "WriteRichDebugInfoFile", - "JitFuncInfoLogFile", - "JitTimeLogCsv", - "JitMeasureNowayAssertFile", - "JitInlineDumpData", - "JitInlineDumpXml", - "JitInlineDumpXmlFile", - "JitInlinePolicyDumpXml", - "JitInlineReplayFile", - "JitFunctionFile" - "JitRawHexCode", - "JitRawHexCodeFile" - }; - - for (const char* ignoredVar : s_ignoredVars) - { - if (_stricmp(key, ignoredVar) == 0) - { - return false; - } - } - - return true; -} - -JitHost::JitHost(ICorJitHost* wrappedHost, MethodContext* methodContext) : wrappedHost(wrappedHost), mc(methodContext) -{ -} - -void* JitHost::allocateMemory(size_t size) -{ - return wrappedHost->allocateMemory(size); -} - -void JitHost::freeMemory(void* block) -{ - return wrappedHost->freeMemory(block); -} - -int JitHost::getIntConfigValue(const char* key, int defaultValue) -{ - // Special-case handling: don't collect this pseudo-variable, and don't - // even record that it was called (since it would get recorded into the - // global state). (See the superpmi.exe tool implementation of JitHost::getIntConfigValue() - // for the special-case implementation of this.) - if (strcmp(key, "SuperPMIMethodContextNumber") == 0 || - strcmp(key, "JitReportMetrics") == 0) - { - return defaultValue; - } - - mc->cr->AddCall("getIntConfigValue"); - int result = wrappedHost->getIntConfigValue(key, defaultValue); - - // The JIT eagerly asks about every config value. If we store all these - // queries, it takes almost half the MC file space. So only store the - // non-default answers. - if (RecordVariable(key) && (result != defaultValue)) - { - mc->recGetIntConfigValue(key, defaultValue, result); - } - return result; -} - -const char* JitHost::getStringConfigValue(const char* key) -{ - mc->cr->AddCall("getStringConfigValue"); - const char* result = wrappedHost->getStringConfigValue(key); - - // Don't store null returns, which is the default - if (RecordVariable(key) && (result != nullptr)) - { - mc->recGetStringConfigValue(key, result); - } - return result; -} - -void JitHost::freeStringConfigValue(const char* value) -{ - mc->cr->AddCall("freeStringConfigValue"); - wrappedHost->freeStringConfigValue(value); -} diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/jithost.h b/src/coreclr/tools/superpmi/superpmi-shim-collector/jithost.h deleted file mode 100644 index a282f409600416..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/jithost.h +++ /dev/null @@ -1,21 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#ifndef _JITHOST -#define _JITHOST - -class JitHost : public ICorJitHost -{ -public: - JitHost(ICorJitHost* wrappedHost, MethodContext* methodContext); - -#include "icorjithostimpl.h" - -private: - ICorJitHost* wrappedHost; - MethodContext* mc; -}; - -extern JitHost* g_ourJitHost; - -#endif diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/superpmi-shim-collector.PAL.exports b/src/coreclr/tools/superpmi/superpmi-shim-collector/superpmi-shim-collector.PAL.exports deleted file mode 100644 index 11e42d3bb11aea..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/superpmi-shim-collector.PAL.exports +++ /dev/null @@ -1,2 +0,0 @@ -getJit -jitStartup diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/superpmi-shim-collector.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/superpmi-shim-collector.cpp deleted file mode 100644 index f3ff4af0e6f9db..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/superpmi-shim-collector.cpp +++ /dev/null @@ -1,226 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// SuperPMI-Shim-Collector.cpp - Shim that collects and yields .mc (method context) files. -//---------------------------------------------------------- - -#include "standardpch.h" -#include "icorjitcompiler.h" -#include "runtimedetails.h" -#include "errorhandling.h" -#include "logging.h" -#include "spmiutil.h" -#include "jithost.h" - -// Assumptions: -// -We'll never be unloaded - we leak memory and have no facility to unload libraries -// -printf output to console is okay - -HMODULE g_hRealJit = 0; // We leak this currently (could do the proper shutdown in process_detach) -std::string g_realJitPath{""}; // Destructable objects will be cleaned up and won't leak -std::string g_logPath{""}; -std::string g_HomeDirectory{""}; -std::string g_DefaultRealJitPath{""}; -std::string g_dataFileName{""}; -MethodContext* g_globalContext = nullptr; -bool g_initialized = false; -char* g_collectionFilter = nullptr; - -// RAII holder for logger -// Global deconstructors are unreliable. We only use it for superpmi shim. -class LoggerHolder -{ -public: - LoggerHolder() - { - Logger::Initialize(); - // If the environment variable isn't set, we don't enable file logging - const char* logFilePath = GetEnvWithDefault("SuperPMIShimLogFilePath", nullptr); - if (logFilePath) - { - Logger::OpenLogFile(logFilePath); - } - } - - ~LoggerHolder() - { - Logger::Shutdown(); - } -} loggerHolder; - -void SetDefaultPaths() -{ - if (g_HomeDirectory.empty()) - { - g_HomeDirectory = GetEnvWithDefault("HOME", "."); - } - - if (g_DefaultRealJitPath.empty()) - { - g_DefaultRealJitPath = g_HomeDirectory + DIRECTORY_SEPARATOR_CHAR_A + DEFAULT_REAL_JIT_NAME_A; - } -} - -void SetLibName() -{ - if (g_realJitPath.empty()) - { - g_realJitPath = GetEnvWithDefault("SuperPMIShimPath", g_DefaultRealJitPath.c_str()); - } -} - -void SetLogPath() -{ - if (g_logPath.empty()) - { - g_logPath = GetEnvWithDefault("SuperPMIShimLogPath", g_HomeDirectory.c_str()); - } -} - -void SetLogPathName() -{ - g_dataFileName = GetResultFileName(g_logPath, GetProcessCommandLine(), ".mc"); -} - -void SetCollectionFilter() -{ - g_collectionFilter = GetEnvironmentVariableWithDefaultA("SuperPMIShimFilter", nullptr); - - if (g_collectionFilter != nullptr) - { - fprintf(stderr, "*** SPMI filter '%s'\n", g_collectionFilter); - } -} - -void InitializeShim() -{ - if (g_initialized) - { - return; - } - -#ifdef HOST_UNIX - // Register signal handlers for the shim so we can handle committing collections on JIT segfaults. - PAL_SetInitializeDLLFlags(PAL_INITIALIZE_REGISTER_SIGNALS); - if (0 != PAL_InitializeDLL()) - { - fprintf(stderr, "Error: Fail to PAL_InitializeDLL\n"); - exit(1); - } -#endif // HOST_UNIX - -#ifdef HOST_WINDOWS - // Assertions will be sent to stderr instead of a pop-up dialog. - _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); - _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); -#endif // HOST_WINDOWS - - g_initialized = true; -} - -extern "C" -#ifdef HOST_UNIX - DLLEXPORT // For Win32 PAL LoadLibrary emulation -#endif - BOOL - DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) -{ - switch (ul_reason_for_call) - { - case DLL_PROCESS_ATTACH: - InitializeShim(); - break; - - case DLL_PROCESS_DETACH: - case DLL_THREAD_ATTACH: - case DLL_THREAD_DETACH: - break; - } - return TRUE; -} - -extern "C" DLLEXPORT void jitStartup(ICorJitHost* host) -{ - // crossgen2 doesn't invoke DllMain on Linux/Mac (under PAL), so optionally do initialization work here. - InitializeShim(); - - SetDefaultPaths(); - SetLibName(); - SetDebugDumpVariables(); - SetCollectionFilter(); - - if (!LoadRealJitLib(g_hRealJit, g_realJitPath)) - { - return; - } - - // Get the required entrypoint - PjitStartup pnjitStartup = (PjitStartup)GET_PROC_ADDRESS(g_hRealJit, "jitStartup"); - if (pnjitStartup == nullptr) - { - // This portion of the interface is not used by the JIT under test. - return; - } - - g_globalContext = new MethodContext(); - g_ourJitHost = new JitHost(host, g_globalContext); - pnjitStartup(g_ourJitHost); -} - -extern "C" DLLEXPORT ICorJitCompiler* getJit() -{ - DWORD dwRetVal = 0; - PgetJit pngetJit; - interceptor_ICJC* pJitInstance = nullptr; - ICorJitCompiler* tICJI = nullptr; - - SetDefaultPaths(); - SetLibName(); - SetLogPath(); - SetLogPathName(); - SetDebugDumpVariables(); - - if (!LoadRealJitLib(g_hRealJit, g_realJitPath)) - { - return nullptr; - } - - // get the required entrypoints - pngetJit = (PgetJit)GET_PROC_ADDRESS(g_hRealJit, "getJit"); - if (pngetJit == 0) - { - LogError("getJit() - GetProcAddress 'getJit' failed (0x%08x)", ::GetLastError()); - return nullptr; - } - - tICJI = pngetJit(); - if (tICJI == nullptr) - { - LogError("getJit() - pngetJit gave us null"); - return nullptr; - } - - pJitInstance = new interceptor_ICJC(); - pJitInstance->original_ICorJitCompiler = tICJI; - -#ifdef TARGET_WINDOWS - pJitInstance->currentOs = CORINFO_WINNT; -#elif defined(TARGET_OSX) - pJitInstance->currentOs = CORINFO_APPLE; -#elif defined(TARGET_UNIX) - pJitInstance->currentOs = CORINFO_UNIX; -#else -#error No target os defined -#endif - - // create our datafile - pJitInstance->hFile = CreateFileA(g_dataFileName.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, - CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); - if (pJitInstance->hFile == INVALID_HANDLE_VALUE) - { - LogError("Couldn't open file '%s': error %d", g_dataFileName.c_str(), GetLastError()); - } - - return pJitInstance; -} diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/superpmi-shim-collector.def b/src/coreclr/tools/superpmi/superpmi-shim-collector/superpmi-shim-collector.def deleted file mode 100644 index f00334b07ef670..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/superpmi-shim-collector.def +++ /dev/null @@ -1,4 +0,0 @@ -LIBRARY -EXPORTS - getJit - jitStartup diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/superpmi-shim-collector.h b/src/coreclr/tools/superpmi/superpmi-shim-collector/superpmi-shim-collector.h deleted file mode 100644 index 6c964db6721fa0..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/superpmi-shim-collector.h +++ /dev/null @@ -1,16 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// SuperPMI-Shim-Collector.h - Shim that collects and yields .mc (method context) files. -//---------------------------------------------------------- -#ifndef _SuperPMIShim -#define _SuperPMIShim - -class MethodContext; -extern MethodContext* g_globalContext; -extern char* g_collectionFilter; - -void DebugBreakorAV(int val); - -#endif diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/CMakeLists.txt b/src/coreclr/tools/superpmi/superpmi-shim-counter/CMakeLists.txt deleted file mode 100644 index 107425a8829743..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/CMakeLists.txt +++ /dev/null @@ -1,69 +0,0 @@ -project(superpmi-shim-counter) - -remove_definitions(-DUNICODE) -remove_definitions(-D_UNICODE) - -add_definitions(-DFEATURE_NO_HOST) -add_definitions(-DSELF_NO_HOST) - -if(CLR_CMAKE_HOST_WIN32) - #use static crt - set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded) -endif(CLR_CMAKE_HOST_WIN32) - -include_directories(.) -include_directories(../superpmi-shared) - -set(SUPERPMI_SHIM_COUNTER_SOURCES - jithost.cpp - icorjitcompiler.cpp - icorjitinfo_generated.cpp - methodcallsummarizer.cpp - superpmi-shim-counter.cpp - ../superpmi-shared/callutils.cpp - ../superpmi-shared/compileresult.cpp - ../superpmi-shared/errorhandling.cpp - ../superpmi-shared/hash.cpp - ../superpmi-shared/logging.cpp - ../superpmi-shared/mclist.cpp - ../superpmi-shared/methodcontext.cpp - ../superpmi-shared/methodcontextreader.cpp - ../superpmi-shared/simpletimer.cpp - ../superpmi-shared/spmiutil.cpp - ../superpmi-shared/tocfile.cpp - ../superpmi-shared/typeutils.cpp - ../superpmi-shared/spmidumphelper.cpp -) - -if (CLR_CMAKE_TARGET_WIN32) - preprocess_file(${CMAKE_CURRENT_SOURCE_DIR}/superpmi-shim-counter.def ${CMAKE_CURRENT_BINARY_DIR}/superpmi-shim-counter.def) - - list(APPEND SUPERPMI_SHIM_COUNTER_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/superpmi-shim-counter.def) -endif (CLR_CMAKE_TARGET_WIN32) - -add_library_clr(superpmi-shim-counter - SHARED - ${SUPERPMI_SHIM_COUNTER_SOURCES} -) - -target_precompile_headers(superpmi-shim-counter PRIVATE "$<$:standardpch.h>") - -if(CLR_CMAKE_HOST_UNIX) - target_link_libraries(superpmi-shim-counter - PRIVATE - utilcodestaticnohost - mscorrc - coreclrpal - coreclrminipal - ) -else() - target_link_libraries(superpmi-shim-counter - PRIVATE - advapi32.lib - coreclrminipal - ${STATIC_MT_CRT_LIB} - ${STATIC_MT_CPP_LIB} - ) -endif(CLR_CMAKE_HOST_UNIX) - -install_clr(TARGETS superpmi-shim-counter DESTINATIONS . COMPONENT spmi) diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitcompiler.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitcompiler.cpp deleted file mode 100644 index f67c5cbf6863bb..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitcompiler.cpp +++ /dev/null @@ -1,42 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "standardpch.h" -#include "icorjitcompiler.h" -#include "icorjitinfo.h" - -void interceptor_ICJC::setTargetOS(CORINFO_OS os) -{ - original_ICorJitCompiler->setTargetOS(os); -} - -CorJitResult interceptor_ICJC::compileMethod(ICorJitInfo* comp, /* IN */ - struct CORINFO_METHOD_INFO* info, /* IN */ - unsigned /* code:CorJitFlag */ flags, /* IN */ - uint8_t** nativeEntry, /* OUT */ - uint32_t* nativeSizeOfCode /* OUT */ - ) -{ - interceptor_ICJI our_ICorJitInfo; - our_ICorJitInfo.original_ICorJitInfo = comp; - - our_ICorJitInfo.mcs = mcs; - - mcs->AddCall("compileMethod"); - CorJitResult temp = - original_ICorJitCompiler->compileMethod(&our_ICorJitInfo, info, flags, nativeEntry, nativeSizeOfCode); - - return temp; -} - -void interceptor_ICJC::ProcessShutdownWork(ICorStaticInfo* info) -{ - mcs->AddCall("ProcessShutdownWork"); - original_ICorJitCompiler->ProcessShutdownWork(info); -} - -void interceptor_ICJC::getVersionIdentifier(GUID* versionIdentifier /* OUT */) -{ - mcs->AddCall("getVersionIdentifier"); - original_ICorJitCompiler->getVersionIdentifier(versionIdentifier); -} diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitcompiler.h b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitcompiler.h deleted file mode 100644 index 6883e72dd8cea6..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitcompiler.h +++ /dev/null @@ -1,21 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#ifndef _ICorJitCompiler -#define _ICorJitCompiler - -#include "runtimedetails.h" -#include "methodcallsummarizer.h" - -class interceptor_ICJC : public ICorJitCompiler -{ - -#include "icorjitcompilerimpl.h" - -public: - // Added to help us track the original icjc and be able to easily indirect to it. - ICorJitCompiler* original_ICorJitCompiler; - MethodCallSummarizer* mcs; -}; - -#endif diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.h b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.h deleted file mode 100644 index 5f365607a2d5fe..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo.h +++ /dev/null @@ -1,22 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#ifndef _ICorJitInfo -#define _ICorJitInfo - -#include "runtimedetails.h" -#include "methodcallsummarizer.h" - -class interceptor_ICJI : public ICorJitInfo -{ - -#include "icorjitinfoimpl.h" - -public: - // Added to help us track the original icji and be able to easily indirect - // to it. And a simple way to keep one memory manager instance per instance. - ICorJitInfo* original_ICorJitInfo; - MethodCallSummarizer* mcs; -}; - -#endif diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp deleted file mode 100644 index 8ad129e00e0893..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp +++ /dev/null @@ -1,1502 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -// DO NOT EDIT THIS FILE! IT IS AUTOGENERATED -// To regenerate run the gen script in src/coreclr/tools/Common/JitInterface/ThunkGenerator -// and follow the instructions in docs/project/updating-jitinterface.md - -#include "standardpch.h" -#include "icorjitinfo.h" -#include "superpmi-shim-counter.h" -#include "icorjitcompiler.h" -#include "spmiutil.h" - - -bool interceptor_ICJI::isIntrinsic( - CORINFO_METHOD_HANDLE ftn) -{ - mcs->AddCall("isIntrinsic"); - return original_ICorJitInfo->isIntrinsic(ftn); -} - -bool interceptor_ICJI::canValueClassInstancePointerEscape( - CORINFO_METHOD_HANDLE ftn) -{ - mcs->AddCall("canValueClassInstancePointerEscape"); - return original_ICorJitInfo->canValueClassInstancePointerEscape(ftn); -} - -bool interceptor_ICJI::notifyMethodInfoUsage( - CORINFO_METHOD_HANDLE ftn) -{ - mcs->AddCall("notifyMethodInfoUsage"); - return original_ICorJitInfo->notifyMethodInfoUsage(ftn); -} - -uint32_t interceptor_ICJI::getMethodAttribs( - CORINFO_METHOD_HANDLE ftn) -{ - mcs->AddCall("getMethodAttribs"); - return original_ICorJitInfo->getMethodAttribs(ftn); -} - -void interceptor_ICJI::setMethodAttribs( - CORINFO_METHOD_HANDLE ftn, - CorInfoMethodRuntimeFlags attribs) -{ - mcs->AddCall("setMethodAttribs"); - original_ICorJitInfo->setMethodAttribs(ftn, attribs); -} - -void interceptor_ICJI::getMethodSig( - CORINFO_METHOD_HANDLE ftn, - CORINFO_SIG_INFO* sig, - CORINFO_CLASS_HANDLE memberParent) -{ - mcs->AddCall("getMethodSig"); - original_ICorJitInfo->getMethodSig(ftn, sig, memberParent); -} - -bool interceptor_ICJI::getMethodInfo( - CORINFO_METHOD_HANDLE ftn, - CORINFO_METHOD_INFO* info, - CORINFO_CONTEXT_HANDLE context) -{ - mcs->AddCall("getMethodInfo"); - return original_ICorJitInfo->getMethodInfo(ftn, info, context); -} - -bool interceptor_ICJI::haveSameMethodDefinition( - CORINFO_METHOD_HANDLE meth1Hnd, - CORINFO_METHOD_HANDLE meth2Hnd) -{ - mcs->AddCall("haveSameMethodDefinition"); - return original_ICorJitInfo->haveSameMethodDefinition(meth1Hnd, meth2Hnd); -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getTypeDefinition( - CORINFO_CLASS_HANDLE type) -{ - mcs->AddCall("getTypeDefinition"); - return original_ICorJitInfo->getTypeDefinition(type); -} - -CorInfoInline interceptor_ICJI::canInline( - CORINFO_METHOD_HANDLE callerHnd, - CORINFO_METHOD_HANDLE calleeHnd) -{ - mcs->AddCall("canInline"); - return original_ICorJitInfo->canInline(callerHnd, calleeHnd); -} - -void interceptor_ICJI::beginInlining( - CORINFO_METHOD_HANDLE inlinerHnd, - CORINFO_METHOD_HANDLE inlineeHnd) -{ - mcs->AddCall("beginInlining"); - original_ICorJitInfo->beginInlining(inlinerHnd, inlineeHnd); -} - -void interceptor_ICJI::reportInliningDecision( - CORINFO_METHOD_HANDLE inlinerHnd, - CORINFO_METHOD_HANDLE inlineeHnd, - CorInfoInline inlineResult, - const char* reason) -{ - mcs->AddCall("reportInliningDecision"); - original_ICorJitInfo->reportInliningDecision(inlinerHnd, inlineeHnd, inlineResult, reason); -} - -bool interceptor_ICJI::canTailCall( - CORINFO_METHOD_HANDLE callerHnd, - CORINFO_METHOD_HANDLE declaredCalleeHnd, - CORINFO_METHOD_HANDLE exactCalleeHnd, - bool fIsTailPrefix) -{ - mcs->AddCall("canTailCall"); - return original_ICorJitInfo->canTailCall(callerHnd, declaredCalleeHnd, exactCalleeHnd, fIsTailPrefix); -} - -void interceptor_ICJI::reportTailCallDecision( - CORINFO_METHOD_HANDLE callerHnd, - CORINFO_METHOD_HANDLE calleeHnd, - bool fIsTailPrefix, - CorInfoTailCall tailCallResult, - const char* reason) -{ - mcs->AddCall("reportTailCallDecision"); - original_ICorJitInfo->reportTailCallDecision(callerHnd, calleeHnd, fIsTailPrefix, tailCallResult, reason); -} - -void interceptor_ICJI::getEHinfo( - CORINFO_METHOD_HANDLE ftn, - unsigned EHnumber, - CORINFO_EH_CLAUSE* clause) -{ - mcs->AddCall("getEHinfo"); - original_ICorJitInfo->getEHinfo(ftn, EHnumber, clause); -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getMethodClass( - CORINFO_METHOD_HANDLE method) -{ - mcs->AddCall("getMethodClass"); - return original_ICorJitInfo->getMethodClass(method); -} - -void interceptor_ICJI::getMethodVTableOffset( - CORINFO_METHOD_HANDLE method, - unsigned* offsetOfIndirection, - unsigned* offsetAfterIndirection, - bool* isRelative) -{ - mcs->AddCall("getMethodVTableOffset"); - original_ICorJitInfo->getMethodVTableOffset(method, offsetOfIndirection, offsetAfterIndirection, isRelative); -} - -bool interceptor_ICJI::resolveVirtualMethod( - CORINFO_DEVIRTUALIZATION_INFO* info) -{ - mcs->AddCall("resolveVirtualMethod"); - return original_ICorJitInfo->resolveVirtualMethod(info); -} - -CORINFO_METHOD_HANDLE interceptor_ICJI::getAsyncOtherVariant( - CORINFO_METHOD_HANDLE ftn, - bool* variantIsThunk) -{ - mcs->AddCall("getAsyncOtherVariant"); - return original_ICorJitInfo->getAsyncOtherVariant(ftn, variantIsThunk); -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getDefaultComparerClass( - CORINFO_CLASS_HANDLE elemType) -{ - mcs->AddCall("getDefaultComparerClass"); - return original_ICorJitInfo->getDefaultComparerClass(elemType); -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getDefaultEqualityComparerClass( - CORINFO_CLASS_HANDLE elemType) -{ - mcs->AddCall("getDefaultEqualityComparerClass"); - return original_ICorJitInfo->getDefaultEqualityComparerClass(elemType); -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getSZArrayHelperEnumeratorClass( - CORINFO_CLASS_HANDLE elemType) -{ - mcs->AddCall("getSZArrayHelperEnumeratorClass"); - return original_ICorJitInfo->getSZArrayHelperEnumeratorClass(elemType); -} - -void interceptor_ICJI::expandRawHandleIntrinsic( - CORINFO_RESOLVED_TOKEN* pResolvedToken, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_GENERICHANDLE_RESULT* pResult) -{ - mcs->AddCall("expandRawHandleIntrinsic"); - original_ICorJitInfo->expandRawHandleIntrinsic(pResolvedToken, callerHandle, pResult); -} - -bool interceptor_ICJI::isIntrinsicType( - CORINFO_CLASS_HANDLE classHnd) -{ - mcs->AddCall("isIntrinsicType"); - return original_ICorJitInfo->isIntrinsicType(classHnd); -} - -CorInfoCallConvExtension interceptor_ICJI::getUnmanagedCallConv( - CORINFO_METHOD_HANDLE method, - CORINFO_SIG_INFO* callSiteSig, - bool* pSuppressGCTransition) -{ - mcs->AddCall("getUnmanagedCallConv"); - return original_ICorJitInfo->getUnmanagedCallConv(method, callSiteSig, pSuppressGCTransition); -} - -bool interceptor_ICJI::pInvokeMarshalingRequired( - CORINFO_METHOD_HANDLE method, - CORINFO_SIG_INFO* callSiteSig) -{ - mcs->AddCall("pInvokeMarshalingRequired"); - return original_ICorJitInfo->pInvokeMarshalingRequired(method, callSiteSig); -} - -bool interceptor_ICJI::satisfiesMethodConstraints( - CORINFO_CLASS_HANDLE parent, - CORINFO_METHOD_HANDLE method) -{ - mcs->AddCall("satisfiesMethodConstraints"); - return original_ICorJitInfo->satisfiesMethodConstraints(parent, method); -} - -void interceptor_ICJI::getGSCookie( - GSCookie* pCookieVal, - GSCookie** ppCookieVal) -{ - mcs->AddCall("getGSCookie"); - original_ICorJitInfo->getGSCookie(pCookieVal, ppCookieVal); -} - -void interceptor_ICJI::setPatchpointInfo( - PatchpointInfo* patchpointInfo) -{ - mcs->AddCall("setPatchpointInfo"); - original_ICorJitInfo->setPatchpointInfo(patchpointInfo); -} - -PatchpointInfo* interceptor_ICJI::getOSRInfo( - unsigned* ilOffset) -{ - mcs->AddCall("getOSRInfo"); - return original_ICorJitInfo->getOSRInfo(ilOffset); -} - -void interceptor_ICJI::resolveToken( - CORINFO_RESOLVED_TOKEN* pResolvedToken) -{ - mcs->AddCall("resolveToken"); - original_ICorJitInfo->resolveToken(pResolvedToken); -} - -void interceptor_ICJI::findSig( - CORINFO_MODULE_HANDLE module, - unsigned sigTOK, - CORINFO_CONTEXT_HANDLE context, - CORINFO_SIG_INFO* sig) -{ - mcs->AddCall("findSig"); - original_ICorJitInfo->findSig(module, sigTOK, context, sig); -} - -void interceptor_ICJI::findCallSiteSig( - CORINFO_MODULE_HANDLE module, - unsigned methTOK, - CORINFO_CONTEXT_HANDLE context, - CORINFO_SIG_INFO* sig) -{ - mcs->AddCall("findCallSiteSig"); - original_ICorJitInfo->findCallSiteSig(module, methTOK, context, sig); -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getTokenTypeAsHandle( - CORINFO_RESOLVED_TOKEN* pResolvedToken) -{ - mcs->AddCall("getTokenTypeAsHandle"); - return original_ICorJitInfo->getTokenTypeAsHandle(pResolvedToken); -} - -int interceptor_ICJI::getStringLiteral( - CORINFO_MODULE_HANDLE module, - unsigned metaTOK, - char16_t* buffer, - int bufferSize, - int startIndex) -{ - mcs->AddCall("getStringLiteral"); - return original_ICorJitInfo->getStringLiteral(module, metaTOK, buffer, bufferSize, startIndex); -} - -size_t interceptor_ICJI::printObjectDescription( - CORINFO_OBJECT_HANDLE handle, - char* buffer, - size_t bufferSize, - size_t* pRequiredBufferSize) -{ - mcs->AddCall("printObjectDescription"); - return original_ICorJitInfo->printObjectDescription(handle, buffer, bufferSize, pRequiredBufferSize); -} - -CorInfoType interceptor_ICJI::asCorInfoType( - CORINFO_CLASS_HANDLE cls) -{ - mcs->AddCall("asCorInfoType"); - return original_ICorJitInfo->asCorInfoType(cls); -} - -const char* interceptor_ICJI::getClassNameFromMetadata( - CORINFO_CLASS_HANDLE cls, - const char** namespaceName) -{ - mcs->AddCall("getClassNameFromMetadata"); - return original_ICorJitInfo->getClassNameFromMetadata(cls, namespaceName); -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getTypeInstantiationArgument( - CORINFO_CLASS_HANDLE cls, - unsigned index) -{ - mcs->AddCall("getTypeInstantiationArgument"); - return original_ICorJitInfo->getTypeInstantiationArgument(cls, index); -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getMethodInstantiationArgument( - CORINFO_METHOD_HANDLE ftn, - unsigned index) -{ - mcs->AddCall("getMethodInstantiationArgument"); - return original_ICorJitInfo->getMethodInstantiationArgument(ftn, index); -} - -size_t interceptor_ICJI::printClassName( - CORINFO_CLASS_HANDLE cls, - char* buffer, - size_t bufferSize, - size_t* pRequiredBufferSize) -{ - mcs->AddCall("printClassName"); - return original_ICorJitInfo->printClassName(cls, buffer, bufferSize, pRequiredBufferSize); -} - -bool interceptor_ICJI::isValueClass( - CORINFO_CLASS_HANDLE cls) -{ - mcs->AddCall("isValueClass"); - return original_ICorJitInfo->isValueClass(cls); -} - -bool interceptor_ICJI::isByRefLike( - CORINFO_CLASS_HANDLE cls) -{ - mcs->AddCall("isByRefLike"); - return original_ICorJitInfo->isByRefLike(cls); -} - -bool interceptor_ICJI::isSharedInst( - CORINFO_CLASS_HANDLE cls) -{ - mcs->AddCall("isSharedInst"); - return original_ICorJitInfo->isSharedInst(cls); -} - -uint32_t interceptor_ICJI::getClassAttribs( - CORINFO_CLASS_HANDLE cls) -{ - mcs->AddCall("getClassAttribs"); - return original_ICorJitInfo->getClassAttribs(cls); -} - -const char* interceptor_ICJI::getClassAssemblyName( - CORINFO_CLASS_HANDLE cls) -{ - mcs->AddCall("getClassAssemblyName"); - return original_ICorJitInfo->getClassAssemblyName(cls); -} - -void* interceptor_ICJI::LongLifetimeMalloc( - size_t sz) -{ - mcs->AddCall("LongLifetimeMalloc"); - return original_ICorJitInfo->LongLifetimeMalloc(sz); -} - -void interceptor_ICJI::LongLifetimeFree( - void* obj) -{ - mcs->AddCall("LongLifetimeFree"); - original_ICorJitInfo->LongLifetimeFree(obj); -} - -bool interceptor_ICJI::getIsClassInitedFlagAddress( - CORINFO_CLASS_HANDLE cls, - CORINFO_CONST_LOOKUP* addr, - int* offset) -{ - mcs->AddCall("getIsClassInitedFlagAddress"); - return original_ICorJitInfo->getIsClassInitedFlagAddress(cls, addr, offset); -} - -void* interceptor_ICJI::getClassThreadStaticDynamicInfo( - CORINFO_CLASS_HANDLE clr) -{ - mcs->AddCall("getClassThreadStaticDynamicInfo"); - return original_ICorJitInfo->getClassThreadStaticDynamicInfo(clr); -} - -void* interceptor_ICJI::getClassStaticDynamicInfo( - CORINFO_CLASS_HANDLE clr) -{ - mcs->AddCall("getClassStaticDynamicInfo"); - return original_ICorJitInfo->getClassStaticDynamicInfo(clr); -} - -bool interceptor_ICJI::getStaticBaseAddress( - CORINFO_CLASS_HANDLE cls, - bool isGc, - CORINFO_CONST_LOOKUP* addr) -{ - mcs->AddCall("getStaticBaseAddress"); - return original_ICorJitInfo->getStaticBaseAddress(cls, isGc, addr); -} - -unsigned interceptor_ICJI::getClassSize( - CORINFO_CLASS_HANDLE cls) -{ - mcs->AddCall("getClassSize"); - return original_ICorJitInfo->getClassSize(cls); -} - -unsigned interceptor_ICJI::getHeapClassSize( - CORINFO_CLASS_HANDLE cls) -{ - mcs->AddCall("getHeapClassSize"); - return original_ICorJitInfo->getHeapClassSize(cls); -} - -bool interceptor_ICJI::canAllocateOnStack( - CORINFO_CLASS_HANDLE cls) -{ - mcs->AddCall("canAllocateOnStack"); - return original_ICorJitInfo->canAllocateOnStack(cls); -} - -unsigned interceptor_ICJI::getClassAlignmentRequirement( - CORINFO_CLASS_HANDLE cls, - bool fDoubleAlignHint) -{ - mcs->AddCall("getClassAlignmentRequirement"); - return original_ICorJitInfo->getClassAlignmentRequirement(cls, fDoubleAlignHint); -} - -unsigned interceptor_ICJI::getClassGClayout( - CORINFO_CLASS_HANDLE cls, - uint8_t* gcPtrs) -{ - mcs->AddCall("getClassGClayout"); - return original_ICorJitInfo->getClassGClayout(cls, gcPtrs); -} - -unsigned interceptor_ICJI::getClassNumInstanceFields( - CORINFO_CLASS_HANDLE cls) -{ - mcs->AddCall("getClassNumInstanceFields"); - return original_ICorJitInfo->getClassNumInstanceFields(cls); -} - -CORINFO_FIELD_HANDLE interceptor_ICJI::getFieldInClass( - CORINFO_CLASS_HANDLE clsHnd, - int32_t num) -{ - mcs->AddCall("getFieldInClass"); - return original_ICorJitInfo->getFieldInClass(clsHnd, num); -} - -GetTypeLayoutResult interceptor_ICJI::getTypeLayout( - CORINFO_CLASS_HANDLE typeHnd, - CORINFO_TYPE_LAYOUT_NODE* treeNodes, - size_t* numTreeNodes) -{ - mcs->AddCall("getTypeLayout"); - return original_ICorJitInfo->getTypeLayout(typeHnd, treeNodes, numTreeNodes); -} - -bool interceptor_ICJI::checkMethodModifier( - CORINFO_METHOD_HANDLE hMethod, - const char* modifier, - bool fOptional) -{ - mcs->AddCall("checkMethodModifier"); - return original_ICorJitInfo->checkMethodModifier(hMethod, modifier, fOptional); -} - -CorInfoHelpFunc interceptor_ICJI::getNewHelper( - CORINFO_CLASS_HANDLE classHandle, - bool* pHasSideEffects) -{ - mcs->AddCall("getNewHelper"); - return original_ICorJitInfo->getNewHelper(classHandle, pHasSideEffects); -} - -CorInfoHelpFunc interceptor_ICJI::getNewArrHelper( - CORINFO_CLASS_HANDLE arrayCls) -{ - mcs->AddCall("getNewArrHelper"); - return original_ICorJitInfo->getNewArrHelper(arrayCls); -} - -CorInfoHelpFunc interceptor_ICJI::getCastingHelper( - CORINFO_RESOLVED_TOKEN* pResolvedToken, - bool fThrowing) -{ - mcs->AddCall("getCastingHelper"); - return original_ICorJitInfo->getCastingHelper(pResolvedToken, fThrowing); -} - -CorInfoHelpFunc interceptor_ICJI::getSharedCCtorHelper( - CORINFO_CLASS_HANDLE clsHnd) -{ - mcs->AddCall("getSharedCCtorHelper"); - return original_ICorJitInfo->getSharedCCtorHelper(clsHnd); -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getTypeForBox( - CORINFO_CLASS_HANDLE cls) -{ - mcs->AddCall("getTypeForBox"); - return original_ICorJitInfo->getTypeForBox(cls); -} - -CorInfoHelpFunc interceptor_ICJI::getBoxHelper( - CORINFO_CLASS_HANDLE cls) -{ - mcs->AddCall("getBoxHelper"); - return original_ICorJitInfo->getBoxHelper(cls); -} - -CorInfoHelpFunc interceptor_ICJI::getUnBoxHelper( - CORINFO_CLASS_HANDLE cls) -{ - mcs->AddCall("getUnBoxHelper"); - return original_ICorJitInfo->getUnBoxHelper(cls); -} - -CORINFO_OBJECT_HANDLE interceptor_ICJI::getRuntimeTypePointer( - CORINFO_CLASS_HANDLE cls) -{ - mcs->AddCall("getRuntimeTypePointer"); - return original_ICorJitInfo->getRuntimeTypePointer(cls); -} - -bool interceptor_ICJI::isObjectImmutable( - CORINFO_OBJECT_HANDLE objPtr) -{ - mcs->AddCall("isObjectImmutable"); - return original_ICorJitInfo->isObjectImmutable(objPtr); -} - -bool interceptor_ICJI::getStringChar( - CORINFO_OBJECT_HANDLE strObj, - int index, - uint16_t* value) -{ - mcs->AddCall("getStringChar"); - return original_ICorJitInfo->getStringChar(strObj, index, value); -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getObjectType( - CORINFO_OBJECT_HANDLE objPtr) -{ - mcs->AddCall("getObjectType"); - return original_ICorJitInfo->getObjectType(objPtr); -} - -bool interceptor_ICJI::getReadyToRunHelper( - CORINFO_RESOLVED_TOKEN* pResolvedToken, - CorInfoHelpFunc id, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_CONST_LOOKUP* pLookup) -{ - mcs->AddCall("getReadyToRunHelper"); - return original_ICorJitInfo->getReadyToRunHelper(pResolvedToken, id, callerHandle, pLookup); -} - -void interceptor_ICJI::getReadyToRunDelegateCtorHelper( - CORINFO_RESOLVED_TOKEN* pTargetMethod, - mdToken targetConstraint, - CORINFO_CLASS_HANDLE delegateType, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_LOOKUP* pLookup) -{ - mcs->AddCall("getReadyToRunDelegateCtorHelper"); - original_ICorJitInfo->getReadyToRunDelegateCtorHelper(pTargetMethod, targetConstraint, delegateType, callerHandle, pLookup); -} - -CorInfoInitClassResult interceptor_ICJI::initClass( - CORINFO_FIELD_HANDLE field, - CORINFO_METHOD_HANDLE method, - CORINFO_CONTEXT_HANDLE context) -{ - mcs->AddCall("initClass"); - return original_ICorJitInfo->initClass(field, method, context); -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getBuiltinClass( - CorInfoClassId classId) -{ - mcs->AddCall("getBuiltinClass"); - return original_ICorJitInfo->getBuiltinClass(classId); -} - -CorInfoType interceptor_ICJI::getTypeForPrimitiveValueClass( - CORINFO_CLASS_HANDLE cls) -{ - mcs->AddCall("getTypeForPrimitiveValueClass"); - return original_ICorJitInfo->getTypeForPrimitiveValueClass(cls); -} - -CorInfoType interceptor_ICJI::getTypeForPrimitiveNumericClass( - CORINFO_CLASS_HANDLE cls) -{ - mcs->AddCall("getTypeForPrimitiveNumericClass"); - return original_ICorJitInfo->getTypeForPrimitiveNumericClass(cls); -} - -bool interceptor_ICJI::canCast( - CORINFO_CLASS_HANDLE child, - CORINFO_CLASS_HANDLE parent) -{ - mcs->AddCall("canCast"); - return original_ICorJitInfo->canCast(child, parent); -} - -TypeCompareState interceptor_ICJI::compareTypesForCast( - CORINFO_CLASS_HANDLE fromClass, - CORINFO_CLASS_HANDLE toClass) -{ - mcs->AddCall("compareTypesForCast"); - return original_ICorJitInfo->compareTypesForCast(fromClass, toClass); -} - -TypeCompareState interceptor_ICJI::compareTypesForEquality( - CORINFO_CLASS_HANDLE cls1, - CORINFO_CLASS_HANDLE cls2) -{ - mcs->AddCall("compareTypesForEquality"); - return original_ICorJitInfo->compareTypesForEquality(cls1, cls2); -} - -bool interceptor_ICJI::isMoreSpecificType( - CORINFO_CLASS_HANDLE cls1, - CORINFO_CLASS_HANDLE cls2) -{ - mcs->AddCall("isMoreSpecificType"); - return original_ICorJitInfo->isMoreSpecificType(cls1, cls2); -} - -bool interceptor_ICJI::isExactType( - CORINFO_CLASS_HANDLE cls) -{ - mcs->AddCall("isExactType"); - return original_ICorJitInfo->isExactType(cls); -} - -TypeCompareState interceptor_ICJI::isGenericType( - CORINFO_CLASS_HANDLE cls) -{ - mcs->AddCall("isGenericType"); - return original_ICorJitInfo->isGenericType(cls); -} - -TypeCompareState interceptor_ICJI::isNullableType( - CORINFO_CLASS_HANDLE cls) -{ - mcs->AddCall("isNullableType"); - return original_ICorJitInfo->isNullableType(cls); -} - -TypeCompareState interceptor_ICJI::isEnum( - CORINFO_CLASS_HANDLE cls, - CORINFO_CLASS_HANDLE* underlyingType) -{ - mcs->AddCall("isEnum"); - return original_ICorJitInfo->isEnum(cls, underlyingType); -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getParentType( - CORINFO_CLASS_HANDLE cls) -{ - mcs->AddCall("getParentType"); - return original_ICorJitInfo->getParentType(cls); -} - -CorInfoType interceptor_ICJI::getChildType( - CORINFO_CLASS_HANDLE clsHnd, - CORINFO_CLASS_HANDLE* clsRet) -{ - mcs->AddCall("getChildType"); - return original_ICorJitInfo->getChildType(clsHnd, clsRet); -} - -bool interceptor_ICJI::isSDArray( - CORINFO_CLASS_HANDLE cls) -{ - mcs->AddCall("isSDArray"); - return original_ICorJitInfo->isSDArray(cls); -} - -unsigned interceptor_ICJI::getArrayRank( - CORINFO_CLASS_HANDLE cls) -{ - mcs->AddCall("getArrayRank"); - return original_ICorJitInfo->getArrayRank(cls); -} - -CorInfoArrayIntrinsic interceptor_ICJI::getArrayIntrinsicID( - CORINFO_METHOD_HANDLE ftn) -{ - mcs->AddCall("getArrayIntrinsicID"); - return original_ICorJitInfo->getArrayIntrinsicID(ftn); -} - -void* interceptor_ICJI::getArrayInitializationData( - CORINFO_FIELD_HANDLE field, - uint32_t size) -{ - mcs->AddCall("getArrayInitializationData"); - return original_ICorJitInfo->getArrayInitializationData(field, size); -} - -CorInfoIsAccessAllowedResult interceptor_ICJI::canAccessClass( - CORINFO_RESOLVED_TOKEN* pResolvedToken, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_HELPER_DESC* pAccessHelper) -{ - mcs->AddCall("canAccessClass"); - return original_ICorJitInfo->canAccessClass(pResolvedToken, callerHandle, pAccessHelper); -} - -size_t interceptor_ICJI::printFieldName( - CORINFO_FIELD_HANDLE field, - char* buffer, - size_t bufferSize, - size_t* pRequiredBufferSize) -{ - mcs->AddCall("printFieldName"); - return original_ICorJitInfo->printFieldName(field, buffer, bufferSize, pRequiredBufferSize); -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getFieldClass( - CORINFO_FIELD_HANDLE field) -{ - mcs->AddCall("getFieldClass"); - return original_ICorJitInfo->getFieldClass(field); -} - -CorInfoType interceptor_ICJI::getFieldType( - CORINFO_FIELD_HANDLE field, - CORINFO_CLASS_HANDLE* structType, - CORINFO_CLASS_HANDLE fieldOwnerHint) -{ - mcs->AddCall("getFieldType"); - return original_ICorJitInfo->getFieldType(field, structType, fieldOwnerHint); -} - -unsigned interceptor_ICJI::getFieldOffset( - CORINFO_FIELD_HANDLE field) -{ - mcs->AddCall("getFieldOffset"); - return original_ICorJitInfo->getFieldOffset(field); -} - -void interceptor_ICJI::getFieldInfo( - CORINFO_RESOLVED_TOKEN* pResolvedToken, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_ACCESS_FLAGS flags, - CORINFO_FIELD_INFO* pResult) -{ - mcs->AddCall("getFieldInfo"); - original_ICorJitInfo->getFieldInfo(pResolvedToken, callerHandle, flags, pResult); -} - -uint32_t interceptor_ICJI::getThreadLocalFieldInfo( - CORINFO_FIELD_HANDLE field, - bool isGCtype) -{ - mcs->AddCall("getThreadLocalFieldInfo"); - return original_ICorJitInfo->getThreadLocalFieldInfo(field, isGCtype); -} - -void interceptor_ICJI::getThreadLocalStaticBlocksInfo( - CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) -{ - mcs->AddCall("getThreadLocalStaticBlocksInfo"); - original_ICorJitInfo->getThreadLocalStaticBlocksInfo(pInfo); -} - -void interceptor_ICJI::getThreadLocalStaticInfo_NativeAOT( - CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo) -{ - mcs->AddCall("getThreadLocalStaticInfo_NativeAOT"); - original_ICorJitInfo->getThreadLocalStaticInfo_NativeAOT(pInfo); -} - -bool interceptor_ICJI::isFieldStatic( - CORINFO_FIELD_HANDLE fldHnd) -{ - mcs->AddCall("isFieldStatic"); - return original_ICorJitInfo->isFieldStatic(fldHnd); -} - -int interceptor_ICJI::getArrayOrStringLength( - CORINFO_OBJECT_HANDLE objHnd) -{ - mcs->AddCall("getArrayOrStringLength"); - return original_ICorJitInfo->getArrayOrStringLength(objHnd); -} - -void interceptor_ICJI::getBoundaries( - CORINFO_METHOD_HANDLE ftn, - unsigned int* cILOffsets, - uint32_t** pILOffsets, - ICorDebugInfo::BoundaryTypes* implicitBoundaries) -{ - mcs->AddCall("getBoundaries"); - original_ICorJitInfo->getBoundaries(ftn, cILOffsets, pILOffsets, implicitBoundaries); -} - -void interceptor_ICJI::setBoundaries( - CORINFO_METHOD_HANDLE ftn, - uint32_t cMap, - ICorDebugInfo::OffsetMapping* pMap) -{ - mcs->AddCall("setBoundaries"); - original_ICorJitInfo->setBoundaries(ftn, cMap, pMap); -} - -void interceptor_ICJI::getVars( - CORINFO_METHOD_HANDLE ftn, - uint32_t* cVars, - ICorDebugInfo::ILVarInfo** vars, - bool* extendOthers) -{ - mcs->AddCall("getVars"); - original_ICorJitInfo->getVars(ftn, cVars, vars, extendOthers); -} - -void interceptor_ICJI::setVars( - CORINFO_METHOD_HANDLE ftn, - uint32_t cVars, - ICorDebugInfo::NativeVarInfo* vars) -{ - mcs->AddCall("setVars"); - original_ICorJitInfo->setVars(ftn, cVars, vars); -} - -void interceptor_ICJI::reportRichMappings( - ICorDebugInfo::InlineTreeNode* inlineTreeNodes, - uint32_t numInlineTreeNodes, - ICorDebugInfo::RichOffsetMapping* mappings, - uint32_t numMappings) -{ - mcs->AddCall("reportRichMappings"); - original_ICorJitInfo->reportRichMappings(inlineTreeNodes, numInlineTreeNodes, mappings, numMappings); -} - -void interceptor_ICJI::reportAsyncDebugInfo( - ICorDebugInfo::AsyncInfo* asyncInfo, - ICorDebugInfo::AsyncSuspensionPoint* suspensionPoints, - ICorDebugInfo::AsyncContinuationVarInfo* vars, - uint32_t numVars) -{ - mcs->AddCall("reportAsyncDebugInfo"); - original_ICorJitInfo->reportAsyncDebugInfo(asyncInfo, suspensionPoints, vars, numVars); -} - -void interceptor_ICJI::reportMetadata( - const char* key, - const void* value, - size_t length) -{ - mcs->AddCall("reportMetadata"); - original_ICorJitInfo->reportMetadata(key, value, length); -} - -void* interceptor_ICJI::allocateArray( - size_t cBytes) -{ - mcs->AddCall("allocateArray"); - return original_ICorJitInfo->allocateArray(cBytes); -} - -void interceptor_ICJI::freeArray( - void* array) -{ - mcs->AddCall("freeArray"); - original_ICorJitInfo->freeArray(array); -} - -CORINFO_ARG_LIST_HANDLE interceptor_ICJI::getArgNext( - CORINFO_ARG_LIST_HANDLE args) -{ - mcs->AddCall("getArgNext"); - return original_ICorJitInfo->getArgNext(args); -} - -CorInfoTypeWithMod interceptor_ICJI::getArgType( - CORINFO_SIG_INFO* sig, - CORINFO_ARG_LIST_HANDLE args, - CORINFO_CLASS_HANDLE* vcTypeRet) -{ - mcs->AddCall("getArgType"); - return original_ICorJitInfo->getArgType(sig, args, vcTypeRet); -} - -int interceptor_ICJI::getExactClasses( - CORINFO_CLASS_HANDLE baseType, - int maxExactClasses, - CORINFO_CLASS_HANDLE* exactClsRet) -{ - mcs->AddCall("getExactClasses"); - return original_ICorJitInfo->getExactClasses(baseType, maxExactClasses, exactClsRet); -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getArgClass( - CORINFO_SIG_INFO* sig, - CORINFO_ARG_LIST_HANDLE args) -{ - mcs->AddCall("getArgClass"); - return original_ICorJitInfo->getArgClass(sig, args); -} - -CorInfoHFAElemType interceptor_ICJI::getHFAType( - CORINFO_CLASS_HANDLE hClass) -{ - mcs->AddCall("getHFAType"); - return original_ICorJitInfo->getHFAType(hClass); -} - -bool interceptor_ICJI::runWithErrorTrap( - ICorJitInfo::errorTrapFunction function, - void* parameter) -{ - mcs->AddCall("runWithErrorTrap"); - return original_ICorJitInfo->runWithErrorTrap(function, parameter); -} - -bool interceptor_ICJI::runWithSPMIErrorTrap( - ICorJitInfo::errorTrapFunction function, - void* parameter) -{ - mcs->AddCall("runWithSPMIErrorTrap"); - return original_ICorJitInfo->runWithSPMIErrorTrap(function, parameter); -} - -void interceptor_ICJI::getEEInfo( - CORINFO_EE_INFO* pEEInfoOut) -{ - mcs->AddCall("getEEInfo"); - original_ICorJitInfo->getEEInfo(pEEInfoOut); -} - -void interceptor_ICJI::getAsyncInfo( - CORINFO_ASYNC_INFO* pAsyncInfoOut) -{ - mcs->AddCall("getAsyncInfo"); - original_ICorJitInfo->getAsyncInfo(pAsyncInfoOut); -} - -CORINFO_METHOD_HANDLE interceptor_ICJI::getAwaitReturnCall( - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_CONTEXT_HANDLE* contextHandle, - CORINFO_LOOKUP* instArg) -{ - mcs->AddCall("getAwaitReturnCall"); - return original_ICorJitInfo->getAwaitReturnCall(callerHandle, contextHandle, instArg); -} - -CORINFO_METHOD_HANDLE interceptor_ICJI::getAwaitAwaiterInContinuationCall( - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_RESOLVED_TOKEN* pResolvedToken, - bool isUnsafe, - CORINFO_CONTEXT_HANDLE* contextHandle, - CORINFO_LOOKUP* instArg) -{ - mcs->AddCall("getAwaitAwaiterInContinuationCall"); - return original_ICorJitInfo->getAwaitAwaiterInContinuationCall(callerHandle, pResolvedToken, isUnsafe, contextHandle, instArg); -} - -mdMethodDef interceptor_ICJI::getMethodDefFromMethod( - CORINFO_METHOD_HANDLE hMethod) -{ - mcs->AddCall("getMethodDefFromMethod"); - return original_ICorJitInfo->getMethodDefFromMethod(hMethod); -} - -size_t interceptor_ICJI::printMethodName( - CORINFO_METHOD_HANDLE ftn, - char* buffer, - size_t bufferSize, - size_t* pRequiredBufferSize) -{ - mcs->AddCall("printMethodName"); - return original_ICorJitInfo->printMethodName(ftn, buffer, bufferSize, pRequiredBufferSize); -} - -const char* interceptor_ICJI::getMethodNameFromMetadata( - CORINFO_METHOD_HANDLE ftn, - const char** className, - const char** namespaceName, - const char** enclosingClassNames, - size_t maxEnclosingClassNames) -{ - mcs->AddCall("getMethodNameFromMetadata"); - return original_ICorJitInfo->getMethodNameFromMetadata(ftn, className, namespaceName, enclosingClassNames, maxEnclosingClassNames); -} - -unsigned interceptor_ICJI::getMethodHash( - CORINFO_METHOD_HANDLE ftn) -{ - mcs->AddCall("getMethodHash"); - return original_ICorJitInfo->getMethodHash(ftn); -} - -bool interceptor_ICJI::getSystemVAmd64PassStructInRegisterDescriptor( - CORINFO_CLASS_HANDLE structHnd, - SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr) -{ - mcs->AddCall("getSystemVAmd64PassStructInRegisterDescriptor"); - return original_ICorJitInfo->getSystemVAmd64PassStructInRegisterDescriptor(structHnd, structPassInRegDescPtr); -} - -void interceptor_ICJI::getSwiftLowering( - CORINFO_CLASS_HANDLE structHnd, - CORINFO_SWIFT_LOWERING* pLowering) -{ - mcs->AddCall("getSwiftLowering"); - original_ICorJitInfo->getSwiftLowering(structHnd, pLowering); -} - -void interceptor_ICJI::getFpStructLowering( - CORINFO_CLASS_HANDLE structHnd, - CORINFO_FPSTRUCT_LOWERING* pLowering) -{ - mcs->AddCall("getFpStructLowering"); - original_ICorJitInfo->getFpStructLowering(structHnd, pLowering); -} - -CorInfoWasmType interceptor_ICJI::getWasmLowering( - CORINFO_CLASS_HANDLE structHnd) -{ - mcs->AddCall("getWasmLowering"); - return original_ICorJitInfo->getWasmLowering(structHnd); -} - -uint32_t interceptor_ICJI::getAddressAlignment( - void* address) -{ - mcs->AddCall("getAddressAlignment"); - return original_ICorJitInfo->getAddressAlignment(address); -} - -void interceptor_ICJI::getWasmWellKnownGlobals( - CORINFO_WASM_WELLKNOWN_GLOBALS* pWellKnownGlobalsOut) -{ - mcs->AddCall("getWasmWellKnownGlobals"); - original_ICorJitInfo->getWasmWellKnownGlobals(pWellKnownGlobalsOut); -} - -uint32_t interceptor_ICJI::getThreadTLSIndex( - void** ppIndirection) -{ - mcs->AddCall("getThreadTLSIndex"); - return original_ICorJitInfo->getThreadTLSIndex(ppIndirection); -} - -int32_t* interceptor_ICJI::getAddrOfCaptureThreadGlobal( - void** ppIndirection) -{ - mcs->AddCall("getAddrOfCaptureThreadGlobal"); - return original_ICorJitInfo->getAddrOfCaptureThreadGlobal(ppIndirection); -} - -void interceptor_ICJI::getHelperFtn( - CorInfoHelpFunc ftnNum, - CORINFO_CONST_LOOKUP* pNativeEntrypoint, - CORINFO_METHOD_HANDLE* pMethod) -{ - mcs->AddCall("getHelperFtn"); - original_ICorJitInfo->getHelperFtn(ftnNum, pNativeEntrypoint, pMethod); -} - -void interceptor_ICJI::getFunctionEntryPoint( - CORINFO_METHOD_HANDLE ftn, - CORINFO_CONST_LOOKUP* pResult, - CORINFO_ACCESS_FLAGS accessFlags) -{ - mcs->AddCall("getFunctionEntryPoint"); - original_ICorJitInfo->getFunctionEntryPoint(ftn, pResult, accessFlags); -} - -void interceptor_ICJI::getFunctionFixedEntryPoint( - CORINFO_METHOD_HANDLE ftn, - bool isUnsafeFunctionPointer, - CORINFO_CONST_LOOKUP* pResult) -{ - mcs->AddCall("getFunctionFixedEntryPoint"); - original_ICorJitInfo->getFunctionFixedEntryPoint(ftn, isUnsafeFunctionPointer, pResult); -} - -CORINFO_MODULE_HANDLE interceptor_ICJI::embedModuleHandle( - CORINFO_MODULE_HANDLE handle, - void** ppIndirection) -{ - mcs->AddCall("embedModuleHandle"); - return original_ICorJitInfo->embedModuleHandle(handle, ppIndirection); -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::embedClassHandle( - CORINFO_CLASS_HANDLE handle, - void** ppIndirection) -{ - mcs->AddCall("embedClassHandle"); - return original_ICorJitInfo->embedClassHandle(handle, ppIndirection); -} - -CORINFO_METHOD_HANDLE interceptor_ICJI::embedMethodHandle( - CORINFO_METHOD_HANDLE handle, - void** ppIndirection) -{ - mcs->AddCall("embedMethodHandle"); - return original_ICorJitInfo->embedMethodHandle(handle, ppIndirection); -} - -CORINFO_FIELD_HANDLE interceptor_ICJI::embedFieldHandle( - CORINFO_FIELD_HANDLE handle, - void** ppIndirection) -{ - mcs->AddCall("embedFieldHandle"); - return original_ICorJitInfo->embedFieldHandle(handle, ppIndirection); -} - -void interceptor_ICJI::embedGenericHandle( - CORINFO_RESOLVED_TOKEN* pResolvedToken, - bool fEmbedParent, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_GENERICHANDLE_RESULT* pResult) -{ - mcs->AddCall("embedGenericHandle"); - original_ICorJitInfo->embedGenericHandle(pResolvedToken, fEmbedParent, callerHandle, pResult); -} - -void interceptor_ICJI::getLocationOfThisType( - CORINFO_METHOD_HANDLE context, - CORINFO_LOOKUP_KIND* pLookupKind) -{ - mcs->AddCall("getLocationOfThisType"); - original_ICorJitInfo->getLocationOfThisType(context, pLookupKind); -} - -void interceptor_ICJI::getAddressOfPInvokeTarget( - CORINFO_METHOD_HANDLE method, - CORINFO_CONST_LOOKUP* pLookup) -{ - mcs->AddCall("getAddressOfPInvokeTarget"); - original_ICorJitInfo->getAddressOfPInvokeTarget(method, pLookup); -} - -void* interceptor_ICJI::GetCookieForInterpreterCalliSig( - CORINFO_SIG_INFO* szMetaSig) -{ - mcs->AddCall("GetCookieForInterpreterCalliSig"); - return original_ICorJitInfo->GetCookieForInterpreterCalliSig(szMetaSig); -} - -CORINFO_JUST_MY_CODE_HANDLE interceptor_ICJI::getJustMyCodeHandle( - CORINFO_METHOD_HANDLE method, - CORINFO_JUST_MY_CODE_HANDLE** ppIndirection) -{ - mcs->AddCall("getJustMyCodeHandle"); - return original_ICorJitInfo->getJustMyCodeHandle(method, ppIndirection); -} - -void interceptor_ICJI::GetProfilingHandle( - bool* pbHookFunction, - void** pProfilerHandle, - bool* pbIndirectedHandles) -{ - mcs->AddCall("GetProfilingHandle"); - original_ICorJitInfo->GetProfilingHandle(pbHookFunction, pProfilerHandle, pbIndirectedHandles); -} - -void interceptor_ICJI::getCallInfo( - CORINFO_RESOLVED_TOKEN* pResolvedToken, - CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_CALLINFO_FLAGS flags, - CORINFO_CALL_INFO* pResult) -{ - mcs->AddCall("getCallInfo"); - original_ICorJitInfo->getCallInfo(pResolvedToken, pConstrainedResolvedToken, callerHandle, flags, pResult); -} - -bool interceptor_ICJI::getStaticFieldContent( - CORINFO_FIELD_HANDLE field, - uint8_t* buffer, - int bufferSize, - int valueOffset, - bool ignoreMovableObjects) -{ - mcs->AddCall("getStaticFieldContent"); - return original_ICorJitInfo->getStaticFieldContent(field, buffer, bufferSize, valueOffset, ignoreMovableObjects); -} - -bool interceptor_ICJI::getObjectContent( - CORINFO_OBJECT_HANDLE obj, - uint8_t* buffer, - int bufferSize, - int valueOffset) -{ - mcs->AddCall("getObjectContent"); - return original_ICorJitInfo->getObjectContent(obj, buffer, bufferSize, valueOffset); -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getStaticFieldCurrentClass( - CORINFO_FIELD_HANDLE field, - bool* pIsSpeculative) -{ - mcs->AddCall("getStaticFieldCurrentClass"); - return original_ICorJitInfo->getStaticFieldCurrentClass(field, pIsSpeculative); -} - -CORINFO_VARARGS_HANDLE interceptor_ICJI::getVarArgsHandle( - CORINFO_SIG_INFO* pSig, - CORINFO_METHOD_HANDLE methHnd, - void** ppIndirection) -{ - mcs->AddCall("getVarArgsHandle"); - return original_ICorJitInfo->getVarArgsHandle(pSig, methHnd, ppIndirection); -} - -InfoAccessType interceptor_ICJI::constructStringLiteral( - CORINFO_MODULE_HANDLE module, - mdToken metaTok, - void** ppValue) -{ - mcs->AddCall("constructStringLiteral"); - return original_ICorJitInfo->constructStringLiteral(module, metaTok, ppValue); -} - -InfoAccessType interceptor_ICJI::emptyStringLiteral( - void** ppValue) -{ - mcs->AddCall("emptyStringLiteral"); - return original_ICorJitInfo->emptyStringLiteral(ppValue); -} - -uint32_t interceptor_ICJI::getFieldThreadLocalStoreID( - CORINFO_FIELD_HANDLE field, - void** ppIndirection) -{ - mcs->AddCall("getFieldThreadLocalStoreID"); - return original_ICorJitInfo->getFieldThreadLocalStoreID(field, ppIndirection); -} - -CORINFO_METHOD_HANDLE interceptor_ICJI::GetDelegateCtor( - CORINFO_METHOD_HANDLE methHnd, - CORINFO_CLASS_HANDLE clsHnd, - CORINFO_METHOD_HANDLE targetMethodHnd, - DelegateCtorArgs* pCtorData) -{ - mcs->AddCall("GetDelegateCtor"); - return original_ICorJitInfo->GetDelegateCtor(methHnd, clsHnd, targetMethodHnd, pCtorData); -} - -void interceptor_ICJI::MethodCompileComplete( - CORINFO_METHOD_HANDLE methHnd) -{ - mcs->AddCall("MethodCompileComplete"); - original_ICorJitInfo->MethodCompileComplete(methHnd); -} - -bool interceptor_ICJI::getTailCallHelpers( - CORINFO_RESOLVED_TOKEN* callToken, - CORINFO_SIG_INFO* sig, - CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, - CORINFO_TAILCALL_HELPERS* pResult) -{ - mcs->AddCall("getTailCallHelpers"); - return original_ICorJitInfo->getTailCallHelpers(callToken, sig, flags, pResult); -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getContinuationType( - size_t dataSize, - bool* objRefs, - size_t objRefsSize) -{ - mcs->AddCall("getContinuationType"); - return original_ICorJitInfo->getContinuationType(dataSize, objRefs, objRefsSize); -} - -CORINFO_METHOD_HANDLE interceptor_ICJI::getAsyncResumptionStub( - void** entryPoint) -{ - mcs->AddCall("getAsyncResumptionStub"); - return original_ICorJitInfo->getAsyncResumptionStub(entryPoint); -} - -bool interceptor_ICJI::convertPInvokeCalliToCall( - CORINFO_RESOLVED_TOKEN* pResolvedToken, - bool mustConvert) -{ - mcs->AddCall("convertPInvokeCalliToCall"); - return original_ICorJitInfo->convertPInvokeCalliToCall(pResolvedToken, mustConvert); -} - -bool interceptor_ICJI::notifyInstructionSetUsage( - CORINFO_InstructionSet instructionSet, - bool supportEnabled, - bool preserveNegativeDependency) -{ - mcs->AddCall("notifyInstructionSetUsage"); - return original_ICorJitInfo->notifyInstructionSetUsage(instructionSet, supportEnabled, preserveNegativeDependency); -} - -void interceptor_ICJI::updateEntryPointForTailCall( - CORINFO_CONST_LOOKUP* entryPoint) -{ - mcs->AddCall("updateEntryPointForTailCall"); - original_ICorJitInfo->updateEntryPointForTailCall(entryPoint); -} - -void interceptor_ICJI::allocMem( - AllocMemArgs* pArgs) -{ - mcs->AddCall("allocMem"); - original_ICorJitInfo->allocMem(pArgs); -} - -void interceptor_ICJI::reserveUnwindInfo( - bool isFunclet, - bool isColdCode, - uint32_t unwindSize) -{ - mcs->AddCall("reserveUnwindInfo"); - original_ICorJitInfo->reserveUnwindInfo(isFunclet, isColdCode, unwindSize); -} - -void interceptor_ICJI::allocUnwindInfo( - uint8_t* pHotCode, - uint8_t* pColdCode, - uint32_t startOffset, - uint32_t endOffset, - uint32_t unwindSize, - uint8_t* pUnwindBlock, - CorJitFuncKind funcKind) -{ - mcs->AddCall("allocUnwindInfo"); - original_ICorJitInfo->allocUnwindInfo(pHotCode, pColdCode, startOffset, endOffset, unwindSize, pUnwindBlock, funcKind); -} - -void* interceptor_ICJI::allocGCInfo( - size_t size) -{ - mcs->AddCall("allocGCInfo"); - return original_ICorJitInfo->allocGCInfo(size); -} - -void interceptor_ICJI::setEHcount( - unsigned cEH) -{ - mcs->AddCall("setEHcount"); - original_ICorJitInfo->setEHcount(cEH); -} - -void interceptor_ICJI::setEHinfo( - unsigned EHnumber, - const CORINFO_EH_CLAUSE* clause) -{ - mcs->AddCall("setEHinfo"); - original_ICorJitInfo->setEHinfo(EHnumber, clause); -} - -bool interceptor_ICJI::logMsg( - unsigned level, - const char* fmt, - va_list args) -{ - mcs->AddCall("logMsg"); - return original_ICorJitInfo->logMsg(level, fmt, args); -} - -int interceptor_ICJI::doAssert( - const char* szFile, - int iLine, - const char* szExpr) -{ - mcs->AddCall("doAssert"); - return original_ICorJitInfo->doAssert(szFile, iLine, szExpr); -} - -void interceptor_ICJI::reportFatalError( - CorJitResult result) -{ - mcs->AddCall("reportFatalError"); - original_ICorJitInfo->reportFatalError(result); -} - -JITINTERFACE_HRESULT interceptor_ICJI::getPgoInstrumentationResults( - CORINFO_METHOD_HANDLE ftnHnd, - ICorJitInfo::PgoInstrumentationSchema** pSchema, - uint32_t* pCountSchemaItems, - uint8_t** pInstrumentationData, - ICorJitInfo::PgoSource* pPgoSource, - bool* pDynamicPgo) -{ - mcs->AddCall("getPgoInstrumentationResults"); - return original_ICorJitInfo->getPgoInstrumentationResults(ftnHnd, pSchema, pCountSchemaItems, pInstrumentationData, pPgoSource, pDynamicPgo); -} - -JITINTERFACE_HRESULT interceptor_ICJI::allocPgoInstrumentationBySchema( - CORINFO_METHOD_HANDLE ftnHnd, - ICorJitInfo::PgoInstrumentationSchema* pSchema, - uint32_t countSchemaItems, - uint8_t** pInstrumentationData) -{ - mcs->AddCall("allocPgoInstrumentationBySchema"); - return original_ICorJitInfo->allocPgoInstrumentationBySchema(ftnHnd, pSchema, countSchemaItems, pInstrumentationData); -} - -void interceptor_ICJI::recordCallSite( - uint32_t instrOffset, - CORINFO_SIG_INFO* callSig, - CORINFO_METHOD_HANDLE methodHandle) -{ - mcs->AddCall("recordCallSite"); - original_ICorJitInfo->recordCallSite(instrOffset, callSig, methodHandle); -} - -void interceptor_ICJI::recordWasmManagedCallSig( - CORINFO_SIG_INFO* callSig) -{ - mcs->AddCall("recordWasmManagedCallSig"); - original_ICorJitInfo->recordWasmManagedCallSig(callSig); -} - -void interceptor_ICJI::recordRelocation( - void* location, - void* locationRW, - void* target, - CorInfoReloc fRelocType, - int32_t addlDelta) -{ - mcs->AddCall("recordRelocation"); - original_ICorJitInfo->recordRelocation(location, locationRW, target, fRelocType, addlDelta); -} - -CorInfoReloc interceptor_ICJI::getRelocTypeHint( - void* target) -{ - mcs->AddCall("getRelocTypeHint"); - return original_ICorJitInfo->getRelocTypeHint(target); -} - -uint32_t interceptor_ICJI::getExpectedTargetArchitecture() -{ - mcs->AddCall("getExpectedTargetArchitecture"); - return original_ICorJitInfo->getExpectedTargetArchitecture(); -} - -uint32_t interceptor_ICJI::getJitFlags( - CORJIT_FLAGS* flags, - uint32_t sizeInBytes) -{ - mcs->AddCall("getJitFlags"); - return original_ICorJitInfo->getJitFlags(flags, sizeInBytes); -} - -CORINFO_WASM_TYPE_SYMBOL_HANDLE interceptor_ICJI::getWasmTypeSymbol( - CorInfoWasmType* types, - size_t typesSize) -{ - mcs->AddCall("getWasmTypeSymbol"); - return original_ICorJitInfo->getWasmTypeSymbol(types, typesSize); -} - -CORINFO_METHOD_HANDLE interceptor_ICJI::getSpecialCopyHelper( - CORINFO_CLASS_HANDLE type) -{ - mcs->AddCall("getSpecialCopyHelper"); - return original_ICorJitInfo->getSpecialCopyHelper(type); -} - diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/jithost.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/jithost.cpp deleted file mode 100644 index 0b20a3e43975d8..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/jithost.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "standardpch.h" -#include "runtimedetails.h" -#include "spmiutil.h" -#include "methodcallsummarizer.h" -#include "jithost.h" - -JitHost* g_ourJitHost; - -JitHost::JitHost(ICorJitHost* wrappedHost) : wrappedHost(wrappedHost), mcs(nullptr) -{ -} - -void JitHost::setMethodCallSummarizer(MethodCallSummarizer* methodCallSummarizer) -{ - this->mcs = methodCallSummarizer; -} - -void* JitHost::allocateMemory(size_t size) -{ - return wrappedHost->allocateMemory(size); -} - -void JitHost::freeMemory(void* block) -{ - return wrappedHost->freeMemory(block); -} - -int JitHost::getIntConfigValue(const char* key, int defaultValue) -{ - mcs->AddCall("getIntConfigValue"); - return wrappedHost->getIntConfigValue(key, defaultValue); -} - -const char* JitHost::getStringConfigValue(const char* key) -{ - mcs->AddCall("getStringConfigValue"); - return wrappedHost->getStringConfigValue(key); -} - -void JitHost::freeStringConfigValue(const char* value) -{ - mcs->AddCall("freeStringConfigValue"); - wrappedHost->freeStringConfigValue(value); -} diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/jithost.h b/src/coreclr/tools/superpmi/superpmi-shim-counter/jithost.h deleted file mode 100644 index bba108adcd881f..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/jithost.h +++ /dev/null @@ -1,23 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#ifndef _JITHOST -#define _JITHOST - -class JitHost : public ICorJitHost -{ -public: - JitHost(ICorJitHost* wrappedHost); - - void setMethodCallSummarizer(MethodCallSummarizer* methodCallSummarizer); - -#include "icorjithostimpl.h" - -private: - ICorJitHost* wrappedHost; - MethodCallSummarizer* mcs; -}; - -extern JitHost* g_ourJitHost; - -#endif diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/methodcallsummarizer.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/methodcallsummarizer.cpp deleted file mode 100644 index ce9f142119c9c9..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/methodcallsummarizer.cpp +++ /dev/null @@ -1,44 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "standardpch.h" -#include "methodcallsummarizer.h" -#include "logging.h" -#include "spmiutil.h" - -MethodCallSummarizer::MethodCallSummarizer(const std::string& logPath) -{ - dataFileName = GetResultFileName(logPath, GetProcessCommandLine(), ".csv"); -} - -// Use ordered map to make the most commonly added items are at the top of the list... -// 60% landed in the first three slots in short runs -void MethodCallSummarizer::AddCall(const char* name) -{ - // std::map initialized integer values to zero - namesAndCounts[std::string(name)]++; -} - -void MethodCallSummarizer::SaveTextFile() -{ - FILE* fp = fopen(dataFileName.c_str(), "w"); - if (fp == NULL) - { - LogError("Couldn't open file '%s': error %d", dataFileName.c_str(), errno); - return; - } - - fprintf(fp, "FunctionName,Count\n"); - - for (auto& elem : namesAndCounts) - { - fprintf(fp, "%s,%d\n", elem.first.c_str(), elem.second); - } - - fclose(fp); -} - -MethodCallSummarizer::~MethodCallSummarizer() -{ - SaveTextFile(); -} diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/methodcallsummarizer.h b/src/coreclr/tools/superpmi/superpmi-shim-counter/methodcallsummarizer.h deleted file mode 100644 index aca87d55e91dd8..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/methodcallsummarizer.h +++ /dev/null @@ -1,24 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#ifndef _MethodCallSummarizer -#define _MethodCallSummarizer - -#include -#include - -class MethodCallSummarizer -{ -public: - MethodCallSummarizer(const std::string& name); - void AddCall(const char* name); - ~MethodCallSummarizer(); - -private: - std::map namesAndCounts; - std::string dataFileName; - - void SaveTextFile(); -}; - -#endif diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/superpmi-shim-counter.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/superpmi-shim-counter.cpp deleted file mode 100644 index a56c6d1bd8c264..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/superpmi-shim-counter.cpp +++ /dev/null @@ -1,178 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// SuperPMI-Shim.cpp - thin shim for the jit -//---------------------------------------------------------- - -#include "standardpch.h" -#include "superpmi-shim-counter.h" -#include "runtimedetails.h" -#include "icorjitcompiler.h" -#include "errorhandling.h" -#include "logging.h" -#include "spmiutil.h" -#include "jithost.h" -#include - -HMODULE g_hRealJit = 0; // We leak this currently (could do the proper shutdown in process_detach) -std::string g_realJitPath{""}; // Destructable objects will be cleaned up and won't leak -std::string g_logPath{""}; -std::string g_HomeDirectory{""}; -std::string g_DefaultRealJitPath{""}; - -std::unique_ptr g_globalContext = nullptr; - -// RAII holder for logger -// Global deconstructors are unreliable. We only use it for superpmi shim. -class LoggerHolder -{ -public: - LoggerHolder() - { - Logger::Initialize(); - // If the environment variable isn't set, we don't enable file logging - const char* logFilePath = GetEnvWithDefault("SuperPMIShimLogFilePath", nullptr); - if (logFilePath) - { - Logger::OpenLogFile(logFilePath); - } - } - - ~LoggerHolder() - { - Logger::Shutdown(); - } -} loggerHolder; - -void SetDefaultPaths() -{ - if (g_HomeDirectory.empty()) - { - g_HomeDirectory = GetEnvWithDefault("HOME", "."); - } - - if (g_DefaultRealJitPath.empty()) - { - g_DefaultRealJitPath = g_HomeDirectory + DIRECTORY_SEPARATOR_CHAR_A + DEFAULT_REAL_JIT_NAME_A; - } -} - -void SetLibName() -{ - if (g_realJitPath.empty()) - { - g_realJitPath = GetEnvWithDefault("SuperPMIShimPath", g_DefaultRealJitPath.c_str()); - } -} - -void SetLogPath() -{ - if (g_logPath.empty()) - { - g_logPath = GetEnvWithDefault("SuperPMIShimLogPath", g_HomeDirectory.c_str()); - } -} - -extern "C" -#ifdef HOST_UNIX - DLLEXPORT // For Win32 PAL LoadLibrary emulation -#endif - BOOL - DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) -{ - switch (ul_reason_for_call) - { - case DLL_PROCESS_ATTACH: -#ifdef HOST_UNIX - if (0 != PAL_InitializeDLL()) - { - fprintf(stderr, "Error: Fail to PAL_InitializeDLL\n"); - exit(1); - } -#endif // HOST_UNIX - break; - - case DLL_PROCESS_DETACH: - case DLL_THREAD_ATTACH: - case DLL_THREAD_DETACH: - break; - } - return TRUE; -} - -extern "C" DLLEXPORT void jitStartup(ICorJitHost* host) -{ - SetDefaultPaths(); - SetLibName(); - SetDebugDumpVariables(); - - if (!LoadRealJitLib(g_hRealJit, g_realJitPath)) - { - return; - } - - // Get the required entrypoint - PjitStartup pnjitStartup = (PjitStartup)GET_PROC_ADDRESS(g_hRealJit, "jitStartup"); - if (pnjitStartup == nullptr) - { - // This portion of the interface is not used by the JIT under test. - g_ourJitHost = nullptr; - return; - } - - g_ourJitHost = new JitHost(host); - - if (g_globalContext == nullptr) - { - SetLogPath(); - g_globalContext = std::unique_ptr(new MethodCallSummarizer(g_logPath)); - } - - g_ourJitHost->setMethodCallSummarizer(g_globalContext.get()); - - pnjitStartup(g_ourJitHost); -} - -extern "C" DLLEXPORT ICorJitCompiler* getJit() -{ - DWORD dwRetVal = 0; - PgetJit pngetJit; - interceptor_ICJC* pJitInstance = nullptr; - ICorJitCompiler* tICJI = nullptr; - - SetDefaultPaths(); - SetLibName(); - SetDebugDumpVariables(); - - if (!LoadRealJitLib(g_hRealJit, g_realJitPath)) - { - return nullptr; - } - - // get the required entrypoints - pngetJit = (PgetJit)GET_PROC_ADDRESS(g_hRealJit, "getJit"); - if (pngetJit == 0) - { - LogError("getJit() - GetProcAddress 'getJit' failed (0x%08x)", ::GetLastError()); - return nullptr; - } - - tICJI = pngetJit(); - if (tICJI == nullptr) - { - LogError("getJit() - pngetJit gave us null"); - return nullptr; - } - - pJitInstance = new interceptor_ICJC(); - pJitInstance->original_ICorJitCompiler = tICJI; - - if (g_globalContext == nullptr) - { - SetLogPath(); - g_globalContext = std::unique_ptr(new MethodCallSummarizer(g_logPath)); - } - pJitInstance->mcs = g_globalContext.get(); - return pJitInstance; -} diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/superpmi-shim-counter.def b/src/coreclr/tools/superpmi/superpmi-shim-counter/superpmi-shim-counter.def deleted file mode 100644 index f00334b07ef670..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/superpmi-shim-counter.def +++ /dev/null @@ -1,4 +0,0 @@ -LIBRARY -EXPORTS - getJit - jitStartup diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/superpmi-shim-counter.h b/src/coreclr/tools/superpmi/superpmi-shim-counter/superpmi-shim-counter.h deleted file mode 100644 index 3634f3ee72cbf9..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/superpmi-shim-counter.h +++ /dev/null @@ -1,10 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// SuperPMI-Shim.h - thin shim for the jit -//---------------------------------------------------------- -#ifndef _SuperPMIShim -#define _SuperPMIShim - -#endif diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/CMakeLists.txt b/src/coreclr/tools/superpmi/superpmi-shim-simple/CMakeLists.txt deleted file mode 100644 index f6be551299c166..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/CMakeLists.txt +++ /dev/null @@ -1,68 +0,0 @@ -project(superpmi-shim-simple) - -remove_definitions(-DUNICODE) -remove_definitions(-D_UNICODE) - -add_definitions(-DFEATURE_NO_HOST) -add_definitions(-DSELF_NO_HOST) - -if(CLR_CMAKE_HOST_WIN32) - #use static crt - set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded) -endif(CLR_CMAKE_HOST_WIN32) - -include_directories(.) -include_directories(../superpmi-shared) - -set(SUPERPMI_SHIM_SIMPLE_SOURCES - jithost.cpp - icorjitcompiler.cpp - icorjitinfo_generated.cpp - superpmi-shim-simple.cpp - ../superpmi-shared/callutils.cpp - ../superpmi-shared/compileresult.cpp - ../superpmi-shared/errorhandling.cpp - ../superpmi-shared/hash.cpp - ../superpmi-shared/logging.cpp - ../superpmi-shared/mclist.cpp - ../superpmi-shared/methodcontext.cpp - ../superpmi-shared/methodcontextreader.cpp - ../superpmi-shared/simpletimer.cpp - ../superpmi-shared/spmiutil.cpp - ../superpmi-shared/tocfile.cpp - ../superpmi-shared/typeutils.cpp - ../superpmi-shared/spmidumphelper.cpp -) - -if (CLR_CMAKE_TARGET_WIN32) - preprocess_file(${CMAKE_CURRENT_SOURCE_DIR}/superpmi-shim-simple.def ${CMAKE_CURRENT_BINARY_DIR}/superpmi-shim-simple.def) - - list(APPEND SUPERPMI_SHIM_SIMPLE_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/superpmi-shim-simple.def) -endif (CLR_CMAKE_TARGET_WIN32) - -add_library_clr(superpmi-shim-simple - SHARED - ${SUPERPMI_SHIM_SIMPLE_SOURCES} -) - -target_precompile_headers(superpmi-shim-simple PRIVATE "$<$:standardpch.h>") - -if(CLR_CMAKE_HOST_UNIX) - target_link_libraries(superpmi-shim-simple - PRIVATE - utilcodestaticnohost - mscorrc - coreclrpal - coreclrminipal - ) -else() - target_link_libraries(superpmi-shim-simple - PRIVATE - advapi32.lib - coreclrminipal - ${STATIC_MT_CRT_LIB} - ${STATIC_MT_CPP_LIB} - ) -endif(CLR_CMAKE_HOST_UNIX) - -install_clr(TARGETS superpmi-shim-simple DESTINATIONS . COMPONENT spmi) diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitcompiler.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitcompiler.cpp deleted file mode 100644 index 5f266c0fc96e9f..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitcompiler.cpp +++ /dev/null @@ -1,37 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "standardpch.h" -#include "icorjitcompiler.h" -#include "icorjitinfo.h" - -void interceptor_ICJC::setTargetOS(CORINFO_OS os) -{ - original_ICorJitCompiler->setTargetOS(os); -} - -CorJitResult interceptor_ICJC::compileMethod(ICorJitInfo* comp, /* IN */ - struct CORINFO_METHOD_INFO* info, /* IN */ - unsigned /* code:CorJitFlag */ flags, /* IN */ - uint8_t** nativeEntry, /* OUT */ - uint32_t* nativeSizeOfCode /* OUT */ - ) -{ - interceptor_ICJI our_ICorJitInfo; - our_ICorJitInfo.original_ICorJitInfo = comp; - - CorJitResult temp = - original_ICorJitCompiler->compileMethod(&our_ICorJitInfo, info, flags, nativeEntry, nativeSizeOfCode); - - return temp; -} - -void interceptor_ICJC::ProcessShutdownWork(ICorStaticInfo* info) -{ - original_ICorJitCompiler->ProcessShutdownWork(info); -} - -void interceptor_ICJC::getVersionIdentifier(GUID* versionIdentifier /* OUT */) -{ - original_ICorJitCompiler->getVersionIdentifier(versionIdentifier); -} diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitcompiler.h b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitcompiler.h deleted file mode 100644 index afce570098081a..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitcompiler.h +++ /dev/null @@ -1,19 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#ifndef _ICorJitCompiler -#define _ICorJitCompiler - -#include "runtimedetails.h" - -class interceptor_ICJC : public ICorJitCompiler -{ - -#include "icorjitcompilerimpl.h" - -public: - // Added to help us track the original icjc and be able to easily indirect to it. - ICorJitCompiler* original_ICorJitCompiler; -}; - -#endif diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.h b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.h deleted file mode 100644 index 000f097f71af39..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo.h +++ /dev/null @@ -1,20 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#ifndef _ICorJitInfo -#define _ICorJitInfo - -#include "runtimedetails.h" - -class interceptor_ICJI : public ICorJitInfo -{ - -#include "icorjitinfoimpl.h" - -public: - // Added to help us track the original icji and be able to easily indirect - // to it. And a simple way to keep one memory manager instance per instance. - ICorJitInfo* original_ICorJitInfo; -}; - -#endif diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp deleted file mode 100644 index 2050b1861675c0..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp +++ /dev/null @@ -1,1319 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -// DO NOT EDIT THIS FILE! IT IS AUTOGENERATED -// To regenerate run the gen script in src/coreclr/tools/Common/JitInterface/ThunkGenerator -// and follow the instructions in docs/project/updating-jitinterface.md - -#include "standardpch.h" -#include "icorjitinfo.h" -#include "superpmi-shim-simple.h" -#include "icorjitcompiler.h" -#include "spmiutil.h" - - -bool interceptor_ICJI::isIntrinsic( - CORINFO_METHOD_HANDLE ftn) -{ - return original_ICorJitInfo->isIntrinsic(ftn); -} - -bool interceptor_ICJI::canValueClassInstancePointerEscape( - CORINFO_METHOD_HANDLE ftn) -{ - return original_ICorJitInfo->canValueClassInstancePointerEscape(ftn); -} - -bool interceptor_ICJI::notifyMethodInfoUsage( - CORINFO_METHOD_HANDLE ftn) -{ - return original_ICorJitInfo->notifyMethodInfoUsage(ftn); -} - -uint32_t interceptor_ICJI::getMethodAttribs( - CORINFO_METHOD_HANDLE ftn) -{ - return original_ICorJitInfo->getMethodAttribs(ftn); -} - -void interceptor_ICJI::setMethodAttribs( - CORINFO_METHOD_HANDLE ftn, - CorInfoMethodRuntimeFlags attribs) -{ - original_ICorJitInfo->setMethodAttribs(ftn, attribs); -} - -void interceptor_ICJI::getMethodSig( - CORINFO_METHOD_HANDLE ftn, - CORINFO_SIG_INFO* sig, - CORINFO_CLASS_HANDLE memberParent) -{ - original_ICorJitInfo->getMethodSig(ftn, sig, memberParent); -} - -bool interceptor_ICJI::getMethodInfo( - CORINFO_METHOD_HANDLE ftn, - CORINFO_METHOD_INFO* info, - CORINFO_CONTEXT_HANDLE context) -{ - return original_ICorJitInfo->getMethodInfo(ftn, info, context); -} - -bool interceptor_ICJI::haveSameMethodDefinition( - CORINFO_METHOD_HANDLE meth1Hnd, - CORINFO_METHOD_HANDLE meth2Hnd) -{ - return original_ICorJitInfo->haveSameMethodDefinition(meth1Hnd, meth2Hnd); -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getTypeDefinition( - CORINFO_CLASS_HANDLE type) -{ - return original_ICorJitInfo->getTypeDefinition(type); -} - -CorInfoInline interceptor_ICJI::canInline( - CORINFO_METHOD_HANDLE callerHnd, - CORINFO_METHOD_HANDLE calleeHnd) -{ - return original_ICorJitInfo->canInline(callerHnd, calleeHnd); -} - -void interceptor_ICJI::beginInlining( - CORINFO_METHOD_HANDLE inlinerHnd, - CORINFO_METHOD_HANDLE inlineeHnd) -{ - original_ICorJitInfo->beginInlining(inlinerHnd, inlineeHnd); -} - -void interceptor_ICJI::reportInliningDecision( - CORINFO_METHOD_HANDLE inlinerHnd, - CORINFO_METHOD_HANDLE inlineeHnd, - CorInfoInline inlineResult, - const char* reason) -{ - original_ICorJitInfo->reportInliningDecision(inlinerHnd, inlineeHnd, inlineResult, reason); -} - -bool interceptor_ICJI::canTailCall( - CORINFO_METHOD_HANDLE callerHnd, - CORINFO_METHOD_HANDLE declaredCalleeHnd, - CORINFO_METHOD_HANDLE exactCalleeHnd, - bool fIsTailPrefix) -{ - return original_ICorJitInfo->canTailCall(callerHnd, declaredCalleeHnd, exactCalleeHnd, fIsTailPrefix); -} - -void interceptor_ICJI::reportTailCallDecision( - CORINFO_METHOD_HANDLE callerHnd, - CORINFO_METHOD_HANDLE calleeHnd, - bool fIsTailPrefix, - CorInfoTailCall tailCallResult, - const char* reason) -{ - original_ICorJitInfo->reportTailCallDecision(callerHnd, calleeHnd, fIsTailPrefix, tailCallResult, reason); -} - -void interceptor_ICJI::getEHinfo( - CORINFO_METHOD_HANDLE ftn, - unsigned EHnumber, - CORINFO_EH_CLAUSE* clause) -{ - original_ICorJitInfo->getEHinfo(ftn, EHnumber, clause); -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getMethodClass( - CORINFO_METHOD_HANDLE method) -{ - return original_ICorJitInfo->getMethodClass(method); -} - -void interceptor_ICJI::getMethodVTableOffset( - CORINFO_METHOD_HANDLE method, - unsigned* offsetOfIndirection, - unsigned* offsetAfterIndirection, - bool* isRelative) -{ - original_ICorJitInfo->getMethodVTableOffset(method, offsetOfIndirection, offsetAfterIndirection, isRelative); -} - -bool interceptor_ICJI::resolveVirtualMethod( - CORINFO_DEVIRTUALIZATION_INFO* info) -{ - return original_ICorJitInfo->resolveVirtualMethod(info); -} - -CORINFO_METHOD_HANDLE interceptor_ICJI::getAsyncOtherVariant( - CORINFO_METHOD_HANDLE ftn, - bool* variantIsThunk) -{ - return original_ICorJitInfo->getAsyncOtherVariant(ftn, variantIsThunk); -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getDefaultComparerClass( - CORINFO_CLASS_HANDLE elemType) -{ - return original_ICorJitInfo->getDefaultComparerClass(elemType); -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getDefaultEqualityComparerClass( - CORINFO_CLASS_HANDLE elemType) -{ - return original_ICorJitInfo->getDefaultEqualityComparerClass(elemType); -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getSZArrayHelperEnumeratorClass( - CORINFO_CLASS_HANDLE elemType) -{ - return original_ICorJitInfo->getSZArrayHelperEnumeratorClass(elemType); -} - -void interceptor_ICJI::expandRawHandleIntrinsic( - CORINFO_RESOLVED_TOKEN* pResolvedToken, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_GENERICHANDLE_RESULT* pResult) -{ - original_ICorJitInfo->expandRawHandleIntrinsic(pResolvedToken, callerHandle, pResult); -} - -bool interceptor_ICJI::isIntrinsicType( - CORINFO_CLASS_HANDLE classHnd) -{ - return original_ICorJitInfo->isIntrinsicType(classHnd); -} - -CorInfoCallConvExtension interceptor_ICJI::getUnmanagedCallConv( - CORINFO_METHOD_HANDLE method, - CORINFO_SIG_INFO* callSiteSig, - bool* pSuppressGCTransition) -{ - return original_ICorJitInfo->getUnmanagedCallConv(method, callSiteSig, pSuppressGCTransition); -} - -bool interceptor_ICJI::pInvokeMarshalingRequired( - CORINFO_METHOD_HANDLE method, - CORINFO_SIG_INFO* callSiteSig) -{ - return original_ICorJitInfo->pInvokeMarshalingRequired(method, callSiteSig); -} - -bool interceptor_ICJI::satisfiesMethodConstraints( - CORINFO_CLASS_HANDLE parent, - CORINFO_METHOD_HANDLE method) -{ - return original_ICorJitInfo->satisfiesMethodConstraints(parent, method); -} - -void interceptor_ICJI::getGSCookie( - GSCookie* pCookieVal, - GSCookie** ppCookieVal) -{ - original_ICorJitInfo->getGSCookie(pCookieVal, ppCookieVal); -} - -void interceptor_ICJI::setPatchpointInfo( - PatchpointInfo* patchpointInfo) -{ - original_ICorJitInfo->setPatchpointInfo(patchpointInfo); -} - -PatchpointInfo* interceptor_ICJI::getOSRInfo( - unsigned* ilOffset) -{ - return original_ICorJitInfo->getOSRInfo(ilOffset); -} - -void interceptor_ICJI::resolveToken( - CORINFO_RESOLVED_TOKEN* pResolvedToken) -{ - original_ICorJitInfo->resolveToken(pResolvedToken); -} - -void interceptor_ICJI::findSig( - CORINFO_MODULE_HANDLE module, - unsigned sigTOK, - CORINFO_CONTEXT_HANDLE context, - CORINFO_SIG_INFO* sig) -{ - original_ICorJitInfo->findSig(module, sigTOK, context, sig); -} - -void interceptor_ICJI::findCallSiteSig( - CORINFO_MODULE_HANDLE module, - unsigned methTOK, - CORINFO_CONTEXT_HANDLE context, - CORINFO_SIG_INFO* sig) -{ - original_ICorJitInfo->findCallSiteSig(module, methTOK, context, sig); -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getTokenTypeAsHandle( - CORINFO_RESOLVED_TOKEN* pResolvedToken) -{ - return original_ICorJitInfo->getTokenTypeAsHandle(pResolvedToken); -} - -int interceptor_ICJI::getStringLiteral( - CORINFO_MODULE_HANDLE module, - unsigned metaTOK, - char16_t* buffer, - int bufferSize, - int startIndex) -{ - return original_ICorJitInfo->getStringLiteral(module, metaTOK, buffer, bufferSize, startIndex); -} - -size_t interceptor_ICJI::printObjectDescription( - CORINFO_OBJECT_HANDLE handle, - char* buffer, - size_t bufferSize, - size_t* pRequiredBufferSize) -{ - return original_ICorJitInfo->printObjectDescription(handle, buffer, bufferSize, pRequiredBufferSize); -} - -CorInfoType interceptor_ICJI::asCorInfoType( - CORINFO_CLASS_HANDLE cls) -{ - return original_ICorJitInfo->asCorInfoType(cls); -} - -const char* interceptor_ICJI::getClassNameFromMetadata( - CORINFO_CLASS_HANDLE cls, - const char** namespaceName) -{ - return original_ICorJitInfo->getClassNameFromMetadata(cls, namespaceName); -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getTypeInstantiationArgument( - CORINFO_CLASS_HANDLE cls, - unsigned index) -{ - return original_ICorJitInfo->getTypeInstantiationArgument(cls, index); -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getMethodInstantiationArgument( - CORINFO_METHOD_HANDLE ftn, - unsigned index) -{ - return original_ICorJitInfo->getMethodInstantiationArgument(ftn, index); -} - -size_t interceptor_ICJI::printClassName( - CORINFO_CLASS_HANDLE cls, - char* buffer, - size_t bufferSize, - size_t* pRequiredBufferSize) -{ - return original_ICorJitInfo->printClassName(cls, buffer, bufferSize, pRequiredBufferSize); -} - -bool interceptor_ICJI::isValueClass( - CORINFO_CLASS_HANDLE cls) -{ - return original_ICorJitInfo->isValueClass(cls); -} - -bool interceptor_ICJI::isByRefLike( - CORINFO_CLASS_HANDLE cls) -{ - return original_ICorJitInfo->isByRefLike(cls); -} - -bool interceptor_ICJI::isSharedInst( - CORINFO_CLASS_HANDLE cls) -{ - return original_ICorJitInfo->isSharedInst(cls); -} - -uint32_t interceptor_ICJI::getClassAttribs( - CORINFO_CLASS_HANDLE cls) -{ - return original_ICorJitInfo->getClassAttribs(cls); -} - -const char* interceptor_ICJI::getClassAssemblyName( - CORINFO_CLASS_HANDLE cls) -{ - return original_ICorJitInfo->getClassAssemblyName(cls); -} - -void* interceptor_ICJI::LongLifetimeMalloc( - size_t sz) -{ - return original_ICorJitInfo->LongLifetimeMalloc(sz); -} - -void interceptor_ICJI::LongLifetimeFree( - void* obj) -{ - original_ICorJitInfo->LongLifetimeFree(obj); -} - -bool interceptor_ICJI::getIsClassInitedFlagAddress( - CORINFO_CLASS_HANDLE cls, - CORINFO_CONST_LOOKUP* addr, - int* offset) -{ - return original_ICorJitInfo->getIsClassInitedFlagAddress(cls, addr, offset); -} - -void* interceptor_ICJI::getClassThreadStaticDynamicInfo( - CORINFO_CLASS_HANDLE clr) -{ - return original_ICorJitInfo->getClassThreadStaticDynamicInfo(clr); -} - -void* interceptor_ICJI::getClassStaticDynamicInfo( - CORINFO_CLASS_HANDLE clr) -{ - return original_ICorJitInfo->getClassStaticDynamicInfo(clr); -} - -bool interceptor_ICJI::getStaticBaseAddress( - CORINFO_CLASS_HANDLE cls, - bool isGc, - CORINFO_CONST_LOOKUP* addr) -{ - return original_ICorJitInfo->getStaticBaseAddress(cls, isGc, addr); -} - -unsigned interceptor_ICJI::getClassSize( - CORINFO_CLASS_HANDLE cls) -{ - return original_ICorJitInfo->getClassSize(cls); -} - -unsigned interceptor_ICJI::getHeapClassSize( - CORINFO_CLASS_HANDLE cls) -{ - return original_ICorJitInfo->getHeapClassSize(cls); -} - -bool interceptor_ICJI::canAllocateOnStack( - CORINFO_CLASS_HANDLE cls) -{ - return original_ICorJitInfo->canAllocateOnStack(cls); -} - -unsigned interceptor_ICJI::getClassAlignmentRequirement( - CORINFO_CLASS_HANDLE cls, - bool fDoubleAlignHint) -{ - return original_ICorJitInfo->getClassAlignmentRequirement(cls, fDoubleAlignHint); -} - -unsigned interceptor_ICJI::getClassGClayout( - CORINFO_CLASS_HANDLE cls, - uint8_t* gcPtrs) -{ - return original_ICorJitInfo->getClassGClayout(cls, gcPtrs); -} - -unsigned interceptor_ICJI::getClassNumInstanceFields( - CORINFO_CLASS_HANDLE cls) -{ - return original_ICorJitInfo->getClassNumInstanceFields(cls); -} - -CORINFO_FIELD_HANDLE interceptor_ICJI::getFieldInClass( - CORINFO_CLASS_HANDLE clsHnd, - int32_t num) -{ - return original_ICorJitInfo->getFieldInClass(clsHnd, num); -} - -GetTypeLayoutResult interceptor_ICJI::getTypeLayout( - CORINFO_CLASS_HANDLE typeHnd, - CORINFO_TYPE_LAYOUT_NODE* treeNodes, - size_t* numTreeNodes) -{ - return original_ICorJitInfo->getTypeLayout(typeHnd, treeNodes, numTreeNodes); -} - -bool interceptor_ICJI::checkMethodModifier( - CORINFO_METHOD_HANDLE hMethod, - const char* modifier, - bool fOptional) -{ - return original_ICorJitInfo->checkMethodModifier(hMethod, modifier, fOptional); -} - -CorInfoHelpFunc interceptor_ICJI::getNewHelper( - CORINFO_CLASS_HANDLE classHandle, - bool* pHasSideEffects) -{ - return original_ICorJitInfo->getNewHelper(classHandle, pHasSideEffects); -} - -CorInfoHelpFunc interceptor_ICJI::getNewArrHelper( - CORINFO_CLASS_HANDLE arrayCls) -{ - return original_ICorJitInfo->getNewArrHelper(arrayCls); -} - -CorInfoHelpFunc interceptor_ICJI::getCastingHelper( - CORINFO_RESOLVED_TOKEN* pResolvedToken, - bool fThrowing) -{ - return original_ICorJitInfo->getCastingHelper(pResolvedToken, fThrowing); -} - -CorInfoHelpFunc interceptor_ICJI::getSharedCCtorHelper( - CORINFO_CLASS_HANDLE clsHnd) -{ - return original_ICorJitInfo->getSharedCCtorHelper(clsHnd); -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getTypeForBox( - CORINFO_CLASS_HANDLE cls) -{ - return original_ICorJitInfo->getTypeForBox(cls); -} - -CorInfoHelpFunc interceptor_ICJI::getBoxHelper( - CORINFO_CLASS_HANDLE cls) -{ - return original_ICorJitInfo->getBoxHelper(cls); -} - -CorInfoHelpFunc interceptor_ICJI::getUnBoxHelper( - CORINFO_CLASS_HANDLE cls) -{ - return original_ICorJitInfo->getUnBoxHelper(cls); -} - -CORINFO_OBJECT_HANDLE interceptor_ICJI::getRuntimeTypePointer( - CORINFO_CLASS_HANDLE cls) -{ - return original_ICorJitInfo->getRuntimeTypePointer(cls); -} - -bool interceptor_ICJI::isObjectImmutable( - CORINFO_OBJECT_HANDLE objPtr) -{ - return original_ICorJitInfo->isObjectImmutable(objPtr); -} - -bool interceptor_ICJI::getStringChar( - CORINFO_OBJECT_HANDLE strObj, - int index, - uint16_t* value) -{ - return original_ICorJitInfo->getStringChar(strObj, index, value); -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getObjectType( - CORINFO_OBJECT_HANDLE objPtr) -{ - return original_ICorJitInfo->getObjectType(objPtr); -} - -bool interceptor_ICJI::getReadyToRunHelper( - CORINFO_RESOLVED_TOKEN* pResolvedToken, - CorInfoHelpFunc id, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_CONST_LOOKUP* pLookup) -{ - return original_ICorJitInfo->getReadyToRunHelper(pResolvedToken, id, callerHandle, pLookup); -} - -void interceptor_ICJI::getReadyToRunDelegateCtorHelper( - CORINFO_RESOLVED_TOKEN* pTargetMethod, - mdToken targetConstraint, - CORINFO_CLASS_HANDLE delegateType, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_LOOKUP* pLookup) -{ - original_ICorJitInfo->getReadyToRunDelegateCtorHelper(pTargetMethod, targetConstraint, delegateType, callerHandle, pLookup); -} - -CorInfoInitClassResult interceptor_ICJI::initClass( - CORINFO_FIELD_HANDLE field, - CORINFO_METHOD_HANDLE method, - CORINFO_CONTEXT_HANDLE context) -{ - return original_ICorJitInfo->initClass(field, method, context); -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getBuiltinClass( - CorInfoClassId classId) -{ - return original_ICorJitInfo->getBuiltinClass(classId); -} - -CorInfoType interceptor_ICJI::getTypeForPrimitiveValueClass( - CORINFO_CLASS_HANDLE cls) -{ - return original_ICorJitInfo->getTypeForPrimitiveValueClass(cls); -} - -CorInfoType interceptor_ICJI::getTypeForPrimitiveNumericClass( - CORINFO_CLASS_HANDLE cls) -{ - return original_ICorJitInfo->getTypeForPrimitiveNumericClass(cls); -} - -bool interceptor_ICJI::canCast( - CORINFO_CLASS_HANDLE child, - CORINFO_CLASS_HANDLE parent) -{ - return original_ICorJitInfo->canCast(child, parent); -} - -TypeCompareState interceptor_ICJI::compareTypesForCast( - CORINFO_CLASS_HANDLE fromClass, - CORINFO_CLASS_HANDLE toClass) -{ - return original_ICorJitInfo->compareTypesForCast(fromClass, toClass); -} - -TypeCompareState interceptor_ICJI::compareTypesForEquality( - CORINFO_CLASS_HANDLE cls1, - CORINFO_CLASS_HANDLE cls2) -{ - return original_ICorJitInfo->compareTypesForEquality(cls1, cls2); -} - -bool interceptor_ICJI::isMoreSpecificType( - CORINFO_CLASS_HANDLE cls1, - CORINFO_CLASS_HANDLE cls2) -{ - return original_ICorJitInfo->isMoreSpecificType(cls1, cls2); -} - -bool interceptor_ICJI::isExactType( - CORINFO_CLASS_HANDLE cls) -{ - return original_ICorJitInfo->isExactType(cls); -} - -TypeCompareState interceptor_ICJI::isGenericType( - CORINFO_CLASS_HANDLE cls) -{ - return original_ICorJitInfo->isGenericType(cls); -} - -TypeCompareState interceptor_ICJI::isNullableType( - CORINFO_CLASS_HANDLE cls) -{ - return original_ICorJitInfo->isNullableType(cls); -} - -TypeCompareState interceptor_ICJI::isEnum( - CORINFO_CLASS_HANDLE cls, - CORINFO_CLASS_HANDLE* underlyingType) -{ - return original_ICorJitInfo->isEnum(cls, underlyingType); -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getParentType( - CORINFO_CLASS_HANDLE cls) -{ - return original_ICorJitInfo->getParentType(cls); -} - -CorInfoType interceptor_ICJI::getChildType( - CORINFO_CLASS_HANDLE clsHnd, - CORINFO_CLASS_HANDLE* clsRet) -{ - return original_ICorJitInfo->getChildType(clsHnd, clsRet); -} - -bool interceptor_ICJI::isSDArray( - CORINFO_CLASS_HANDLE cls) -{ - return original_ICorJitInfo->isSDArray(cls); -} - -unsigned interceptor_ICJI::getArrayRank( - CORINFO_CLASS_HANDLE cls) -{ - return original_ICorJitInfo->getArrayRank(cls); -} - -CorInfoArrayIntrinsic interceptor_ICJI::getArrayIntrinsicID( - CORINFO_METHOD_HANDLE ftn) -{ - return original_ICorJitInfo->getArrayIntrinsicID(ftn); -} - -void* interceptor_ICJI::getArrayInitializationData( - CORINFO_FIELD_HANDLE field, - uint32_t size) -{ - return original_ICorJitInfo->getArrayInitializationData(field, size); -} - -CorInfoIsAccessAllowedResult interceptor_ICJI::canAccessClass( - CORINFO_RESOLVED_TOKEN* pResolvedToken, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_HELPER_DESC* pAccessHelper) -{ - return original_ICorJitInfo->canAccessClass(pResolvedToken, callerHandle, pAccessHelper); -} - -size_t interceptor_ICJI::printFieldName( - CORINFO_FIELD_HANDLE field, - char* buffer, - size_t bufferSize, - size_t* pRequiredBufferSize) -{ - return original_ICorJitInfo->printFieldName(field, buffer, bufferSize, pRequiredBufferSize); -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getFieldClass( - CORINFO_FIELD_HANDLE field) -{ - return original_ICorJitInfo->getFieldClass(field); -} - -CorInfoType interceptor_ICJI::getFieldType( - CORINFO_FIELD_HANDLE field, - CORINFO_CLASS_HANDLE* structType, - CORINFO_CLASS_HANDLE fieldOwnerHint) -{ - return original_ICorJitInfo->getFieldType(field, structType, fieldOwnerHint); -} - -unsigned interceptor_ICJI::getFieldOffset( - CORINFO_FIELD_HANDLE field) -{ - return original_ICorJitInfo->getFieldOffset(field); -} - -void interceptor_ICJI::getFieldInfo( - CORINFO_RESOLVED_TOKEN* pResolvedToken, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_ACCESS_FLAGS flags, - CORINFO_FIELD_INFO* pResult) -{ - original_ICorJitInfo->getFieldInfo(pResolvedToken, callerHandle, flags, pResult); -} - -uint32_t interceptor_ICJI::getThreadLocalFieldInfo( - CORINFO_FIELD_HANDLE field, - bool isGCtype) -{ - return original_ICorJitInfo->getThreadLocalFieldInfo(field, isGCtype); -} - -void interceptor_ICJI::getThreadLocalStaticBlocksInfo( - CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) -{ - original_ICorJitInfo->getThreadLocalStaticBlocksInfo(pInfo); -} - -void interceptor_ICJI::getThreadLocalStaticInfo_NativeAOT( - CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo) -{ - original_ICorJitInfo->getThreadLocalStaticInfo_NativeAOT(pInfo); -} - -bool interceptor_ICJI::isFieldStatic( - CORINFO_FIELD_HANDLE fldHnd) -{ - return original_ICorJitInfo->isFieldStatic(fldHnd); -} - -int interceptor_ICJI::getArrayOrStringLength( - CORINFO_OBJECT_HANDLE objHnd) -{ - return original_ICorJitInfo->getArrayOrStringLength(objHnd); -} - -void interceptor_ICJI::getBoundaries( - CORINFO_METHOD_HANDLE ftn, - unsigned int* cILOffsets, - uint32_t** pILOffsets, - ICorDebugInfo::BoundaryTypes* implicitBoundaries) -{ - original_ICorJitInfo->getBoundaries(ftn, cILOffsets, pILOffsets, implicitBoundaries); -} - -void interceptor_ICJI::setBoundaries( - CORINFO_METHOD_HANDLE ftn, - uint32_t cMap, - ICorDebugInfo::OffsetMapping* pMap) -{ - original_ICorJitInfo->setBoundaries(ftn, cMap, pMap); -} - -void interceptor_ICJI::getVars( - CORINFO_METHOD_HANDLE ftn, - uint32_t* cVars, - ICorDebugInfo::ILVarInfo** vars, - bool* extendOthers) -{ - original_ICorJitInfo->getVars(ftn, cVars, vars, extendOthers); -} - -void interceptor_ICJI::setVars( - CORINFO_METHOD_HANDLE ftn, - uint32_t cVars, - ICorDebugInfo::NativeVarInfo* vars) -{ - original_ICorJitInfo->setVars(ftn, cVars, vars); -} - -void interceptor_ICJI::reportRichMappings( - ICorDebugInfo::InlineTreeNode* inlineTreeNodes, - uint32_t numInlineTreeNodes, - ICorDebugInfo::RichOffsetMapping* mappings, - uint32_t numMappings) -{ - original_ICorJitInfo->reportRichMappings(inlineTreeNodes, numInlineTreeNodes, mappings, numMappings); -} - -void interceptor_ICJI::reportAsyncDebugInfo( - ICorDebugInfo::AsyncInfo* asyncInfo, - ICorDebugInfo::AsyncSuspensionPoint* suspensionPoints, - ICorDebugInfo::AsyncContinuationVarInfo* vars, - uint32_t numVars) -{ - original_ICorJitInfo->reportAsyncDebugInfo(asyncInfo, suspensionPoints, vars, numVars); -} - -void interceptor_ICJI::reportMetadata( - const char* key, - const void* value, - size_t length) -{ - original_ICorJitInfo->reportMetadata(key, value, length); -} - -void* interceptor_ICJI::allocateArray( - size_t cBytes) -{ - return original_ICorJitInfo->allocateArray(cBytes); -} - -void interceptor_ICJI::freeArray( - void* array) -{ - original_ICorJitInfo->freeArray(array); -} - -CORINFO_ARG_LIST_HANDLE interceptor_ICJI::getArgNext( - CORINFO_ARG_LIST_HANDLE args) -{ - return original_ICorJitInfo->getArgNext(args); -} - -CorInfoTypeWithMod interceptor_ICJI::getArgType( - CORINFO_SIG_INFO* sig, - CORINFO_ARG_LIST_HANDLE args, - CORINFO_CLASS_HANDLE* vcTypeRet) -{ - return original_ICorJitInfo->getArgType(sig, args, vcTypeRet); -} - -int interceptor_ICJI::getExactClasses( - CORINFO_CLASS_HANDLE baseType, - int maxExactClasses, - CORINFO_CLASS_HANDLE* exactClsRet) -{ - return original_ICorJitInfo->getExactClasses(baseType, maxExactClasses, exactClsRet); -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getArgClass( - CORINFO_SIG_INFO* sig, - CORINFO_ARG_LIST_HANDLE args) -{ - return original_ICorJitInfo->getArgClass(sig, args); -} - -CorInfoHFAElemType interceptor_ICJI::getHFAType( - CORINFO_CLASS_HANDLE hClass) -{ - return original_ICorJitInfo->getHFAType(hClass); -} - -bool interceptor_ICJI::runWithErrorTrap( - ICorJitInfo::errorTrapFunction function, - void* parameter) -{ - return original_ICorJitInfo->runWithErrorTrap(function, parameter); -} - -bool interceptor_ICJI::runWithSPMIErrorTrap( - ICorJitInfo::errorTrapFunction function, - void* parameter) -{ - return original_ICorJitInfo->runWithSPMIErrorTrap(function, parameter); -} - -void interceptor_ICJI::getEEInfo( - CORINFO_EE_INFO* pEEInfoOut) -{ - original_ICorJitInfo->getEEInfo(pEEInfoOut); -} - -void interceptor_ICJI::getAsyncInfo( - CORINFO_ASYNC_INFO* pAsyncInfoOut) -{ - original_ICorJitInfo->getAsyncInfo(pAsyncInfoOut); -} - -CORINFO_METHOD_HANDLE interceptor_ICJI::getAwaitReturnCall( - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_CONTEXT_HANDLE* contextHandle, - CORINFO_LOOKUP* instArg) -{ - return original_ICorJitInfo->getAwaitReturnCall(callerHandle, contextHandle, instArg); -} - -CORINFO_METHOD_HANDLE interceptor_ICJI::getAwaitAwaiterInContinuationCall( - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_RESOLVED_TOKEN* pResolvedToken, - bool isUnsafe, - CORINFO_CONTEXT_HANDLE* contextHandle, - CORINFO_LOOKUP* instArg) -{ - return original_ICorJitInfo->getAwaitAwaiterInContinuationCall(callerHandle, pResolvedToken, isUnsafe, contextHandle, instArg); -} - -mdMethodDef interceptor_ICJI::getMethodDefFromMethod( - CORINFO_METHOD_HANDLE hMethod) -{ - return original_ICorJitInfo->getMethodDefFromMethod(hMethod); -} - -size_t interceptor_ICJI::printMethodName( - CORINFO_METHOD_HANDLE ftn, - char* buffer, - size_t bufferSize, - size_t* pRequiredBufferSize) -{ - return original_ICorJitInfo->printMethodName(ftn, buffer, bufferSize, pRequiredBufferSize); -} - -const char* interceptor_ICJI::getMethodNameFromMetadata( - CORINFO_METHOD_HANDLE ftn, - const char** className, - const char** namespaceName, - const char** enclosingClassNames, - size_t maxEnclosingClassNames) -{ - return original_ICorJitInfo->getMethodNameFromMetadata(ftn, className, namespaceName, enclosingClassNames, maxEnclosingClassNames); -} - -unsigned interceptor_ICJI::getMethodHash( - CORINFO_METHOD_HANDLE ftn) -{ - return original_ICorJitInfo->getMethodHash(ftn); -} - -bool interceptor_ICJI::getSystemVAmd64PassStructInRegisterDescriptor( - CORINFO_CLASS_HANDLE structHnd, - SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr) -{ - return original_ICorJitInfo->getSystemVAmd64PassStructInRegisterDescriptor(structHnd, structPassInRegDescPtr); -} - -void interceptor_ICJI::getSwiftLowering( - CORINFO_CLASS_HANDLE structHnd, - CORINFO_SWIFT_LOWERING* pLowering) -{ - original_ICorJitInfo->getSwiftLowering(structHnd, pLowering); -} - -void interceptor_ICJI::getFpStructLowering( - CORINFO_CLASS_HANDLE structHnd, - CORINFO_FPSTRUCT_LOWERING* pLowering) -{ - original_ICorJitInfo->getFpStructLowering(structHnd, pLowering); -} - -CorInfoWasmType interceptor_ICJI::getWasmLowering( - CORINFO_CLASS_HANDLE structHnd) -{ - return original_ICorJitInfo->getWasmLowering(structHnd); -} - -uint32_t interceptor_ICJI::getAddressAlignment( - void* address) -{ - return original_ICorJitInfo->getAddressAlignment(address); -} - -void interceptor_ICJI::getWasmWellKnownGlobals( - CORINFO_WASM_WELLKNOWN_GLOBALS* pWellKnownGlobalsOut) -{ - original_ICorJitInfo->getWasmWellKnownGlobals(pWellKnownGlobalsOut); -} - -uint32_t interceptor_ICJI::getThreadTLSIndex( - void** ppIndirection) -{ - return original_ICorJitInfo->getThreadTLSIndex(ppIndirection); -} - -int32_t* interceptor_ICJI::getAddrOfCaptureThreadGlobal( - void** ppIndirection) -{ - return original_ICorJitInfo->getAddrOfCaptureThreadGlobal(ppIndirection); -} - -void interceptor_ICJI::getHelperFtn( - CorInfoHelpFunc ftnNum, - CORINFO_CONST_LOOKUP* pNativeEntrypoint, - CORINFO_METHOD_HANDLE* pMethod) -{ - original_ICorJitInfo->getHelperFtn(ftnNum, pNativeEntrypoint, pMethod); -} - -void interceptor_ICJI::getFunctionEntryPoint( - CORINFO_METHOD_HANDLE ftn, - CORINFO_CONST_LOOKUP* pResult, - CORINFO_ACCESS_FLAGS accessFlags) -{ - original_ICorJitInfo->getFunctionEntryPoint(ftn, pResult, accessFlags); -} - -void interceptor_ICJI::getFunctionFixedEntryPoint( - CORINFO_METHOD_HANDLE ftn, - bool isUnsafeFunctionPointer, - CORINFO_CONST_LOOKUP* pResult) -{ - original_ICorJitInfo->getFunctionFixedEntryPoint(ftn, isUnsafeFunctionPointer, pResult); -} - -CORINFO_MODULE_HANDLE interceptor_ICJI::embedModuleHandle( - CORINFO_MODULE_HANDLE handle, - void** ppIndirection) -{ - return original_ICorJitInfo->embedModuleHandle(handle, ppIndirection); -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::embedClassHandle( - CORINFO_CLASS_HANDLE handle, - void** ppIndirection) -{ - return original_ICorJitInfo->embedClassHandle(handle, ppIndirection); -} - -CORINFO_METHOD_HANDLE interceptor_ICJI::embedMethodHandle( - CORINFO_METHOD_HANDLE handle, - void** ppIndirection) -{ - return original_ICorJitInfo->embedMethodHandle(handle, ppIndirection); -} - -CORINFO_FIELD_HANDLE interceptor_ICJI::embedFieldHandle( - CORINFO_FIELD_HANDLE handle, - void** ppIndirection) -{ - return original_ICorJitInfo->embedFieldHandle(handle, ppIndirection); -} - -void interceptor_ICJI::embedGenericHandle( - CORINFO_RESOLVED_TOKEN* pResolvedToken, - bool fEmbedParent, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_GENERICHANDLE_RESULT* pResult) -{ - original_ICorJitInfo->embedGenericHandle(pResolvedToken, fEmbedParent, callerHandle, pResult); -} - -void interceptor_ICJI::getLocationOfThisType( - CORINFO_METHOD_HANDLE context, - CORINFO_LOOKUP_KIND* pLookupKind) -{ - original_ICorJitInfo->getLocationOfThisType(context, pLookupKind); -} - -void interceptor_ICJI::getAddressOfPInvokeTarget( - CORINFO_METHOD_HANDLE method, - CORINFO_CONST_LOOKUP* pLookup) -{ - original_ICorJitInfo->getAddressOfPInvokeTarget(method, pLookup); -} - -void* interceptor_ICJI::GetCookieForInterpreterCalliSig( - CORINFO_SIG_INFO* szMetaSig) -{ - return original_ICorJitInfo->GetCookieForInterpreterCalliSig(szMetaSig); -} - -CORINFO_JUST_MY_CODE_HANDLE interceptor_ICJI::getJustMyCodeHandle( - CORINFO_METHOD_HANDLE method, - CORINFO_JUST_MY_CODE_HANDLE** ppIndirection) -{ - return original_ICorJitInfo->getJustMyCodeHandle(method, ppIndirection); -} - -void interceptor_ICJI::GetProfilingHandle( - bool* pbHookFunction, - void** pProfilerHandle, - bool* pbIndirectedHandles) -{ - original_ICorJitInfo->GetProfilingHandle(pbHookFunction, pProfilerHandle, pbIndirectedHandles); -} - -void interceptor_ICJI::getCallInfo( - CORINFO_RESOLVED_TOKEN* pResolvedToken, - CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_CALLINFO_FLAGS flags, - CORINFO_CALL_INFO* pResult) -{ - original_ICorJitInfo->getCallInfo(pResolvedToken, pConstrainedResolvedToken, callerHandle, flags, pResult); -} - -bool interceptor_ICJI::getStaticFieldContent( - CORINFO_FIELD_HANDLE field, - uint8_t* buffer, - int bufferSize, - int valueOffset, - bool ignoreMovableObjects) -{ - return original_ICorJitInfo->getStaticFieldContent(field, buffer, bufferSize, valueOffset, ignoreMovableObjects); -} - -bool interceptor_ICJI::getObjectContent( - CORINFO_OBJECT_HANDLE obj, - uint8_t* buffer, - int bufferSize, - int valueOffset) -{ - return original_ICorJitInfo->getObjectContent(obj, buffer, bufferSize, valueOffset); -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getStaticFieldCurrentClass( - CORINFO_FIELD_HANDLE field, - bool* pIsSpeculative) -{ - return original_ICorJitInfo->getStaticFieldCurrentClass(field, pIsSpeculative); -} - -CORINFO_VARARGS_HANDLE interceptor_ICJI::getVarArgsHandle( - CORINFO_SIG_INFO* pSig, - CORINFO_METHOD_HANDLE methHnd, - void** ppIndirection) -{ - return original_ICorJitInfo->getVarArgsHandle(pSig, methHnd, ppIndirection); -} - -InfoAccessType interceptor_ICJI::constructStringLiteral( - CORINFO_MODULE_HANDLE module, - mdToken metaTok, - void** ppValue) -{ - return original_ICorJitInfo->constructStringLiteral(module, metaTok, ppValue); -} - -InfoAccessType interceptor_ICJI::emptyStringLiteral( - void** ppValue) -{ - return original_ICorJitInfo->emptyStringLiteral(ppValue); -} - -uint32_t interceptor_ICJI::getFieldThreadLocalStoreID( - CORINFO_FIELD_HANDLE field, - void** ppIndirection) -{ - return original_ICorJitInfo->getFieldThreadLocalStoreID(field, ppIndirection); -} - -CORINFO_METHOD_HANDLE interceptor_ICJI::GetDelegateCtor( - CORINFO_METHOD_HANDLE methHnd, - CORINFO_CLASS_HANDLE clsHnd, - CORINFO_METHOD_HANDLE targetMethodHnd, - DelegateCtorArgs* pCtorData) -{ - return original_ICorJitInfo->GetDelegateCtor(methHnd, clsHnd, targetMethodHnd, pCtorData); -} - -void interceptor_ICJI::MethodCompileComplete( - CORINFO_METHOD_HANDLE methHnd) -{ - original_ICorJitInfo->MethodCompileComplete(methHnd); -} - -bool interceptor_ICJI::getTailCallHelpers( - CORINFO_RESOLVED_TOKEN* callToken, - CORINFO_SIG_INFO* sig, - CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, - CORINFO_TAILCALL_HELPERS* pResult) -{ - return original_ICorJitInfo->getTailCallHelpers(callToken, sig, flags, pResult); -} - -CORINFO_CLASS_HANDLE interceptor_ICJI::getContinuationType( - size_t dataSize, - bool* objRefs, - size_t objRefsSize) -{ - return original_ICorJitInfo->getContinuationType(dataSize, objRefs, objRefsSize); -} - -CORINFO_METHOD_HANDLE interceptor_ICJI::getAsyncResumptionStub( - void** entryPoint) -{ - return original_ICorJitInfo->getAsyncResumptionStub(entryPoint); -} - -bool interceptor_ICJI::convertPInvokeCalliToCall( - CORINFO_RESOLVED_TOKEN* pResolvedToken, - bool mustConvert) -{ - return original_ICorJitInfo->convertPInvokeCalliToCall(pResolvedToken, mustConvert); -} - -bool interceptor_ICJI::notifyInstructionSetUsage( - CORINFO_InstructionSet instructionSet, - bool supportEnabled, - bool preserveNegativeDependency) -{ - return original_ICorJitInfo->notifyInstructionSetUsage(instructionSet, supportEnabled, preserveNegativeDependency); -} - -void interceptor_ICJI::updateEntryPointForTailCall( - CORINFO_CONST_LOOKUP* entryPoint) -{ - original_ICorJitInfo->updateEntryPointForTailCall(entryPoint); -} - -void interceptor_ICJI::allocMem( - AllocMemArgs* pArgs) -{ - original_ICorJitInfo->allocMem(pArgs); -} - -void interceptor_ICJI::reserveUnwindInfo( - bool isFunclet, - bool isColdCode, - uint32_t unwindSize) -{ - original_ICorJitInfo->reserveUnwindInfo(isFunclet, isColdCode, unwindSize); -} - -void interceptor_ICJI::allocUnwindInfo( - uint8_t* pHotCode, - uint8_t* pColdCode, - uint32_t startOffset, - uint32_t endOffset, - uint32_t unwindSize, - uint8_t* pUnwindBlock, - CorJitFuncKind funcKind) -{ - original_ICorJitInfo->allocUnwindInfo(pHotCode, pColdCode, startOffset, endOffset, unwindSize, pUnwindBlock, funcKind); -} - -void* interceptor_ICJI::allocGCInfo( - size_t size) -{ - return original_ICorJitInfo->allocGCInfo(size); -} - -void interceptor_ICJI::setEHcount( - unsigned cEH) -{ - original_ICorJitInfo->setEHcount(cEH); -} - -void interceptor_ICJI::setEHinfo( - unsigned EHnumber, - const CORINFO_EH_CLAUSE* clause) -{ - original_ICorJitInfo->setEHinfo(EHnumber, clause); -} - -bool interceptor_ICJI::logMsg( - unsigned level, - const char* fmt, - va_list args) -{ - return original_ICorJitInfo->logMsg(level, fmt, args); -} - -int interceptor_ICJI::doAssert( - const char* szFile, - int iLine, - const char* szExpr) -{ - return original_ICorJitInfo->doAssert(szFile, iLine, szExpr); -} - -void interceptor_ICJI::reportFatalError( - CorJitResult result) -{ - original_ICorJitInfo->reportFatalError(result); -} - -JITINTERFACE_HRESULT interceptor_ICJI::getPgoInstrumentationResults( - CORINFO_METHOD_HANDLE ftnHnd, - ICorJitInfo::PgoInstrumentationSchema** pSchema, - uint32_t* pCountSchemaItems, - uint8_t** pInstrumentationData, - ICorJitInfo::PgoSource* pPgoSource, - bool* pDynamicPgo) -{ - return original_ICorJitInfo->getPgoInstrumentationResults(ftnHnd, pSchema, pCountSchemaItems, pInstrumentationData, pPgoSource, pDynamicPgo); -} - -JITINTERFACE_HRESULT interceptor_ICJI::allocPgoInstrumentationBySchema( - CORINFO_METHOD_HANDLE ftnHnd, - ICorJitInfo::PgoInstrumentationSchema* pSchema, - uint32_t countSchemaItems, - uint8_t** pInstrumentationData) -{ - return original_ICorJitInfo->allocPgoInstrumentationBySchema(ftnHnd, pSchema, countSchemaItems, pInstrumentationData); -} - -void interceptor_ICJI::recordCallSite( - uint32_t instrOffset, - CORINFO_SIG_INFO* callSig, - CORINFO_METHOD_HANDLE methodHandle) -{ - original_ICorJitInfo->recordCallSite(instrOffset, callSig, methodHandle); -} - -void interceptor_ICJI::recordWasmManagedCallSig( - CORINFO_SIG_INFO* callSig) -{ - original_ICorJitInfo->recordWasmManagedCallSig(callSig); -} - -void interceptor_ICJI::recordRelocation( - void* location, - void* locationRW, - void* target, - CorInfoReloc fRelocType, - int32_t addlDelta) -{ - original_ICorJitInfo->recordRelocation(location, locationRW, target, fRelocType, addlDelta); -} - -CorInfoReloc interceptor_ICJI::getRelocTypeHint( - void* target) -{ - return original_ICorJitInfo->getRelocTypeHint(target); -} - -uint32_t interceptor_ICJI::getExpectedTargetArchitecture() -{ - return original_ICorJitInfo->getExpectedTargetArchitecture(); -} - -uint32_t interceptor_ICJI::getJitFlags( - CORJIT_FLAGS* flags, - uint32_t sizeInBytes) -{ - return original_ICorJitInfo->getJitFlags(flags, sizeInBytes); -} - -CORINFO_WASM_TYPE_SYMBOL_HANDLE interceptor_ICJI::getWasmTypeSymbol( - CorInfoWasmType* types, - size_t typesSize) -{ - return original_ICorJitInfo->getWasmTypeSymbol(types, typesSize); -} - -CORINFO_METHOD_HANDLE interceptor_ICJI::getSpecialCopyHelper( - CORINFO_CLASS_HANDLE type) -{ - return original_ICorJitInfo->getSpecialCopyHelper(type); -} - diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/jithost.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/jithost.cpp deleted file mode 100644 index 43c7c2e0ae1e40..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/jithost.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "standardpch.h" -#include "runtimedetails.h" -#include "spmiutil.h" -#include "jithost.h" - -JitHost* g_ourJitHost; - -JitHost::JitHost(ICorJitHost* wrappedHost) : wrappedHost(wrappedHost) -{ -} - -void* JitHost::allocateMemory(size_t size) -{ - return wrappedHost->allocateMemory(size); -} - -void JitHost::freeMemory(void* block) -{ - return wrappedHost->freeMemory(block); -} - -int JitHost::getIntConfigValue(const char* key, int defaultValue) -{ - return wrappedHost->getIntConfigValue(key, defaultValue); -} - -const char* JitHost::getStringConfigValue(const char* key) -{ - return wrappedHost->getStringConfigValue(key); -} - -void JitHost::freeStringConfigValue(const char* value) -{ - wrappedHost->freeStringConfigValue(value); -} diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/jithost.h b/src/coreclr/tools/superpmi/superpmi-shim-simple/jithost.h deleted file mode 100644 index a12d377dd79b3a..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/jithost.h +++ /dev/null @@ -1,20 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#ifndef _JITHOST -#define _JITHOST - -class JitHost : public ICorJitHost -{ -public: - JitHost(ICorJitHost* wrappedHost); - -#include "icorjithostimpl.h" - -private: - ICorJitHost* wrappedHost; -}; - -extern JitHost* g_ourJitHost; - -#endif diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/superpmi-shim-simple.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/superpmi-shim-simple.cpp deleted file mode 100644 index 2cc1ef2a268170..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/superpmi-shim-simple.cpp +++ /dev/null @@ -1,152 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// SuperPMI-Shim.cpp - thin shim for the jit -//---------------------------------------------------------- - -#include "standardpch.h" -#include "superpmi-shim-simple.h" -#include "runtimedetails.h" -#include "icorjitcompiler.h" -#include "errorhandling.h" -#include "logging.h" -#include "spmiutil.h" -#include "jithost.h" - - -HMODULE g_hRealJit = 0; // We leak this currently (could do the proper shutdown in process_detach) -std::string g_realJitPath{""}; // Destructable objects will be cleaned up and won't leak -std::string g_logPath{""}; -std::string g_HomeDirectory{""}; -std::string g_DefaultRealJitPath{""}; - -// RAII holder for logger -// Global deconstructors are unreliable. We only use it for superpmi shim. -class LoggerHolder -{ -public: - LoggerHolder() - { - Logger::Initialize(); - // If the environment variable isn't set, we don't enable file logging - const char* logFilePath = GetEnvWithDefault("SuperPMIShimLogFilePath", nullptr); - if (logFilePath) - { - Logger::OpenLogFile(logFilePath); - } - } - - ~LoggerHolder() - { - Logger::Shutdown(); - } -} loggerHolder; - -void SetDefaultPaths() -{ - if (g_HomeDirectory.empty()) - { - g_HomeDirectory = GetEnvWithDefault("HOME", "."); - } - - if (g_DefaultRealJitPath.empty()) - { - g_DefaultRealJitPath = g_HomeDirectory + DIRECTORY_SEPARATOR_CHAR_A + DEFAULT_REAL_JIT_NAME_A; - } -} - -void SetLibName() -{ - if (g_realJitPath.empty()) - { - g_realJitPath = GetEnvWithDefault("SuperPMIShimPath", g_DefaultRealJitPath.c_str()); - } -} - -extern "C" -#ifdef HOST_UNIX - DLLEXPORT // For Win32 PAL LoadLibrary emulation -#endif - BOOL - DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) -{ - switch (ul_reason_for_call) - { - case DLL_PROCESS_ATTACH: -#ifdef HOST_UNIX - if (0 != PAL_InitializeDLL()) - { - fprintf(stderr, "Error: Fail to PAL_InitializeDLL\n"); - exit(1); - } -#endif // HOST_UNIX - break; - - case DLL_PROCESS_DETACH: - case DLL_THREAD_ATTACH: - case DLL_THREAD_DETACH: - break; - } - return TRUE; -} - -extern "C" DLLEXPORT void jitStartup(ICorJitHost* host) -{ - SetDefaultPaths(); - SetLibName(); - SetDebugDumpVariables(); - - if (!LoadRealJitLib(g_hRealJit, g_realJitPath)) - { - return; - } - - // Get the required entrypoint - PjitStartup pnjitStartup = (PjitStartup)GET_PROC_ADDRESS(g_hRealJit, "jitStartup"); - if (pnjitStartup == nullptr) - { - // This portion of the interface is not used by the JIT under test. - g_ourJitHost = nullptr; - return; - } - - g_ourJitHost = new JitHost(host); - pnjitStartup(g_ourJitHost); -} - -extern "C" DLLEXPORT ICorJitCompiler* getJit() -{ - DWORD dwRetVal = 0; - PgetJit pngetJit; - interceptor_ICJC* pJitInstance = nullptr; - ICorJitCompiler* tICJI = nullptr; - - SetDefaultPaths(); - SetLibName(); - SetDebugDumpVariables(); - - if (!LoadRealJitLib(g_hRealJit, g_realJitPath)) - { - return nullptr; - } - - // get the required entrypoints - pngetJit = (PgetJit)GET_PROC_ADDRESS(g_hRealJit, "getJit"); - if (pngetJit == 0) - { - LogError("getJit() - GetProcAddress 'getJit' failed (0x%08x)", ::GetLastError()); - return nullptr; - } - - tICJI = pngetJit(); - if (tICJI == nullptr) - { - LogError("getJit() - pngetJit gave us null"); - return nullptr; - } - - pJitInstance = new interceptor_ICJC(); - pJitInstance->original_ICorJitCompiler = tICJI; - return pJitInstance; -} diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/superpmi-shim-simple.def b/src/coreclr/tools/superpmi/superpmi-shim-simple/superpmi-shim-simple.def deleted file mode 100644 index f00334b07ef670..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/superpmi-shim-simple.def +++ /dev/null @@ -1,4 +0,0 @@ -LIBRARY -EXPORTS - getJit - jitStartup diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/superpmi-shim-simple.h b/src/coreclr/tools/superpmi/superpmi-shim-simple/superpmi-shim-simple.h deleted file mode 100644 index 3634f3ee72cbf9..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/superpmi-shim-simple.h +++ /dev/null @@ -1,10 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// SuperPMI-Shim.h - thin shim for the jit -//---------------------------------------------------------- -#ifndef _SuperPMIShim -#define _SuperPMIShim - -#endif diff --git a/src/coreclr/tools/superpmi/superpmi/CMakeLists.txt b/src/coreclr/tools/superpmi/superpmi/CMakeLists.txt deleted file mode 100644 index 2b93a45c7c9eb9..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi/CMakeLists.txt +++ /dev/null @@ -1,80 +0,0 @@ -project(superpmi) - -remove_definitions(-DUNICODE) -remove_definitions(-D_UNICODE) - -add_definitions(-DFEATURE_NO_HOST) -add_definitions(-DSELF_NO_HOST) -add_definitions(-DUSE_COREDISTOOLS) - -if(CLR_CMAKE_HOST_WIN32) - #use static crt - set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded) -endif(CLR_CMAKE_HOST_WIN32) - -if(CLR_CMAKE_HOST_UNIX) - # Make sure a public symbol is created for Instrumentor_GetInsCount - if(CLR_CMAKE_HOST_APPLE) - add_linker_flag(-Wl,-export_dynamic) - else() - add_linker_flag(-Wl,--export-dynamic) - endif(CLR_CMAKE_HOST_APPLE) -endif(CLR_CMAKE_HOST_UNIX) - -include_directories(.) -include_directories(../superpmi-shared) - -set(SUPERPMI_SOURCES - commandline.cpp - cycletimer.cpp - icorjitinfo.cpp - jitdebugger.cpp - jitinstance.cpp - methodstatsemitter.cpp - neardiffer.cpp - parallelsuperpmi.cpp - streamingsuperpmi.cpp - superpmi.cpp - fileio.cpp - jithost.cpp - ../superpmi-shared/callutils.cpp - ../superpmi-shared/compileresult.cpp - ../superpmi-shared/errorhandling.cpp - ../superpmi-shared/hash.cpp - ../superpmi-shared/logging.cpp - ../superpmi-shared/mclist.cpp - ../superpmi-shared/methodcontext.cpp - ../superpmi-shared/methodcontextreader.cpp - ../superpmi-shared/simpletimer.cpp - ../superpmi-shared/spmiutil.cpp - ../superpmi-shared/tocfile.cpp - ../superpmi-shared/typeutils.cpp - ../superpmi-shared/spmidumphelper.cpp -) - -add_executable_clr(superpmi - ${SUPERPMI_SOURCES} -) - -target_precompile_headers(superpmi PRIVATE "$<$:standardpch.h>") - -if(CLR_CMAKE_HOST_UNIX) - target_link_libraries(superpmi - PRIVATE - utilcodestaticnohost - mscorrc - coreclrpal - coreclrminipal - ) -else() - target_link_libraries(superpmi - PRIVATE - version.lib - advapi32.lib - coreclrminipal - ${STATIC_MT_CRT_LIB} - ${STATIC_MT_CPP_LIB} - ) -endif(CLR_CMAKE_HOST_UNIX) - -install_clr(TARGETS superpmi DESTINATIONS . COMPONENT spmi) diff --git a/src/coreclr/tools/superpmi/superpmi/commandline.cpp b/src/coreclr/tools/superpmi/superpmi/commandline.cpp deleted file mode 100644 index cf27a6b186e51e..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi/commandline.cpp +++ /dev/null @@ -1,952 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// CommandLine.cpp - tiny very specific command line parser -//---------------------------------------------------------- - -#include "standardpch.h" -#include "lightweightmap.h" -#include "commandline.h" -#include "superpmi.h" -#include "mclist.h" -#include "methodcontext.h" -#include "logging.h" -#include "spmiutil.h" - -// NOTE: this is parsed by parallelsuperpmi.cpp::ProcessChildStdOut() to determine if an incorrect -// argument usage error has occurred. -const char* const g_SuperPMIUsageFirstLine = "SuperPMI is a JIT compiler testing tool."; - -void CommandLine::DumpHelp(const char* program) -{ - printf("%s\n", g_SuperPMIUsageFirstLine); - printf("\n"); - printf("Usage: %s [options] [jitname] [jitname2] filename.mc\n", program); - printf(" jitname" PLATFORM_SHARED_LIB_SUFFIX_A " - optional path of jit to be tested (default is JIT in same directory as %s)\n", program); - printf(" jitname2" PLATFORM_SHARED_LIB_SUFFIX_A " - optional path of second jit to be tested\n"); - printf(" filename.mc - load method contexts from filename.mc\n"); - printf(" -j[it] Name - optionally -jit can be used to specify jits\n"); - printf(" -l[oad] filename - optionally -load can be used to specify method contexts\n"); - printf("\n"); - printf("Options:\n"); - printf("\n"); - printf(" -boe\n"); - printf(" Break on error return from compileMethod\n"); - printf("\n"); - printf(" -boa\n"); - printf(" Break on assert from the JIT\n"); - printf("\n"); - printf(" -box\n"); - printf(" Break on exception thrown, such as for missing data during replay\n"); - printf("\n"); - printf(" -ignoreStoredConfig\n"); - printf(" On replay, ignore any stored configuration variables. Useful for Checked/Release asm diffs.\n"); - printf("\n"); - printf(" -v[erbosity] messagetypes\n"); - printf(" Controls which types of messages SuperPMI logs. Specify a string of\n"); - printf(" characters representing message categories to enable, where:\n"); - printf(" e - errors (internal fatal errors that are non-recoverable)\n"); - printf(" w - warnings (internal conditions that are unusual, but not serious)\n"); - printf(" m - missing (failures due to missing JIT-EE interface details)\n"); - printf(" i - issues (issues found with the JIT, e.g. asm diffs, asserts)\n"); - printf(" n - information (notifications/summaries, e.g. 'Loaded 5 Jitted 4 FailedCompile 1')\n"); - printf(" v - verbose (status messages, e.g. 'Jit startup took '151.12ms')\n"); - printf(" d - debug (lots of detailed output)\n"); - printf(" a - all (enable all message types; overrides other enable message types)\n"); - printf(" q - quiet (disable all output; overrides all others)\n"); - printf(" e.g. '-v ew' only writes error and warning messages to the console.\n"); - printf(" 'q' takes precedence over any other message type specified.\n"); - printf(" Default set of messages enabled is 'ewminv'.\n"); - printf("\n"); - printf(" -w[riteLogFile] logfile\n"); - printf(" Write log messages to the specified file.\n"); - printf("\n"); - printf(" -c[ompile] \n"); - printf(" Compile only those method contexts whose indices are specified.\n"); - printf(" Indices can be either a single index, comma separated values,\n"); - printf(" a range, or the name of a .MCL file with newline delimited indices.\n"); - printf(" e.g. -compile 20\n"); - printf(" e.g. -compile 20,25,30,32\n"); - printf(" e.g. -compile 10-99\n"); - printf(" e.g. -compile 5,10-99,101,201-300\n"); - printf(" e.g. -compile failed.mcl\n"); - printf("\n"); - printf(" -m[atchHash] \n"); - printf(" Compile only method context with specific MD5 hash\n"); - printf("\n"); - printf(" -e[mitMethodStats] \n"); - printf(" Emit method statistics in CSV format to filename.mc.stats.\n"); - printf(" Specify a string of characters representing statistics to emit, where:\n"); - printf(" i - method IL code size\n"); - printf(" a - method compiled ASM code size\n"); - printf(" h - method hash to uniquely identify a method across MCH files\n"); - printf(" n - method number inside the source MCH\n"); - printf(" t - method throughput time\n"); - printf(" * - all available method stats\n"); - printf("\n"); - printf(" -details \n"); - printf(" Emit detailed information about the replay/diff of each context into the specified file\n"); - printf("\n"); - printf(" -a[pplyDiff]\n"); - printf(" Compare the compile result generated from the provided JIT with the\n"); - printf(" compile result stored with the MC. If two JITs are provided, this\n"); - printf(" compares the compile results generated by the two JITs.\n"); - printf("\n"); - printf(" -r[eproName] prefix\n"); - printf(" Write out failing methods to prefix-n.mc\n"); - printf("\n"); - printf(" -f[ailingMCList] mclfilename\n"); - printf(" Write out failing methods to mclfilename.\n"); - printf(" If using -applyDiff and no -diffMCList is specified,\n"); - printf(" comparison failures also get written to mclfilename.\n"); - printf("\n"); - printf(" -diffMCList diffMCLfilename\n"); - printf(" Write out methods that differ between compilations to diffMCLfilename.\n"); - printf(" This only works with -applyDiff.\n"); - printf("\n"); - printf(" -p[arallel] [workerCount]\n"); - printf(" Run in parallel mode by spawning 'workerCount' processes to do processing.\n"); - printf(" If 'workerCount' is not specified, the number of workers used is\n"); - printf(" the number of processors on the machine.\n"); - printf("\n"); - printf(" -streaming filename\n"); - printf(" Streaming mode. Read and execute work requests from indicated file (can be 'stdin').\n"); - printf(" Each line is a method context number and additional force jit options for that method.\n"); - printf(" Blank line or EOF terminates\n"); - printf("\n"); - printf(" -failureLimit \n"); - printf(" For a positive 'limit' number, replay and asm diffs will exit if it sees more than 'limit' failures.\n"); - printf(" Otherwise, all methods will be compiled.\n"); - printf("\n"); - printf(" -skipCleanup\n"); - printf(" Skip deletion of temporary files created by child SuperPMI processes with -parallel.\n"); - printf("\n"); - printf(" -repeatCount \n"); - printf(" Number of times compilation should repeat for each method context. Usually used when\n"); - printf(" trying to measure JIT throughput for a specific set of methods. Default=1.\n"); - printf("\n"); - printf(" -target \n"); - printf(" Specifies the target architecture if doing cross-compilation.\n"); - printf(" Allowed values: x64, x86, arm, arm64, loongarch64, riscv64, wasm\n"); - printf(" Used by the assembly differences calculator; to determine a default JIT dll name;\n"); - printf(" and to avoid treating mismatched cross-compilation replay as failure.\n"); - printf("\n"); - printf(" -coredistools\n"); - printf(" Use disassembly tools from the CoreDisTools library\n"); -#if defined(USE_MSVCDIS) - printf(" Default: use MSVCDIS.\n"); -#elif defined(USE_COREDISTOOLS) - printf(" Ignored: MSVCDIS is not available, so CoreDisTools will be used.\n"); -#else - printf(" Ignored: neither MSVCDIS nor CoreDisTools is available.\n"); -#endif // USE_COREDISTOOLS - printf("\n"); - printf(" -jitoption [force] key=value\n"); - printf(" Set the JIT option named \"key\" to \"value\" for JIT 1 if the option was not set.\n"); - printf(" With optional force flag overwrites the existing value if it was already set.\n"); - printf(" NOTE: do not use a \"DOTNET_\" prefix. \"key\" and \"value\" are case sensitive.\n"); - printf(" \"key#value\" is also accepted.\n"); - printf("\n"); - printf(" -jit2option [force] key=value\n"); - printf(" Set the JIT option named \"key\" to \"value\" for JIT 2 if the option was not set.\n"); - printf(" With optional force flag overwrites the existing value if it was already set.\n"); - printf(" NOTE: do not use a \"DOTNET_\" prefix. \"key\" and \"value\" are case sensitive.\n"); - printf(" \"key#value\" is also accepted.\n"); - printf("\n"); - printf("Inputs are case sensitive.\n"); - printf("\n"); - printf("SuperPMI method contexts are stored in files with extension .MC, implying\n"); - printf("a single method context, or .MCH, implying a set of method contexts. Either\n"); - printf("extension works equivalently.\n"); - printf("\n"); - printf("Exit codes:\n"); - printf("0 : success\n"); - printf("-1 : general fatal error (e.g., failed to initialize, failed to read files)\n"); - printf("-2 : JIT failed to initialize\n"); - printf("1 : there were compilation failures\n"); - printf("2 : there were assembly diffs\n"); - printf("3 : there were missing values in method context\n"); - printf("\n"); - printf("Examples:\n"); - printf(" %s " MAKEDLLNAME_A("clrjit") " test.mch\n", program); - printf(" ; compile all functions in test.mch using " MAKEDLLNAME_A("clrjit") "\n"); - printf(" %s -p " MAKEDLLNAME_A("clrjit") " test.mch\n", program); - printf(" ; same as above, but use all available processors to compile in parallel\n"); - printf(" %s -f fail.mcl " MAKEDLLNAME_A("clrjit") " test.mch\n", program); - printf(" ; if there are any failures, record their MC numbers in the file fail.mcl\n"); -} - -bool CommandLine::ParseJitOption(const char* optionString, char** key, char** value) -{ - char tempKey[1024]; - - unsigned i; - for (i = 0; (optionString[i] != '=') && (optionString[i] != '#'); i++) - { - if ((i >= 1023) || (optionString[i] == '\0')) - { - return false; - } - tempKey[i] = optionString[i]; - } - tempKey[i] = '\0'; - - const char* tempVal = &optionString[i + 1]; - - const unsigned keyLen = i; - char* keyBuf = new char[keyLen + 1]; - strcpy_s(keyBuf, keyLen + 1, tempKey); - - const unsigned valLen = (unsigned)strlen(tempVal); - char* valBuf = new char[valLen + 1]; - strcpy_s(valBuf, valLen + 1, tempVal); - - *key = keyBuf; - *value = valBuf; - return true; -} - -// Assumption: All inputs are initialized to default or real value. we'll just set the stuff we see on the command -// line. Assumption: Single byte names are passed in.. mb stuff doesnt cause an obvious problem... but it might have -// issues... Assumption: Values larger than 2^31 aren't expressible from the commandline.... (atoi) Unless you pass in -// negatives.. :-| -bool CommandLine::Parse(int argc, char* argv[], /* OUT */ Options* o) -{ - size_t argLen = 0; - size_t tempLen = 0; - bool foundJit = false; - bool foundFile = false; - - if (argc == 1) // Print help when no args are passed - { - DumpHelp(argv[0]); - return false; - } - - for (int i = 1; i < argc; i++) - { - bool isASwitch = (argv[i][0] == '-'); -#ifndef TARGET_UNIX - if (argv[i][0] == '/') // Also accept "/" on Windows - { - isASwitch = true; - } -#endif // !TARGET_UNIX - - // Process a switch - if (isASwitch) - { - argLen = strlen(argv[i]); - - if (argLen > 1) - argLen--; // adjust for leading switch - else - { - DumpHelp(argv[0]); - return false; - } - - if ((_strnicmp(&argv[i][1], "help", argLen) == 0) || (_strnicmp(&argv[i][1], "HELP", argLen) == 0) || - (_strnicmp(&argv[i][1], "?", argLen) == 0)) - { - DumpHelp(argv[0]); - return false; - } - else if ((_strnicmp(&argv[i][1], "load", argLen) == 0)) - { - if (++i >= argc) - { - DumpHelp(argv[0]); - return false; - } - - processMethodContext: - - tempLen = strlen(argv[i]); - if (tempLen == 0) - { - LogError("Arg '%s' is invalid, name of file missing.", argv[i]); - DumpHelp(argv[0]); - return false; - } - o->nameOfInputMethodContextFile = new char[tempLen + 1]; - strcpy_s(o->nameOfInputMethodContextFile, tempLen + 1, argv[i]); - foundFile = true; - } - else if ((_strnicmp(&argv[i][1], "jit", argLen) == 0)) - { - if (++i >= argc) - { - DumpHelp(argv[0]); - return false; - } - - processJit: - - tempLen = strlen(argv[i]); - if (tempLen == 0) - { - LogError("Arg '%s' is invalid, name of jit missing.", argv[i]); - DumpHelp(argv[0]); - return false; - } - char* tempStr = new char[tempLen + 1]; - strcpy_s(tempStr, tempLen + 1, argv[i]); - if (!foundJit) - { - o->nameOfJit = tempStr; - foundJit = true; - } - else - { - if (o->nameOfJit2 != nullptr) - { - LogError("Too many JITs specified."); - DumpHelp(argv[0]); - return false; - } - - o->nameOfJit2 = tempStr; - } - } - else if ((_strnicmp(&argv[i][1], "reproName", argLen) == 0)) - { - if (++i >= argc) - { - DumpHelp(argv[0]); - return false; - } - - tempLen = strlen(argv[i]); - if (tempLen == 0) - { - LogError("Arg '%s' is invalid, name of prefix missing.", argv[i]); - DumpHelp(argv[0]); - return false; - } - char* tempStr = new char[tempLen + 1]; - strcpy_s(tempStr, tempLen + 1, argv[i]); - o->reproName = tempStr; - } - else if ((_strnicmp(&argv[i][1], "failingMCList", argLen) == 0)) - { - if (++i >= argc) - { - DumpHelp(argv[0]); - return false; - } - - o->mclFilename = argv[i]; - } - else if ((_strnicmp(&argv[i][1], "target", 6) == 0)) - { - if (++i >= argc) - { - DumpHelp(argv[0]); - return false; - } - - o->targetArchitecture = argv[i]; - } - else if ((_strnicmp(&argv[i][1], "boe", 3) == 0)) - { - o->breakOnError = true; - } - else if ((_strnicmp(&argv[i][1], "boa", 3) == 0)) - { - o->breakOnAssert = true; - } - else if ((_strnicmp(&argv[i][1], "box", 3) == 0)) - { - o->breakOnException = true; - } - else if ((_strnicmp(&argv[i][1], "ignoreStoredConfig", 18) == 0)) - { - o->ignoreStoredConfig = true; - } - else if ((_strnicmp(&argv[i][1], "verbosity", argLen) == 0)) - { - if (++i >= argc) - { - DumpHelp(argv[0]); - return false; - } - - o->verbosity = argv[i]; - Logger::SetLogLevel(Logger::ParseLogLevelString(o->verbosity)); - } - else if ((_strnicmp(&argv[i][1], "writeLogFile", argLen) == 0)) - { - if (++i >= argc) - { - DumpHelp(argv[0]); - return false; - } - - o->writeLogFile = argv[i]; - Logger::OpenLogFile(argv[i]); - } - else if ((_strnicmp(&argv[i][1], "emitMethodStats", argLen) == 0)) - { - if (++i >= argc) - { - DumpHelp(argv[0]); - return false; - } - - o->methodStatsTypes = argv[i]; - } - else if ((_strnicmp(&argv[i][1], "details", argLen) == 0)) - { - if (++i >= argc) - { - DumpHelp(argv[0]); - return false; - } - - o->details = argv[i]; - } - else if ((_strnicmp(&argv[i][1], "applyDiff", argLen) == 0)) - { - o->applyDiff = true; - } - else if ((_strnicmp(&argv[i][1], "compile", argLen) == 0)) - { - if (++i >= argc) - { - DumpHelp(argv[0]); - return false; - } - - bool isValidList = MCList::processArgAsMCL(argv[i], &o->indexCount, &o->indexes); - if (!isValidList) - { - LogError("Arg '%s' is invalid, needed method context list.", argv[i]); - DumpHelp(argv[0]); - return false; - } - if (o->hash != nullptr) - { - LogError("Cannot use both method context list and method context hash."); - DumpHelp(argv[0]); - return false; - } - if (o->offset > 0 && o->increment > 0) - { - LogError("Cannot use method context list in parallel mode."); - DumpHelp(argv[0]); - return false; - } - - o->compileList = argv[i]; // Save this in case we need it for -parallel. - } - else if ((_strnicmp(&argv[i][1], "coredistools", argLen) == 0)) - { -#ifndef USE_COREDISTOOLS // If USE_COREDISTOOLS is not defined, then allow the switch, but ignore it. - o->useCoreDisTools = true; -#endif // USE_COREDISTOOLS - } - else if ((_strnicmp(&argv[i][1], "matchHash", argLen) == 0)) - { - if (++i >= argc) - { - DumpHelp(argv[0]); - return false; - } - - if (strlen(argv[i]) != (MM3_HASH_BUFFER_SIZE - 1)) - { - LogError("Arg '%s' is invalid, needed a valid method context hash.", argv[i]); - DumpHelp(argv[0]); - return false; - } - if (o->indexCount > 0) - { - LogError("Cannot use both method context list and method context hash."); - DumpHelp(argv[0]); - return false; - } - if (o->offset > 0 && o->increment > 0) - { - LogError("Cannot use method context hash in parallel mode."); - DumpHelp(argv[0]); - return false; - } - o->hash = argv[i]; - } - else if ((_strnicmp(&argv[i][1], "streaming", argLen) == 0)) - { - if (++i >= argc) - { - LogError("'-streaming' must be followed by a file name or 'stdin'."); - DumpHelp(argv[0]); - return false; - } - - o->streamFile = argv[i]; - } - else if ((_strnicmp(&argv[i][1], "parallel", argLen) == 0)) - { - o->parallel = true; - - // Is there another argument? - if (i + 1 < argc) - { - // If so, does it look like a worker count? - bool isWorkerCount = true; - size_t nextlen = strlen(argv[i + 1]); - for (size_t j = 0; j < nextlen; j++) - { - if (!isdigit(argv[i + 1][j])) - { - isWorkerCount = - false; // Doesn't look like a worker count; bail out and let someone else handle it. - break; - } - } - if (isWorkerCount) - { - ++i; - o->workerCount = atoi(argv[i]); - - if (o->workerCount < 1) - { - LogError("Invalid workers count specified, workers count must be at least 1."); - DumpHelp(argv[0]); - return false; - } - if (o->workerCount > MAXIMUM_WAIT_OBJECTS) - { - LogError("Invalid workers count specified, workers count cannot be more than %d.", - MAXIMUM_WAIT_OBJECTS); - DumpHelp(argv[0]); - return false; - } - } - } - } - else if ((_strnicmp(&argv[i][1], "failureLimit", argLen) == 0)) - { - if (++i >= argc) - { - DumpHelp(argv[0]); - return false; - } - - o->failureLimit = atoi(argv[i]); - - if (o->failureLimit < 1) - { - LogError( - "Incorrect limit specified for -failureLimit. Limit must be > 0."); - DumpHelp(argv[0]); - return false; - } - } - else if ((_stricmp(&argv[i][1], "skipCleanup") == 0)) - { - o->skipCleanup = true; - } - else if ((_stricmp(&argv[i][1], "repeatCount") == 0)) - { - if (++i >= argc) - { - DumpHelp(argv[0]); - return false; - } - - bool isValidRepeatCount = true; - size_t nextlen = strlen(argv[i]); - for (size_t j = 0; j < nextlen; j++) - { - if (!isdigit(argv[i][j])) - { - isValidRepeatCount = false; - break; - } - } - if (isValidRepeatCount) - { - o->repeatCount = atoi(argv[i]); - if (o->repeatCount < 1) - { - isValidRepeatCount = false; - } - } - - if (!isValidRepeatCount) - { - LogError("Invalid repeat count specified. Repeat count must be between 1 and INT_MAX."); - DumpHelp(argv[0]); - return false; - } - } - else if ((_strnicmp(&argv[i][1], "stride", argLen) == 0)) - { - // "-stride" is an internal switch used by -parallel. Usage is: - // - // -stride offset increment - // - // It compiles methods in this series until end-of-file: - // offset, offset+increment, offset+2*increment, offset+3*increment, ... - - if (++i >= argc) - { - DumpHelp(argv[0]); - return false; - } - - o->offset = atoi(argv[i]); - - if (++i >= argc) - { - DumpHelp(argv[0]); - return false; - } - - o->increment = atoi(argv[i]); - - if (o->offset < 1 || o->increment < 1) - { - LogError( - "Incorrect offset/increment specified for -stride. Offset and increment both must be > 0."); - DumpHelp(argv[0]); - return false; - } - if (o->indexCount > 0) - { - LogError("Cannot use method context list in parallel mode."); - DumpHelp(argv[0]); - return false; - } - if (o->hash != nullptr) - { - LogError("Cannot use method context hash in parallel mode."); - DumpHelp(argv[0]); - return false; - } - } - else if (_strnicmp(&argv[i][1], "jitoption", argLen) == 0) - { - i++; - if (!AddJitOption(i, argc, argv, &o->jitOptions, &o->forceJitOptions)) - { - return false; - } - } - else if (_strnicmp(&argv[i][1], "jit2option", argLen) == 0) - { - i++; - if (!AddJitOption(i, argc, argv, &o->jit2Options, &o->forceJit2Options)) - { - return false; - } - } - else - { - LogError("Unknown switch '%s' passed as argument.", argv[i]); - DumpHelp(argv[0]); - return false; - } - } - // Process an input filename - // String comparisons on file extensions must be case-insensitive since we run on Windows - else - { - char* lastdot = strrchr(argv[i], '.'); - if (lastdot == nullptr) - { - DumpHelp(argv[0]); - return false; - } - - if (_stricmp(lastdot, PLATFORM_SHARED_LIB_SUFFIX_A) == 0) - goto processJit; - else if (_stricmp(lastdot, ".mc") == 0) - goto processMethodContext; - else if (_stricmp(lastdot, ".mch") == 0) - goto processMethodContext; - else if (_stricmp(lastdot, ".mct") == 0) - goto processMethodContext; - else - { - LogError("Unknown file type passed as argument, '%s'.", argv[i]); - DumpHelp(argv[0]); - return false; - } - } - } - - // Do some argument validation. - - if (o->targetArchitecture != nullptr) - { - if ((0 != _stricmp(o->targetArchitecture, "amd64")) && - (0 != _stricmp(o->targetArchitecture, "x64")) && - (0 != _stricmp(o->targetArchitecture, "x86")) && - (0 != _stricmp(o->targetArchitecture, "arm64")) && - (0 != _stricmp(o->targetArchitecture, "arm")) && - (0 != _stricmp(o->targetArchitecture, "arm32")) && - (0 != _stricmp(o->targetArchitecture, "loongarch64")) && - (0 != _stricmp(o->targetArchitecture, "riscv64")) && - (0 != _stricmp(o->targetArchitecture, "wasm")) && - (0 != _stricmp(o->targetArchitecture, "wasm32"))) - { - LogError("Illegal target architecture specified with -target."); - DumpHelp(argv[0]); - return false; - } - } - - if (o->streamFile != nullptr) - { - if (o->parallel) - { - LogError("streaming mode and parallel mode are incompatible."); - return false; - } - - if (o->nameOfJit2 != nullptr) - { - LogError("streaming mode and diff mode are incompatible."); - return false; - } - } - - SPMI_TARGET_ARCHITECTURE defaultSpmiTargetArchitecture = GetSpmiTargetArchitecture(); - SetSuperPmiTargetArchitecture(o->targetArchitecture); - - if (o->nameOfInputMethodContextFile == nullptr) - { - LogError("Missing name of an input file."); - DumpHelp(argv[0]); - return false; - } - - if (o->nameOfJit == nullptr) - { - // Try to find a JIT in the same directory as superpmi.exe. If found (based on targetArchitecture), use it. - - bool allowDefaultJIT = true; - - const char* hostOSTag = ""; - const char* jitHostOSPrefix = ""; - const char* jitHostOSExtension = ""; - -#if defined(HOST_OSX) // NOTE: HOST_UNIX is also defined for HOST_OSX - hostOSTag = "unix"; - jitHostOSPrefix = "lib"; - jitHostOSExtension = ".dylib"; -#elif defined(HOST_UNIX) - hostOSTag = "unix"; - jitHostOSPrefix = "lib"; - jitHostOSExtension = ".so"; -#elif defined(HOST_WINDOWS) - hostOSTag = "win"; - jitHostOSExtension = ".dll"; -#else - allowDefaultJIT = false; -#endif - - const char* hostArch = ""; - -#if defined(HOST_AMD64) - hostArch = "x64"; -#elif defined(HOST_X86) - hostArch = "x86"; -#elif defined(HOST_ARM) - hostArch = "arm"; -#elif defined(HOST_ARM64) - hostArch = "arm64"; -#elif defined(HOST_LOONGARCH64) - hostArch = "loongarch64"; -#elif defined(HOST_RISCV64) - hostArch = "riscv64"; -#else - allowDefaultJIT = false; -#endif - - const char* targetArch = ""; - - switch (GetSpmiTargetArchitecture()) - { - case SPMI_TARGET_ARCHITECTURE_AMD64: - targetArch = "x64"; - break; - case SPMI_TARGET_ARCHITECTURE_X86: - targetArch = "x86"; - break; - case SPMI_TARGET_ARCHITECTURE_ARM: - targetArch = "arm"; - break; - case SPMI_TARGET_ARCHITECTURE_ARM64: - targetArch = "arm64"; - break; - case SPMI_TARGET_ARCHITECTURE_LOONGARCH64: - targetArch = "loongarch64"; - break; - case SPMI_TARGET_ARCHITECTURE_RISCV64: - targetArch = "riscv64"; - break; - default: - allowDefaultJIT = false; - break; - } - - size_t programPathLen = 0; - char* programPath = nullptr; - const char* lastSlash = strrchr(argv[0], DIRECTORY_SEPARATOR_CHAR_A); - if (lastSlash == nullptr) - { - allowDefaultJIT = false; - } - else - { - programPathLen = lastSlash - argv[0] + 1; - programPath = new char[programPathLen]; - strncpy_s(programPath, programPathLen, argv[0], programPathLen - 1); - } - - if (allowDefaultJIT) - { - const char* jitOSName = nullptr; - - if (defaultSpmiTargetArchitecture != GetSpmiTargetArchitecture()) - { - // SuperPMI doesn't know about "target OS" so always assume host OS. - - switch (GetSpmiTargetArchitecture()) - { - case SPMI_TARGET_ARCHITECTURE_AMD64: - case SPMI_TARGET_ARCHITECTURE_X86: - jitOSName = hostOSTag; - break; - case SPMI_TARGET_ARCHITECTURE_ARM: - case SPMI_TARGET_ARCHITECTURE_ARM64: - jitOSName = "universal"; - break; - case SPMI_TARGET_ARCHITECTURE_LOONGARCH64: - case SPMI_TARGET_ARCHITECTURE_RISCV64: - jitOSName = "unix"; - break; - default: - // Can't get here if `allowDefaultJIT` was properly set above. - break; - } - } - - const char* const jitBaseName = "clrjit"; - size_t len = programPathLen + strlen(jitHostOSPrefix) + strlen(jitBaseName) + strlen(jitHostOSExtension) + 1; - if (jitOSName != nullptr) - { - len += 3 /* underscores */ + strlen(jitOSName) + strlen(targetArch) + strlen(hostArch); - } - char* tempStr = new char[len]; - if (jitOSName == nullptr) - { - sprintf_s(tempStr, len, "%s%c%s%s%s", - programPath, - DIRECTORY_SEPARATOR_CHAR_A, - jitHostOSPrefix, - jitBaseName, - jitHostOSExtension); - } - else - { - sprintf_s(tempStr, len, "%s%c%s%s_%s_%s_%s%s", - programPath, - DIRECTORY_SEPARATOR_CHAR_A, - jitHostOSPrefix, - jitBaseName, - jitOSName, - targetArch, - hostArch, - jitHostOSExtension); - } - - o->nameOfJit = tempStr; - - LogInfo("Using default JIT: %s", o->nameOfJit); - } - else - { - LogError("Missing name of a Jit."); - DumpHelp(argv[0]); - return false; - } - } - - if (o->skipCleanup && !o->parallel) - { - LogError("-skipCleanup requires -parallel."); - DumpHelp(argv[0]); - return false; - } - - return true; -} - -//------------------------------------------------------------- -// AddJitOption: Parse the value that was passed with -jitOption flag. -// -// Arguments: -// currArgument - current argument number. Points to the token next to -jitOption. After the function -// points to the last parsed token -// argc - number of all arguments -// argv - arguments as array of char* -// pJitOptions - a jit options map, that sets the option, if it was not already set. -// pForceJitOptions - a jit options map, that forces the option even if it was already set. -// -// Returns: -// False if an error occurred, true if the option was parsed and added. -bool CommandLine::AddJitOption(int& currArgument, - int argc, - char* argv[], - LightWeightMap** pJitOptions, - LightWeightMap** pForceJitOptions) -{ - if (currArgument >= argc) - { - DumpHelp(argv[0]); - return false; - } - - LightWeightMap* targetjitOptions = nullptr; - - if (_strnicmp(argv[currArgument], "force", strlen(argv[currArgument])) == 0) - { - if (*pForceJitOptions == nullptr) - { - *pForceJitOptions = new LightWeightMap(); - } - targetjitOptions = *pForceJitOptions; - currArgument++; - } - else - { - if (*pJitOptions == nullptr) - { - *pJitOptions = new LightWeightMap(); - } - targetjitOptions = *pJitOptions; - } - - char* key; - char* value; - if ((currArgument >= argc) || !ParseJitOption(argv[currArgument], &key, &value)) - { - DumpHelp(argv[0]); - return false; - } - - DWORD keyIndex = - (DWORD)targetjitOptions->AddBuffer((unsigned char*)key, sizeof(char) * ((unsigned int)strlen(key) + 1)); - DWORD valueIndex = - (DWORD)targetjitOptions->AddBuffer((unsigned char*)value, sizeof(char) * ((unsigned int)strlen(value) + 1)); - targetjitOptions->Add(keyIndex, valueIndex); - - delete[] key; - delete[] value; - return true; -} diff --git a/src/coreclr/tools/superpmi/superpmi/commandline.h b/src/coreclr/tools/superpmi/superpmi/commandline.h deleted file mode 100644 index 02a9ef4ee38466..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi/commandline.h +++ /dev/null @@ -1,67 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// CommandLine.h - tiny very specific command line parser -//---------------------------------------------------------- -#ifndef _CommandLine -#define _CommandLine - -class CommandLine -{ -public: - class Options - { - public: - char* nameOfJit = nullptr; - char* nameOfJit2 = nullptr; - char* nameOfInputMethodContextFile = nullptr; - char* verbosity = nullptr; - char* writeLogFile = nullptr; - char* reproName = nullptr; - bool breakOnError = false; - bool breakOnAssert = false; - bool breakOnException = false; - bool ignoreStoredConfig = false; - bool applyDiff = false; - bool parallel = false; // User specified to use /parallel mode. - char* streamFile = nullptr; -#if !defined(USE_MSVCDIS) && defined(USE_COREDISTOOLS) - bool useCoreDisTools = true; // Use CoreDisTools library instead of Msvcdis -#else - bool useCoreDisTools = false; // Use CoreDisTools library instead of Msvcdis -#endif - bool skipCleanup = false; // In /parallel mode, do we skip cleanup of temporary files? Used for debugging /parallel. - int workerCount = -1; // Number of workers to use for /parallel mode. -1 (or 1) means don't use parallel mode. - int indexCount = -1; // If indexCount is -1 and hash points to nullptr it means compile all. - int failureLimit = -1; // Number of failures after which bail out the replay/asmdiffs. - int repeatCount = 1; // Number of times given methods should be compiled. - int* indexes = nullptr; - char* hash = nullptr; - char* methodStatsTypes = nullptr; - char* details = nullptr; - char* mclFilename = nullptr; - char* targetArchitecture = nullptr; - char* compileList = nullptr; - int offset = -1; - int increment = -1; - LightWeightMap* forceJitOptions = nullptr; - LightWeightMap* forceJit2Options = nullptr; - LightWeightMap* jitOptions = nullptr; - LightWeightMap* jit2Options = nullptr; - }; - - static bool Parse(int argc, char* argv[], /* OUT */ Options* o); - - static bool AddJitOption(int& currArgument, - int argc, - char* argv[], - LightWeightMap** pJitOptions, - LightWeightMap** pForceJitOptions); - - static bool ParseJitOption(const char* optionString, char** key, char** value); - -private: - static void DumpHelp(const char* program); -}; -#endif diff --git a/src/coreclr/tools/superpmi/superpmi/cycletimer.cpp b/src/coreclr/tools/superpmi/superpmi/cycletimer.cpp deleted file mode 100644 index 6e0e8a9adc5e4e..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi/cycletimer.cpp +++ /dev/null @@ -1,58 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "standardpch.h" -#include "cycletimer.h" - -CycleTimer::CycleTimer() -{ - start = 0; - stop = 0; - overhead = QueryOverhead(); -} - -CycleTimer::~CycleTimer() -{ -} - -void CycleTimer::Start() -{ - BOOL retVal = QueryThreadCycleTime(GetCurrentThread(), &start); - - if (retVal == FALSE) - { - LogError("CycleTimer::Start unable to QPC. error was 0x%08x", ::GetLastError()); - DEBUG_BREAK; - } -} - -void CycleTimer::Stop() -{ - BOOL retVal = QueryThreadCycleTime(GetCurrentThread(), &stop); - - if (retVal == FALSE) - { - LogError("CycleTimer::Stop unable to QPC. error was 0x%08x", ::GetLastError()); - DEBUG_BREAK; - } -} - -uint64_t CycleTimer::GetCycles() -{ - return stop - start - overhead; -} - -uint64_t CycleTimer::QueryOverhead() -{ - uint64_t tot = 0; - uint64_t startCycles; - uint64_t endCycles; - const int N = 1000; - for (int i = 0; i < N; i++) - { - QueryThreadCycleTime(GetCurrentThread(), &startCycles); - QueryThreadCycleTime(GetCurrentThread(), &endCycles); - tot += (endCycles - startCycles); - } - return tot / N; -} diff --git a/src/coreclr/tools/superpmi/superpmi/cycletimer.h b/src/coreclr/tools/superpmi/superpmi/cycletimer.h deleted file mode 100644 index 8f89a879fa4a13..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi/cycletimer.h +++ /dev/null @@ -1,26 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#ifndef _CycleTimer -#define _CycleTimer - -#include "errorhandling.h" - -class CycleTimer -{ -public: - CycleTimer(); - ~CycleTimer(); - - void Start(); - void Stop(); - uint64_t GetCycles(); - uint64_t QueryOverhead(); - -private: - // Cycles - uint64_t start; - uint64_t stop; - uint64_t overhead; -}; -#endif diff --git a/src/coreclr/tools/superpmi/superpmi/fileio.cpp b/src/coreclr/tools/superpmi/superpmi/fileio.cpp deleted file mode 100644 index eaa53fb0c9189e..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi/fileio.cpp +++ /dev/null @@ -1,206 +0,0 @@ -#include "standardpch.h" -#include "fileio.h" - -bool FileWriter::Printf(const char* fmt, ...) -{ - va_list args; - va_start(args, fmt); - - char stackBuffer[512]; - size_t bufferSize = sizeof(stackBuffer); - char* pBuffer = stackBuffer; - while (true) - { - va_list argsCopy; - va_copy(argsCopy, args); - int printed = _vsnprintf_s(pBuffer, bufferSize, _TRUNCATE, fmt, argsCopy); - va_end(argsCopy); - - if (printed < 0) - { - // buffer too small - if (pBuffer != stackBuffer) - delete[] pBuffer; - - bufferSize *= 2; - pBuffer = new char[bufferSize]; - } - else - { - bool result = Print(pBuffer, static_cast(printed)); - - if (pBuffer != stackBuffer) - delete[] pBuffer; - - va_end(args); - return result; - } - } -} - -bool FileWriter::Print(const char* value, size_t numChars) -{ - if (numChars > (m_buffer.size() - m_bufferIndex)) - { - Flush(); - - if (numChars > m_buffer.size()) - { - DWORD numWritten; - bool result = - WriteFile(m_file.Get(), value, static_cast(numChars), &numWritten, nullptr) && - (numWritten == static_cast(numChars)); - return result; - } - } - - memcpy(m_buffer.data() + m_bufferIndex, value, numChars); - m_bufferIndex += numChars; - return true; -} - -bool FileWriter::Print(const char* value) -{ - return Print(value, strlen(value)); -} - -bool FileWriter::Print(int value) -{ - return Printf("%d", value); -} - -bool FileWriter::Print(int64_t value) -{ - return Printf("%lld", value); -} - -bool FileWriter::Print(double value) -{ - return Printf("%f", value); -} - -bool FileWriter::PrintQuotedCsvField(const char* value) -{ - size_t numQuotes = 0; - for (const char* p = value; *p != '\0'; p++) - { - if (*p == '"') - { - numQuotes++; - } - } - - if (numQuotes == 0) - { - return Printf("\"%s\"", value); - } - else - { - size_t len = 2 + strlen(value) + numQuotes; - char* buffer = new char[len]; - - size_t index = 0; - buffer[index++] = '"'; - for (const char* p = value; *p != '\0'; p++) - { - if (*p == '"') - { - buffer[index++] = '"'; - } - buffer[index++] = *p; - } - - buffer[index++] = '"'; - assert(index == len); - - bool result = Print(buffer, len); - delete[] buffer; - return result; - } -} - -bool FileWriter::Flush() -{ - if (m_bufferIndex <= 0) - return true; - - DWORD numWritten; - bool result = - WriteFile(m_file.Get(), m_buffer.data(), static_cast(m_bufferIndex), &numWritten, nullptr) && - (numWritten == static_cast(m_bufferIndex)); - m_bufferIndex = 0; - return result; -} - -bool FileWriter::CreateNew(const char* path, FileWriter* fw) -{ - FileHandle handle(CreateFile(path, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr)); - if (!handle.IsValid()) - { - return false; - } - - *fw = FileWriter(std::move(handle)); - return true; -} - -bool FileLineReader::Open(const char* path, FileLineReader* fr) -{ - FileHandle file(CreateFile(path, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr)); - if (!file.IsValid()) - { - return false; - } - - LARGE_INTEGER size; - if (!GetFileSizeEx(file.Get(), &size)) - { - return false; - } - - if (static_cast(size.QuadPart) > SIZE_MAX) - { - return false; - } - - FileMappingHandle mapping(CreateFileMapping(file.Get(), nullptr, PAGE_READONLY, size.u.HighPart, size.u.LowPart, nullptr)); - if (!mapping.IsValid()) - { - return false; - } - - FileViewHandle view(MapViewOfFile(mapping.Get(), FILE_MAP_READ, 0, 0, 0)); - if (!view.IsValid()) - { - return false; - } - - *fr = FileLineReader(std::move(file), std::move(mapping), std::move(view), static_cast(size.QuadPart)); - return true; -} - -bool FileLineReader::AdvanceLine() -{ - if (m_cur >= m_end) - { - return false; - } - - char* end = m_cur; - while (end < m_end && *end != '\r' && *end != '\n') - { - end++; - } - - m_currentLine.resize(end - m_cur + 1); - memcpy(m_currentLine.data(), m_cur, end - m_cur); - m_currentLine[end - m_cur] = '\0'; - - m_cur = end; - if (m_cur < m_end && *m_cur == '\r') - m_cur++; - if (m_cur < m_end && *m_cur == '\n') - m_cur++; - - return true; -} diff --git a/src/coreclr/tools/superpmi/superpmi/fileio.h b/src/coreclr/tools/superpmi/superpmi/fileio.h deleted file mode 100644 index 8c721c2545008e..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi/fileio.h +++ /dev/null @@ -1,165 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#ifndef _FileIO -#define _FileIO - -template -struct HandleWrapper -{ - using HandleType = typename HandleSpec::Type; - - HandleWrapper() - : m_handle(HandleSpec::Invalid()) - { - } - - explicit HandleWrapper(HandleType handle) - : m_handle(handle) - { - } - - ~HandleWrapper() - { - if (m_handle != HandleSpec::Invalid()) - { - HandleSpec::Close(m_handle); - m_handle = HandleSpec::Invalid(); - } - } - - HandleWrapper(const HandleWrapper&) = delete; - HandleWrapper& operator=(const HandleWrapper&) = delete; - - HandleWrapper(HandleWrapper&& hw) noexcept - : m_handle(hw.m_handle) - { - hw.m_handle = HandleSpec::Invalid(); - } - - HandleWrapper& operator=(HandleWrapper&& hw) noexcept - { - if (m_handle != HandleSpec::Invalid()) - HandleSpec::Close(m_handle); - - m_handle = hw.m_handle; - hw.m_handle = HandleSpec::Invalid(); - return *this; - } - - bool IsValid() { return m_handle != HandleSpec::Invalid(); } - HandleType Get() { return m_handle; } - -private: - HandleType m_handle; -}; - -struct FileHandleSpec -{ - using Type = HANDLE; - static HANDLE Invalid() { return INVALID_HANDLE_VALUE; } - static void Close(HANDLE h) { CloseHandle(h); } -}; - -struct FileMappingHandleSpec -{ - using Type = HANDLE; - static HANDLE Invalid() { return nullptr; } - static void Close(HANDLE h) { CloseHandle(h); } -}; - -struct FileViewHandleSpec -{ - using Type = LPVOID; - static LPVOID Invalid() { return nullptr; } - static void Close(LPVOID p) { UnmapViewOfFile(p); } -}; - -typedef HandleWrapper FileHandle; -typedef HandleWrapper FileMappingHandle; -typedef HandleWrapper FileViewHandle; - -class FileWriter -{ - FileHandle m_file; - std::vector m_buffer; - size_t m_bufferIndex = 0; - - explicit FileWriter(FileHandle file) - : m_file(std::move(file)) - , m_buffer(8192) - { - } - -public: - FileWriter() - { - } - - FileWriter(FileWriter&& fw) noexcept - : m_file(std::move(fw.m_file)) - , m_buffer(std::move(fw.m_buffer)) - , m_bufferIndex(fw.m_bufferIndex) - { - } - FileWriter& operator=(FileWriter&& fw) noexcept - { - m_file = std::move(fw.m_file); - m_buffer = std::move(fw.m_buffer); - m_bufferIndex = fw.m_bufferIndex; - return *this; - } - - FileWriter(const FileWriter&) = delete; - FileWriter& operator=(const FileWriter&) = delete; - - ~FileWriter() - { - Flush(); - } - - bool Print(const char* value, size_t numChars); - bool Print(const char* value); - bool Print(int value); - bool Print(int64_t value); - bool Print(double value); - bool PrintQuotedCsvField(const char* value); - bool Printf(const char* fmt, ...); - bool Flush(); - - static bool CreateNew(const char* path, FileWriter* fw); -}; - -class FileLineReader -{ - FileHandle m_file; - FileMappingHandle m_fileMapping; - FileViewHandle m_view; - - char* m_cur; - char* m_end; - std::vector m_currentLine; - - FileLineReader(FileHandle file, FileMappingHandle fileMapping, FileViewHandle view, size_t size) - : m_file(std::move(file)) - , m_fileMapping(std::move(fileMapping)) - , m_view(std::move(view)) - , m_cur(static_cast(m_view.Get())) - , m_end(static_cast(m_view.Get()) + size) - { - } - -public: - FileLineReader() - : m_cur(nullptr) - , m_end(nullptr) - { - } - - bool AdvanceLine(); - const char* GetCurrentLine() { return m_currentLine.data(); } - - static bool Open(const char* path, FileLineReader* fr); -}; - -#endif diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp deleted file mode 100644 index 926214292f0b37..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ /dev/null @@ -1,1915 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "standardpch.h" -#include "icorjitinfo.h" -#include "jitdebugger.h" -#include "spmiutil.h" - -ICorJitInfo* pICJI = nullptr; - -ICorJitInfo* InitICorJitInfo(JitInstance* jitInstance) -{ - MyICJI* icji = new MyICJI(); - icji->jitInstance = jitInstance; - pICJI = icji; - return icji; -} - -// Stuff on ICorStaticInfo -/**********************************************************************************/ -// -// ICorMethodInfo -// -/**********************************************************************************/ - -// Quick check whether the method is a jit intrinsic. Returns the same value as getMethodAttribs(ftn) & -// CORINFO_FLG_INTRINSIC, except faster. -bool MyICJI::isIntrinsic(CORINFO_METHOD_HANDLE ftn) -{ - jitInstance->mc->cr->AddCall("isIntrinsic"); - return jitInstance->mc->repIsIntrinsic(ftn); -} - -bool MyICJI::canValueClassInstancePointerEscape(CORINFO_METHOD_HANDLE ftn) -{ - jitInstance->mc->cr->AddCall("canValueClassInstancePointerEscape"); - return jitInstance->mc->repCanValueClassInstancePointerEscape(ftn); -} - -bool MyICJI::notifyMethodInfoUsage(CORINFO_METHOD_HANDLE ftn) -{ - jitInstance->mc->cr->AddCall("notifyMethodInfoUsage"); - return jitInstance->mc->repNotifyMethodInfoUsage(ftn); -} - -// return flags (defined above, CORINFO_FLG_PUBLIC ...) -uint32_t MyICJI::getMethodAttribs(CORINFO_METHOD_HANDLE ftn /* IN */) -{ - jitInstance->mc->cr->AddCall("getMethodAttribs"); - return jitInstance->mc->repGetMethodAttribs(ftn); -} - -// sets private JIT flags, which can be, retrieved using getAttrib. -void MyICJI::setMethodAttribs(CORINFO_METHOD_HANDLE ftn, /* IN */ - CorInfoMethodRuntimeFlags attribs /* IN */) -{ - jitInstance->mc->cr->AddCall("setMethodAttribs"); - jitInstance->mc->cr->recSetMethodAttribs(ftn, attribs); -} - -// Given a method descriptor ftnHnd, extract signature information into sigInfo -// -// 'memberParent' is typically only set when verifying. It should be the -// result of calling getMemberParent. -void MyICJI::getMethodSig(CORINFO_METHOD_HANDLE ftn, /* IN */ - CORINFO_SIG_INFO* sig, /* OUT */ - CORINFO_CLASS_HANDLE memberParent /* IN */ - ) -{ - jitInstance->mc->cr->AddCall("getMethodSig"); - jitInstance->mc->repGetMethodSig(ftn, sig, memberParent); -} - -/********************************************************************* -* Note the following methods can only be used on functions known -* to be IL. This includes the method being compiled and any method -* that 'getMethodInfo' returns true for -*********************************************************************/ - -// return information about a method private to the implementation -// returns false if method is not IL, or is otherwise unavailable. -// This method is used to fetch data needed to inline functions -bool MyICJI::getMethodInfo(CORINFO_METHOD_HANDLE ftn, /* IN */ - CORINFO_METHOD_INFO* info, /* OUT */ - CORINFO_CONTEXT_HANDLE context /* IN */ - ) -{ - jitInstance->mc->cr->AddCall("getMethodInfo"); - DWORD exceptionCode = 0; - bool value = jitInstance->mc->repGetMethodInfo(ftn, info, context, &exceptionCode); - if (exceptionCode != 0) - ThrowRecordedException(exceptionCode); - return value; -} - -bool MyICJI::haveSameMethodDefinition( - CORINFO_METHOD_HANDLE methHnd1, - CORINFO_METHOD_HANDLE methHnd2) -{ - jitInstance->mc->cr->AddCall("haveSameMethodDefinition"); - bool value = jitInstance->mc->repHaveSameMethodDefinition(methHnd1, methHnd2); - return value; -} - -CORINFO_CLASS_HANDLE MyICJI::getTypeDefinition( - CORINFO_CLASS_HANDLE type) -{ - jitInstance->mc->cr->AddCall("getTypeDefinition"); - CORINFO_CLASS_HANDLE value = jitInstance->mc->repGetTypeDefinition(type); - return value; -} - -// Decides if you have any limitations for inlining. If everything's OK, it will return -// INLINE_PASS. -// -// The callerHnd must be the immediate caller (i.e. when we have a chain of inlined calls) -// -// The inlined method need not be verified - -CorInfoInline MyICJI::canInline(CORINFO_METHOD_HANDLE callerHnd, /* IN */ - CORINFO_METHOD_HANDLE calleeHnd /* IN */ - ) -{ - jitInstance->mc->cr->AddCall("canInline"); - - DWORD exceptionCode = 0; - CorInfoInline result = jitInstance->mc->repCanInline(callerHnd, calleeHnd, &exceptionCode); - if (exceptionCode != 0) - ThrowRecordedException(exceptionCode); - return result; -} - -void MyICJI::beginInlining(CORINFO_METHOD_HANDLE inlinerHnd, - CORINFO_METHOD_HANDLE inlineeHnd) -{ - // do nothing -} -// Reports whether or not a method can be inlined, and why. canInline is responsible for reporting all -// inlining results when it returns INLINE_FAIL and INLINE_NEVER. All other results are reported by the -// JIT. -void MyICJI::reportInliningDecision(CORINFO_METHOD_HANDLE inlinerHnd, - CORINFO_METHOD_HANDLE inlineeHnd, - CorInfoInline inlineResult, - const char* reason) -{ - jitInstance->mc->cr->AddCall("reportInliningDecision"); - jitInstance->mc->cr->recReportInliningDecision(inlinerHnd, inlineeHnd, inlineResult, reason); -} - -// Returns false if the call is across security boundaries thus we cannot tailcall -// -// The callerHnd must be the immediate caller (i.e. when we have a chain of inlined calls) -bool MyICJI::canTailCall(CORINFO_METHOD_HANDLE callerHnd, /* IN */ - CORINFO_METHOD_HANDLE declaredCalleeHnd, /* IN */ - CORINFO_METHOD_HANDLE exactCalleeHnd, /* IN */ - bool fIsTailPrefix /* IN */ - ) -{ - jitInstance->mc->cr->AddCall("canTailCall"); - return jitInstance->mc->repCanTailCall(callerHnd, declaredCalleeHnd, exactCalleeHnd, fIsTailPrefix); -} - -// Reports whether or not a method can be tail called, and why. -// canTailCall is responsible for reporting all results when it returns -// false. All other results are reported by the JIT. -void MyICJI::reportTailCallDecision(CORINFO_METHOD_HANDLE callerHnd, - CORINFO_METHOD_HANDLE calleeHnd, - bool fIsTailPrefix, - CorInfoTailCall tailCallResult, - const char* reason) -{ - jitInstance->mc->cr->AddCall("reportTailCallDecision"); - jitInstance->mc->cr->recReportTailCallDecision(callerHnd, calleeHnd, fIsTailPrefix, tailCallResult, reason); -} - -// get individual exception handler -void MyICJI::getEHinfo(CORINFO_METHOD_HANDLE ftn, /* IN */ - unsigned EHnumber, /* IN */ - CORINFO_EH_CLAUSE* clause /* OUT */ - ) -{ - jitInstance->mc->cr->AddCall("getEHinfo"); - jitInstance->mc->repGetEHinfo(ftn, EHnumber, clause); -} - -// return class it belongs to -CORINFO_CLASS_HANDLE MyICJI::getMethodClass(CORINFO_METHOD_HANDLE method) -{ - jitInstance->mc->cr->AddCall("getMethodClass"); - return jitInstance->mc->repGetMethodClass(method); -} - -// This function returns the offset of the specified method in the -// vtable of it's owning class or interface. -void MyICJI::getMethodVTableOffset(CORINFO_METHOD_HANDLE method, /* IN */ - unsigned* offsetOfIndirection, /* OUT */ - unsigned* offsetAfterIndirection, /* OUT */ - bool* isRelative /* OUT */ - ) -{ - jitInstance->mc->cr->AddCall("getMethodVTableOffset"); - jitInstance->mc->repGetMethodVTableOffset(method, offsetOfIndirection, offsetAfterIndirection, isRelative); -} - -bool MyICJI::resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO * info) -{ - jitInstance->mc->cr->AddCall("resolveVirtualMethod"); - bool result = jitInstance->mc->repResolveVirtualMethod(info); - return result; -} - -CORINFO_METHOD_HANDLE MyICJI::getAsyncOtherVariant(CORINFO_METHOD_HANDLE ftn, bool* variantIsThunk) -{ - jitInstance->mc->cr->AddCall("getAsyncOtherVariant"); - CORINFO_METHOD_HANDLE result = jitInstance->mc->repGetAsyncOtherVariant(ftn, variantIsThunk); - return result; -} - -// Given T, return the type of the default Comparer. -// Returns null if the type can't be determined exactly. -CORINFO_CLASS_HANDLE MyICJI::getDefaultComparerClass(CORINFO_CLASS_HANDLE cls) -{ - jitInstance->mc->cr->AddCall("getDefaultComparerClass"); - CORINFO_CLASS_HANDLE result = jitInstance->mc->repGetDefaultComparerClass(cls); - return result; -} - -// Given T, return the type of the default EqualityComparer. -// Returns null if the type can't be determined exactly. -CORINFO_CLASS_HANDLE MyICJI::getDefaultEqualityComparerClass(CORINFO_CLASS_HANDLE cls) -{ - jitInstance->mc->cr->AddCall("getDefaultEqualityComparerClass"); - CORINFO_CLASS_HANDLE result = jitInstance->mc->repGetDefaultEqualityComparerClass(cls); - return result; -} - -// Given T, return the type of the SZGenericArrayEnumerator. -// Returns null if the type can't be determined exactly. -CORINFO_CLASS_HANDLE MyICJI::getSZArrayHelperEnumeratorClass(CORINFO_CLASS_HANDLE cls) -{ - jitInstance->mc->cr->AddCall("getSZArrayHelperEnumeratorClass"); - CORINFO_CLASS_HANDLE result = jitInstance->mc->repGetSZArrayHelperEnumeratorClass(cls); - return result; -} - -void MyICJI::expandRawHandleIntrinsic(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_HANDLE callerHandle, CORINFO_GENERICHANDLE_RESULT* pResult) -{ - jitInstance->mc->cr->AddCall("expandRawHandleIntrinsic"); - jitInstance->mc->repExpandRawHandleIntrinsic(pResolvedToken, callerHandle, pResult); -} - -// Is the given type in System.Private.Corelib and marked with IntrinsicAttribute? -bool MyICJI::isIntrinsicType(CORINFO_CLASS_HANDLE classHnd) -{ - jitInstance->mc->cr->AddCall("isIntrinsicType"); - return jitInstance->mc->repIsIntrinsicType(classHnd) ? true : false; -} - -// return the entry point calling convention for any of the following -// - a P/Invoke -// - a method marked with UnmanagedCallersOnly -// - a function pointer with the CORINFO_CALLCONV_UNMANAGED calling convention. -CorInfoCallConvExtension MyICJI::getUnmanagedCallConv(CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* callSiteSig, bool* pSuppressGCTransition) -{ - jitInstance->mc->cr->AddCall("getUnmanagedCallConv"); - return jitInstance->mc->repGetUnmanagedCallConv(method, callSiteSig, pSuppressGCTransition); -} - -// return if any marshaling is required for PInvoke methods. Note that -// method == 0 => calli. The call site sig is only needed for the varargs or calli case -bool MyICJI::pInvokeMarshalingRequired(CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* callSiteSig) -{ - jitInstance->mc->cr->AddCall("pInvokeMarshalingRequired"); - return jitInstance->mc->repPInvokeMarshalingRequired(method, callSiteSig); -} - -// Check constraints on method type arguments (only). -bool MyICJI::satisfiesMethodConstraints(CORINFO_CLASS_HANDLE parent, // the exact parent of the method - CORINFO_METHOD_HANDLE method) -{ - jitInstance->mc->cr->AddCall("satisfiesMethodConstraints"); - return jitInstance->mc->repSatisfiesMethodConstraints(parent, method); -} - -// Returns the global cookie for the /GS unsafe buffer checks -// The cookie might be a constant value (JIT), or a handle to memory location (Ngen) -void MyICJI::getGSCookie(GSCookie* pCookieVal, // OUT - GSCookie** ppCookieVal // OUT - ) -{ - jitInstance->mc->cr->AddCall("getGSCookie"); - jitInstance->mc->repGetGSCookie(pCookieVal, ppCookieVal); -} - -// Provide patchpoint info for the method currently being jitted. -void MyICJI::setPatchpointInfo(PatchpointInfo* patchpointInfo) -{ - jitInstance->mc->cr->AddCall("setPatchpointInfo"); - jitInstance->mc->cr->recSetPatchpointInfo(patchpointInfo); - freeArray(patchpointInfo); // See note in recSetPatchpointInfo... we own destroying this array -} - -// Get OSR info for the method currently being jitted -PatchpointInfo* MyICJI::getOSRInfo(unsigned* ilOffset) -{ - jitInstance->mc->cr->AddCall("getOSRInfo"); - return jitInstance->mc->repGetOSRInfo(ilOffset); -} - -/**********************************************************************************/ -// -// ICorModuleInfo -// -/**********************************************************************************/ - -// Resolve metadata token into runtime method handles. -void MyICJI::resolveToken(/* IN, OUT */ CORINFO_RESOLVED_TOKEN* pResolvedToken) -{ - DWORD exceptionCode = 0; - jitInstance->mc->cr->AddCall("resolveToken"); - jitInstance->mc->repResolveToken(pResolvedToken, &exceptionCode); - if (exceptionCode != 0) - ThrowRecordedException(exceptionCode); -} - -// Signature information about the call sig -void MyICJI::findSig(CORINFO_MODULE_HANDLE module, /* IN */ - unsigned sigTOK, /* IN */ - CORINFO_CONTEXT_HANDLE context, /* IN */ - CORINFO_SIG_INFO* sig /* OUT */ - ) -{ - jitInstance->mc->cr->AddCall("findSig"); - jitInstance->mc->repFindSig(module, sigTOK, context, sig); -} - -// for Varargs, the signature at the call site may differ from -// the signature at the definition. Thus we need a way of -// fetching the call site information -void MyICJI::findCallSiteSig(CORINFO_MODULE_HANDLE module, /* IN */ - unsigned methTOK, /* IN */ - CORINFO_CONTEXT_HANDLE context, /* IN */ - CORINFO_SIG_INFO* sig /* OUT */ - ) -{ - jitInstance->mc->cr->AddCall("findCallSiteSig"); - jitInstance->mc->repFindCallSiteSig(module, methTOK, context, sig); -} - -CORINFO_CLASS_HANDLE MyICJI::getTokenTypeAsHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken /* IN */) -{ - jitInstance->mc->cr->AddCall("getTokenTypeAsHandle"); - return jitInstance->mc->repGetTokenTypeAsHandle(pResolvedToken); -} - -int MyICJI::getStringLiteral(CORINFO_MODULE_HANDLE module, /* IN */ - unsigned metaTOK, /* IN */ - char16_t* buffer, /* OUT */ - int bufferSize,/* IN */ - int startIndex - ) -{ - jitInstance->mc->cr->AddCall("getStringLiteral"); - return jitInstance->mc->repGetStringLiteral(module, metaTOK, buffer, bufferSize, startIndex); -} - -size_t MyICJI::printObjectDescription(CORINFO_OBJECT_HANDLE handle, /* IN */ - char* buffer, /* OUT */ - size_t bufferSize, /* IN */ - size_t* pRequiredBufferSize /* OUT */ - ) -{ - jitInstance->mc->cr->AddCall("printObjectDescription"); - return jitInstance->mc->repPrintObjectDescription(handle, buffer, bufferSize, pRequiredBufferSize); -} - -/**********************************************************************************/ -// -// ICorClassInfo -// -/**********************************************************************************/ - -// If the value class 'cls' is isomorphic to a primitive type it will -// return that type, otherwise it will return CORINFO_TYPE_VALUECLASS -CorInfoType MyICJI::asCorInfoType(CORINFO_CLASS_HANDLE cls) -{ - jitInstance->mc->cr->AddCall("asCorInfoType"); - return jitInstance->mc->repAsCorInfoType(cls); -} - -const char* MyICJI::getClassNameFromMetadata(CORINFO_CLASS_HANDLE cls, const char** namespaceName) -{ - jitInstance->mc->cr->AddCall("getClassNameFromMetadata"); - const char* result = jitInstance->mc->repGetClassNameFromMetadata(cls, namespaceName); - return result; -} - -CORINFO_CLASS_HANDLE MyICJI::getTypeInstantiationArgument(CORINFO_CLASS_HANDLE cls, unsigned index) -{ - jitInstance->mc->cr->AddCall("getTypeInstantiationArgument"); - CORINFO_CLASS_HANDLE result = jitInstance->mc->repGetTypeInstantiationArgument(cls, index); - return result; -} - -CORINFO_CLASS_HANDLE MyICJI::getMethodInstantiationArgument(CORINFO_METHOD_HANDLE ftn, unsigned index) -{ - jitInstance->mc->cr->AddCall("getMethodInstantiationArgument"); - CORINFO_CLASS_HANDLE result = jitInstance->mc->repGetMethodInstantiationArgument(ftn, index); - return result; -} - -size_t MyICJI::printClassName(CORINFO_CLASS_HANDLE cls, char* buffer, size_t bufferSize, size_t* pRequiredBufferSize) -{ - jitInstance->mc->cr->AddCall("printClassName"); - return jitInstance->mc->repPrintClassName(cls, buffer, bufferSize, pRequiredBufferSize); -} - -// Quick check whether the type is a value class. Returns the same value as getClassAttribs(cls) & -// CORINFO_FLG_VALUECLASS, except faster. -bool MyICJI::isValueClass(CORINFO_CLASS_HANDLE cls) -{ - jitInstance->mc->cr->AddCall("isValueClass"); - return jitInstance->mc->repIsValueClass(cls); -} - -bool MyICJI::isByRefLike(CORINFO_CLASS_HANDLE cls) -{ - jitInstance->mc->cr->AddCall("isByRefLike"); - return jitInstance->mc->repIsByRefLike(cls); -} - -bool MyICJI::isSharedInst(CORINFO_CLASS_HANDLE cls) -{ - jitInstance->mc->cr->AddCall("isSharedInst"); - return jitInstance->mc->repIsSharedInst(cls); -} - -// return flags (defined above, CORINFO_FLG_PUBLIC ...) -uint32_t MyICJI::getClassAttribs(CORINFO_CLASS_HANDLE cls) -{ - jitInstance->mc->cr->AddCall("getClassAttribs"); - return jitInstance->mc->repGetClassAttribs(cls); -} - -// Returns the assembly name of the class "cls". -const char* MyICJI::getClassAssemblyName(CORINFO_CLASS_HANDLE cls) -{ - jitInstance->mc->cr->AddCall("getClassAssemblyName"); - return jitInstance->mc->repGetClassAssemblyName(cls); -} - -// Allocate and delete process-lifetime objects. Should only be -// referred to from static fields, lest a leak occur. -// Note that "LongLifetimeFree" does not execute destructors, if "obj" -// is an array of a struct type with a destructor. -void* MyICJI::LongLifetimeMalloc(size_t sz) -{ - jitInstance->mc->cr->AddCall("LongLifetimeMalloc"); - LogError("Hit unimplemented LongLifetimeMalloc"); - DebugBreakorAV(32); - return 0; -} - -void MyICJI::LongLifetimeFree(void* obj) -{ - jitInstance->mc->cr->AddCall("LongLifetimeFree"); - LogError("Hit unimplemented LongLifetimeFree"); - DebugBreakorAV(33); -} - -void* MyICJI::getClassThreadStaticDynamicInfo(CORINFO_CLASS_HANDLE cls) -{ - jitInstance->mc->cr->AddCall("getClassThreadStaticDynamicInfo"); - return jitInstance->mc->repGetClassThreadStaticDynamicInfo(cls); -} - -void* MyICJI::getClassStaticDynamicInfo(CORINFO_CLASS_HANDLE cls) -{ - jitInstance->mc->cr->AddCall("getClassStaticDynamicInfo"); - return jitInstance->mc->repGetClassStaticDynamicInfo(cls); -} - -bool MyICJI::getIsClassInitedFlagAddress(CORINFO_CLASS_HANDLE cls, - CORINFO_CONST_LOOKUP* addr, - int* offset) -{ - jitInstance->mc->cr->AddCall("getIsClassInitedFlagAddress"); - return jitInstance->mc->repGetIsClassInitedFlagAddress(cls, addr, offset); -} - -bool MyICJI::getStaticBaseAddress(CORINFO_CLASS_HANDLE cls, - bool isGc, - CORINFO_CONST_LOOKUP* addr) -{ - jitInstance->mc->cr->AddCall("getStaticBaseAddress"); - return jitInstance->mc->repGetStaticBaseAddress(cls, isGc, addr); -} - -// return the number of bytes needed by an instance of the class -unsigned MyICJI::getClassSize(CORINFO_CLASS_HANDLE cls) -{ - jitInstance->mc->cr->AddCall("getClassSize"); - return jitInstance->mc->repGetClassSize(cls); -} - -// return the number of bytes needed by an instance of the class allocated on the heap -unsigned MyICJI::getHeapClassSize(CORINFO_CLASS_HANDLE cls) -{ - jitInstance->mc->cr->AddCall("getHeapClassSize"); - return jitInstance->mc->repGetHeapClassSize(cls); -} - -bool MyICJI::canAllocateOnStack(CORINFO_CLASS_HANDLE cls) -{ - jitInstance->mc->cr->AddCall("canAllocateOnStack"); - return jitInstance->mc->repCanAllocateOnStack(cls); -} - -unsigned MyICJI::getClassAlignmentRequirement(CORINFO_CLASS_HANDLE cls, bool fDoubleAlignHint) -{ - jitInstance->mc->cr->AddCall("getClassAlignmentRequirement"); - return jitInstance->mc->repGetClassAlignmentRequirement(cls, fDoubleAlignHint); -} - -// This called for ref and value classes. It returns a boolean array -// in representing of 'cls' from a GC perspective. The class is -// assumed to be an array of machine words -// (of length // getClassSize(cls) / sizeof(void*)), -// 'gcPtrs' is a pointer to an array of BYTEs of this length. -// getClassGClayout fills in this array so that gcPtrs[i] is set -// to one of the CorInfoGCType values which is the GC type of -// the i-th machine word of an object of type 'cls' -// returns the number of GC pointers in the array -unsigned MyICJI::getClassGClayout(CORINFO_CLASS_HANDLE cls, /* IN */ - BYTE* gcPtrs /* OUT */ - ) -{ - jitInstance->mc->cr->AddCall("getClassGClayout"); - return jitInstance->mc->repGetClassGClayout(cls, gcPtrs); -} - -// returns the number of instance fields in a class -unsigned MyICJI::getClassNumInstanceFields(CORINFO_CLASS_HANDLE cls /* IN */ - ) -{ - jitInstance->mc->cr->AddCall("getClassNumInstanceFields"); - return jitInstance->mc->repGetClassNumInstanceFields(cls); -} - -CORINFO_FIELD_HANDLE MyICJI::getFieldInClass(CORINFO_CLASS_HANDLE clsHnd, INT num) -{ - jitInstance->mc->cr->AddCall("getFieldInClass"); - return jitInstance->mc->repGetFieldInClass(clsHnd, num); -} - -GetTypeLayoutResult MyICJI::getTypeLayout( - CORINFO_CLASS_HANDLE typeHnd, - CORINFO_TYPE_LAYOUT_NODE* nodes, - size_t* numNodes) -{ - jitInstance->mc->cr->AddCall("getTypeLayout"); - return jitInstance->mc->repGetTypeLayout(typeHnd, nodes, numNodes); -} - -bool MyICJI::checkMethodModifier(CORINFO_METHOD_HANDLE hMethod, LPCSTR modifier, bool fOptional) -{ - jitInstance->mc->cr->AddCall("checkMethodModifier"); - bool result = jitInstance->mc->repCheckMethodModifier(hMethod, modifier, fOptional); - return result; -} - -// returns the "NEW" helper optimized for "newCls." -CorInfoHelpFunc MyICJI::getNewHelper(CORINFO_CLASS_HANDLE classHandle, bool* pHasSideEffects) -{ - jitInstance->mc->cr->AddCall("getNewHelper"); - DWORD exceptionCode = 0; - CorInfoHelpFunc result = jitInstance->mc->repGetNewHelper(classHandle, pHasSideEffects, &exceptionCode); - if (exceptionCode != 0) - ThrowRecordedException(exceptionCode); - return result; -} - -// returns the newArr (1-Dim array) helper optimized for "arrayCls." -CorInfoHelpFunc MyICJI::getNewArrHelper(CORINFO_CLASS_HANDLE arrayCls) -{ - jitInstance->mc->cr->AddCall("getNewArrHelper"); - return jitInstance->mc->repGetNewArrHelper(arrayCls); -} - -// returns the optimized "IsInstanceOf" or "ChkCast" helper -CorInfoHelpFunc MyICJI::getCastingHelper(CORINFO_RESOLVED_TOKEN* pResolvedToken, bool fThrowing) -{ - jitInstance->mc->cr->AddCall("getCastingHelper"); - return jitInstance->mc->repGetCastingHelper(pResolvedToken, fThrowing); -} - -// returns helper to trigger static constructor -CorInfoHelpFunc MyICJI::getSharedCCtorHelper(CORINFO_CLASS_HANDLE clsHnd) -{ - jitInstance->mc->cr->AddCall("getSharedCCtorHelper"); - return jitInstance->mc->repGetSharedCCtorHelper(clsHnd); -} - -// This is not pretty. Boxing nullable actually returns -// a boxed not a boxed Nullable. This call allows the verifier -// to call back to the EE on the 'box' instruction and get the transformed -// type to use for verification. -CORINFO_CLASS_HANDLE MyICJI::getTypeForBox(CORINFO_CLASS_HANDLE cls) -{ - jitInstance->mc->cr->AddCall("getTypeForBox"); - return jitInstance->mc->repGetTypeForBox(cls); -} - -// returns the correct box helper for a particular class. Note -// that if this returns CORINFO_HELP_BOX, the JIT can assume -// 'standard' boxing (allocate object and copy), and optimize -CorInfoHelpFunc MyICJI::getBoxHelper(CORINFO_CLASS_HANDLE cls) -{ - jitInstance->mc->cr->AddCall("getBoxHelper"); - return jitInstance->mc->repGetBoxHelper(cls); -} - -// returns the unbox helper. If 'helperCopies' points to a true -// value it means the JIT is requesting a helper that unboxes the -// value into a particular location and thus has the signature -// void unboxHelper(void* dest, CORINFO_CLASS_HANDLE cls, Object* obj) -// Otherwise (it is null or points at a FALSE value) it is requesting -// a helper that returns a pointer to the unboxed data -// void* unboxHelper(CORINFO_CLASS_HANDLE cls, Object* obj) -// The EE has the option of NOT returning the copy style helper -// (But must be able to always honor the non-copy style helper) -// The EE set 'helperCopies' on return to indicate what kind of -// helper has been created. - -CorInfoHelpFunc MyICJI::getUnBoxHelper(CORINFO_CLASS_HANDLE cls) -{ - jitInstance->mc->cr->AddCall("getUnBoxHelper"); - CorInfoHelpFunc result = jitInstance->mc->repGetUnBoxHelper(cls); - return result; -} - -CORINFO_OBJECT_HANDLE MyICJI::getRuntimeTypePointer(CORINFO_CLASS_HANDLE cls) -{ - jitInstance->mc->cr->AddCall("getRuntimeTypePointer"); - CORINFO_OBJECT_HANDLE result = jitInstance->mc->repGetRuntimeTypePointer(cls); - return result; -} - -bool MyICJI::isObjectImmutable(CORINFO_OBJECT_HANDLE objPtr) -{ - jitInstance->mc->cr->AddCall("isObjectImmutable"); - bool result = jitInstance->mc->repIsObjectImmutable(objPtr); - return result; -} - -bool MyICJI::getStringChar(CORINFO_OBJECT_HANDLE strObj, int index, uint16_t* value) -{ - jitInstance->mc->cr->AddCall("getStringChar"); - bool result = jitInstance->mc->repGetStringChar(strObj, index, value); - return result; -} - -CORINFO_CLASS_HANDLE MyICJI::getObjectType(CORINFO_OBJECT_HANDLE objPtr) -{ - jitInstance->mc->cr->AddCall("getObjectType"); - CORINFO_CLASS_HANDLE result = jitInstance->mc->repGetObjectType(objPtr); - return result; -} - -bool MyICJI::getReadyToRunHelper(CORINFO_RESOLVED_TOKEN* pResolvedToken, - CorInfoHelpFunc id, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_CONST_LOOKUP* pLookup) -{ - jitInstance->mc->cr->AddCall("getReadyToRunHelper"); - return jitInstance->mc->repGetReadyToRunHelper(pResolvedToken, id, callerHandle, pLookup); -} - -void MyICJI::getReadyToRunDelegateCtorHelper(CORINFO_RESOLVED_TOKEN* pTargetMethod, - mdToken targetConstraint, - CORINFO_CLASS_HANDLE delegateType, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_LOOKUP* pLookup) -{ - jitInstance->mc->cr->AddCall("getReadyToRunDelegateCtorHelper"); - jitInstance->mc->repGetReadyToRunDelegateCtorHelper(pTargetMethod, targetConstraint, delegateType, callerHandle, pLookup); -} - -// This function tries to initialize the class (run the class constructor). -// this function returns whether the JIT must insert helper calls before -// accessing static field or method. -// -// See code:ICorClassInfo#ClassConstruction. -CorInfoInitClassResult MyICJI::initClass(CORINFO_FIELD_HANDLE field, // Non-nullptr - inquire about cctor trigger before - // static field access nullptr - inquire about - // cctor trigger in method prolog - CORINFO_METHOD_HANDLE method, // Method referencing the field or prolog - CORINFO_CONTEXT_HANDLE context // Exact context of method - ) -{ - jitInstance->mc->cr->AddCall("initClass"); - return jitInstance->mc->repInitClass(field, method, context); -} - -// returns the class handle for the special builtin classes -CORINFO_CLASS_HANDLE MyICJI::getBuiltinClass(CorInfoClassId classId) -{ - jitInstance->mc->cr->AddCall("getBuiltinClass"); - return jitInstance->mc->repGetBuiltinClass(classId); -} - -// "System.Int32" ==> CORINFO_TYPE_INT.. -CorInfoType MyICJI::getTypeForPrimitiveValueClass(CORINFO_CLASS_HANDLE cls) -{ - jitInstance->mc->cr->AddCall("getTypeForPrimitiveValueClass"); - return jitInstance->mc->repGetTypeForPrimitiveValueClass(cls); -} - -// "System.Int32" ==> CORINFO_TYPE_INT.. -// "System.UInt32" ==> CORINFO_TYPE_UINT.. -CorInfoType MyICJI::getTypeForPrimitiveNumericClass(CORINFO_CLASS_HANDLE cls) -{ - jitInstance->mc->cr->AddCall("getTypeForPrimitiveNumericClass"); - return jitInstance->mc->repGetTypeForPrimitiveNumericClass(cls); -} - -// TRUE if child is a subtype of parent -// if parent is an interface, then does child implement / extend parent -bool MyICJI::canCast(CORINFO_CLASS_HANDLE child, // subtype (extends parent) - CORINFO_CLASS_HANDLE parent // base type - ) -{ - jitInstance->mc->cr->AddCall("canCast"); - return jitInstance->mc->repCanCast(child, parent); -} - -// See if a cast from fromClass to toClass will succeed, fail, or needs -// to be resolved at runtime. -TypeCompareState MyICJI::compareTypesForCast(CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass) -{ - jitInstance->mc->cr->AddCall("compareTypesForCast"); - return jitInstance->mc->repCompareTypesForCast(fromClass, toClass); -} - -// See if types represented by cls1 and cls2 compare equal, not -// equal, or the comparison needs to be resolved at runtime. -TypeCompareState MyICJI::compareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2) -{ - jitInstance->mc->cr->AddCall("compareTypesForEquality"); - return jitInstance->mc->repCompareTypesForEquality(cls1, cls2); -} - -// Returns true if cls2 is known to be a more specific type than cls1 -bool MyICJI::isMoreSpecificType(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2) -{ - jitInstance->mc->cr->AddCall("isMoreSpecificType"); - return jitInstance->mc->repIsMoreSpecificType(cls1, cls2); -} - -// Returns true if a class handle can only describe values of exactly one type. -bool MyICJI::isExactType(CORINFO_CLASS_HANDLE cls) -{ - jitInstance->mc->cr->AddCall("isExactType"); - return jitInstance->mc->repIsExactType(cls); -} - -// Returns true if a class handle represents a generic type. -TypeCompareState MyICJI::isGenericType(CORINFO_CLASS_HANDLE cls) -{ - jitInstance->mc->cr->AddCall("isGenericType"); - return jitInstance->mc->repIsGenericType(cls); -} - -// Returns true if a class handle represents a Nullable type. -TypeCompareState MyICJI::isNullableType(CORINFO_CLASS_HANDLE cls) -{ - jitInstance->mc->cr->AddCall("isNullableType"); - return jitInstance->mc->repIsNullableType(cls); -} - -// Returns TypeCompareState::Must if cls is known to be an enum. -// For enums with known exact type returns the underlying -// type in underlyingType when the provided pointer is -// non-NULL. -// Returns TypeCompareState::May when a runtime check is required. -TypeCompareState MyICJI::isEnum(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE* underlyingType) -{ - jitInstance->mc->cr->AddCall("isEnum"); - return jitInstance->mc->repIsEnum(cls, underlyingType); -} - -// Given a class handle, returns the Parent type. -// For COMObjectType, it returns Class Handle of System.Object. -// Returns 0 if System.Object is passed in. -CORINFO_CLASS_HANDLE MyICJI::getParentType(CORINFO_CLASS_HANDLE cls) -{ - jitInstance->mc->cr->AddCall("getParentType"); - return jitInstance->mc->repGetParentType(cls); -} - -// Returns the CorInfoType of the "child type". If the child type is -// not a primitive type, *clsRet will be set. -// Given an Array of Type Foo, returns Foo. -// Given BYREF Foo, returns Foo -CorInfoType MyICJI::getChildType(CORINFO_CLASS_HANDLE clsHnd, CORINFO_CLASS_HANDLE* clsRet) -{ - jitInstance->mc->cr->AddCall("getChildType"); - return jitInstance->mc->repGetChildType(clsHnd, clsRet); -} - -// Check if this is a single dimensional array type -bool MyICJI::isSDArray(CORINFO_CLASS_HANDLE cls) -{ - jitInstance->mc->cr->AddCall("isSDArray"); - return jitInstance->mc->repIsSDArray(cls); -} - -// Get the numbmer of dimensions in an array -unsigned MyICJI::getArrayRank(CORINFO_CLASS_HANDLE cls) -{ - jitInstance->mc->cr->AddCall("getArrayRank"); - return jitInstance->mc->repGetArrayRank(cls); -} - -// Get the index of runtime provided array method -CorInfoArrayIntrinsic MyICJI::getArrayIntrinsicID(CORINFO_METHOD_HANDLE hMethod) -{ - jitInstance->mc->cr->AddCall("getArrayIntrinsicID"); - return jitInstance->mc->repGetArrayIntrinsicID(hMethod); -} - -// Get static field data for an array -void* MyICJI::getArrayInitializationData(CORINFO_FIELD_HANDLE field, uint32_t size) -{ - jitInstance->mc->cr->AddCall("getArrayInitializationData"); - return jitInstance->mc->repGetArrayInitializationData(field, size); -} - -// Check Visibility rules. -CorInfoIsAccessAllowedResult MyICJI::canAccessClass(CORINFO_RESOLVED_TOKEN* pResolvedToken, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_HELPER_DESC* pAccessHelper /* If canAccessMethod returns - something other than - ALLOWED, - then this is filled in. */ - ) -{ - jitInstance->mc->cr->AddCall("canAccessClass"); - return jitInstance->mc->repCanAccessClass(pResolvedToken, callerHandle, pAccessHelper); -} - -/**********************************************************************************/ -// -// ICorFieldInfo -// -/**********************************************************************************/ - -size_t MyICJI::printFieldName(CORINFO_FIELD_HANDLE field, char* buffer, size_t bufferSize, size_t* pRequiredBufferSize) -{ - jitInstance->mc->cr->AddCall("printFieldName"); - return jitInstance->mc->repPrintFieldName(field, buffer, bufferSize, pRequiredBufferSize); -} - -// return class it belongs to -CORINFO_CLASS_HANDLE MyICJI::getFieldClass(CORINFO_FIELD_HANDLE field) -{ - jitInstance->mc->cr->AddCall("getFieldClass"); - return jitInstance->mc->repGetFieldClass(field); -} - -// Return the field's type, if it is CORINFO_TYPE_VALUECLASS 'structType' is set -// the field's value class (if 'structType' == 0, then don't bother -// the structure info). -// -// 'fieldOwnerHint' is, potentially, a more exact owner of the field. -// it's fine for it to be non-precise, it's just a hint. -CorInfoType MyICJI::getFieldType(CORINFO_FIELD_HANDLE field, - CORINFO_CLASS_HANDLE* structType, - CORINFO_CLASS_HANDLE fieldOwnerHint /* IN */ - ) -{ - jitInstance->mc->cr->AddCall("getFieldType"); - return jitInstance->mc->repGetFieldType(field, structType, fieldOwnerHint); -} - -// return the data member's instance offset -unsigned MyICJI::getFieldOffset(CORINFO_FIELD_HANDLE field) -{ - jitInstance->mc->cr->AddCall("getFieldOffset"); - return jitInstance->mc->repGetFieldOffset(field); -} - -void MyICJI::getFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_ACCESS_FLAGS flags, - CORINFO_FIELD_INFO* pResult) -{ - jitInstance->mc->cr->AddCall("getFieldInfo"); - jitInstance->mc->repGetFieldInfo(pResolvedToken, callerHandle, flags, pResult); -} - -uint32_t MyICJI::getThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, bool isGCType) -{ - jitInstance->mc->cr->AddCall("getThreadLocalFieldInfo"); - return jitInstance->mc->repGetThreadLocalFieldInfo(field, isGCType); -} - -void MyICJI::getThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) -{ - jitInstance->mc->cr->AddCall("getThreadLocalStaticBlocksInfo"); - jitInstance->mc->repGetThreadLocalStaticBlocksInfo(pInfo); -} - -void MyICJI::getThreadLocalStaticInfo_NativeAOT(CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo) -{ - jitInstance->mc->cr->AddCall("getThreadLocalStaticInfo_NativeAOT"); - jitInstance->mc->repGetThreadLocalStaticInfo_NativeAOT(pInfo); -} - -// Returns true iff "fldHnd" represents a static field. -bool MyICJI::isFieldStatic(CORINFO_FIELD_HANDLE fldHnd) -{ - jitInstance->mc->cr->AddCall("isFieldStatic"); - return jitInstance->mc->repIsFieldStatic(fldHnd); -} - -int MyICJI::getArrayOrStringLength(CORINFO_OBJECT_HANDLE objHnd) -{ - jitInstance->mc->cr->AddCall("getArrayOrStringLength"); - return jitInstance->mc->repGetArrayOrStringLength(objHnd); -} - -/*********************************************************************************/ -// -// ICorDebugInfo -// -/*********************************************************************************/ - -// Query the EE to find out where interesting break points -// in the code are. The native compiler will ensure that these places -// have a corresponding break point in native code. -// -// Note that unless CORJIT_FLAG_DEBUG_CODE is specified, this function will -// be used only as a hint and the native compiler should not change its -// code generation. -void MyICJI::getBoundaries(CORINFO_METHOD_HANDLE ftn, // [IN] method of interest - unsigned int* cILOffsets, // [OUT] size of pILOffsets - uint32_t** pILOffsets, // [OUT] IL offsets of interest - // jit MUST free with freeArray! - ICorDebugInfo::BoundaryTypes* implicitBoundaries // [OUT] tell jit, all boundaries of this type - ) -{ - jitInstance->mc->cr->AddCall("getBoundaries"); - jitInstance->mc->repGetBoundaries(ftn, cILOffsets, pILOffsets, implicitBoundaries); - - // The JIT will want to call freearray on the array we pass back, so move the data into a form that complies with - // this - if (*cILOffsets > 0) - { - uint32_t* realOffsets = (uint32_t*)allocateArray(*cILOffsets * sizeof(ICorDebugInfo::BoundaryTypes)); - memcpy(realOffsets, *pILOffsets, *cILOffsets * sizeof(ICorDebugInfo::BoundaryTypes)); - *pILOffsets = realOffsets; - } - else - *pILOffsets = 0; -} - -// Report back the mapping from IL to native code, -// this map should include all boundaries that 'getBoundaries' -// reported as interesting to the debugger. - -// Note that debugger (and profiler) is assuming that all of the -// offsets form a contiguous block of memory, and that the -// OffsetMapping is sorted in order of increasing native offset. -void MyICJI::setBoundaries(CORINFO_METHOD_HANDLE ftn, // [IN] method of interest - ULONG32 cMap, // [IN] size of pMap - ICorDebugInfo::OffsetMapping* pMap // [IN] map including all points of interest. - // jit allocated with allocateArray, EE frees - ) -{ - jitInstance->mc->cr->AddCall("setBoundaries"); - jitInstance->mc->cr->recSetBoundaries(ftn, cMap, pMap); - - freeArray(pMap); // see note in recSetBoundaries... we own this array and own destroying it. -} - -// Query the EE to find out the scope of local variables. -// normally the JIT would trash variables after last use, but -// under debugging, the JIT needs to keep them live over their -// entire scope so that they can be inspected. -// -// Note that unless CORJIT_FLAG_DEBUG_CODE is specified, this function will -// be used only as a hint and the native compiler should not change its -// code generation. -void MyICJI::getVars(CORINFO_METHOD_HANDLE ftn, // [IN] method of interest - ULONG32* cVars, // [OUT] size of 'vars' - ICorDebugInfo::ILVarInfo** vars, // [OUT] scopes of variables of interest - // jit MUST free with freeArray! - bool* extendOthers // [OUT] it TRUE, then assume the scope - // of unmentioned vars is entire method - ) -{ - jitInstance->mc->cr->AddCall("getVars"); - jitInstance->mc->repGetVars(ftn, cVars, vars, extendOthers); - - // The JIT will want to call freearray on the array we pass back, so move the data into a form that complies with - // this - if (*cVars > 0) - { - ICorDebugInfo::ILVarInfo* realOffsets = - (ICorDebugInfo::ILVarInfo*)allocateArray(*cVars * sizeof(ICorDebugInfo::ILVarInfo)); - memcpy(realOffsets, *vars, *cVars * sizeof(ICorDebugInfo::ILVarInfo)); - *vars = realOffsets; - } - else - *vars = nullptr; -} - -// Report back to the EE the location of every variable. -// note that the JIT might split lifetimes into different -// locations etc. - -void MyICJI::setVars(CORINFO_METHOD_HANDLE ftn, // [IN] method of interest - ULONG32 cVars, // [IN] size of 'vars' - ICorDebugInfo::NativeVarInfo* vars // [IN] map telling where local vars are stored at what points - // jit allocated with allocateArray, EE frees - ) -{ - jitInstance->mc->cr->AddCall("setVars"); - jitInstance->mc->cr->recSetVars(ftn, cVars, vars); - freeArray(vars); // See note in recSetVars... we own destroying this array -} - -void MyICJI::reportRichMappings( - ICorDebugInfo::InlineTreeNode* inlineTreeNodes, - uint32_t numInlineTreeNodes, - ICorDebugInfo::RichOffsetMapping* mappings, - uint32_t numMappings) -{ - jitInstance->mc->cr->AddCall("reportRichMappings"); - // Compile output that we do not currently save - freeArray(inlineTreeNodes); - freeArray(mappings); -} - -void MyICJI::reportAsyncDebugInfo( - ICorDebugInfo::AsyncInfo* asyncInfo, - ICorDebugInfo::AsyncSuspensionPoint* suspensionPoints, - ICorDebugInfo::AsyncContinuationVarInfo* vars, - uint32_t numVars) -{ - jitInstance->mc->cr->AddCall("reportAsyncDebugInfo"); - // Compile output that we do not currently save - freeArray(suspensionPoints); - freeArray(vars); -} - -void MyICJI::reportMetadata(const char* key, const void* value, size_t length) -{ - jitInstance->mc->cr->AddCall("reportMetadata"); - - if (strcmp(key, "MethodFullName") == 0) - { - char* buf = static_cast(jitInstance->mc->cr->allocateMemory(length + 1)); - memcpy(buf, value, length + 1); - jitInstance->mc->cr->MethodFullName = buf; - return; - } - - if (strcmp(key, "TieringName") == 0) - { - char* buf = static_cast(jitInstance->mc->cr->allocateMemory(length + 1)); - memcpy(buf, value, length + 1); - jitInstance->mc->cr->TieringName = buf; - return; - } - - struct MetricEntry - { - const char* Name; - void (*Store)(CompileResult* cr, const void* value, size_t length); - }; - - static const MetricEntry s_metrics[] = { -#define JITMETADATAINFO(name, type, flags) -#define JITMETADATAMETRIC(name, type, flags) \ - {#name, [](CompileResult* cr, const void* value, size_t length) { \ - if (length == sizeof(type)) \ - { \ - cr->name = *static_cast(value); \ - } \ - }}, -#include "jitmetadatalist.h" - }; - - const size_t count = ArrLen(s_metrics); - - // The JIT reports metrics in the order they are declared in jitmetadatalist.h, - // so resume the search where the previous one matched instead of always scanning - // from the start. In practice this matches on the first comparison. - size_t index = m_metricSearchStart; - for (size_t i = 0; i < count; i++) - { - const MetricEntry& entry = s_metrics[index]; - - index++; - if (index == count) - { - index = 0; - } - - if (strcmp(key, entry.Name) == 0) - { - m_metricSearchStart = index; - entry.Store(jitInstance->mc->cr, value, length); - return; - } - } -} - -/*-------------------------- Misc ---------------------------------------*/ - -// Used to allocate memory that needs to handed to the EE. -// For eg, use this to allocated memory for reporting debug info, -// which will be handed to the EE by setVars() and setBoundaries() -void* MyICJI::allocateArray(size_t cBytes) -{ - return jitInstance->allocateArray(cBytes); -} - -// JitCompiler will free arrays passed by the EE using this -// For eg, The EE returns memory in getVars() and getBoundaries() -// to the JitCompiler, which the JitCompiler should release using -// freeArray() -void MyICJI::freeArray(void* array) -{ - jitInstance->freeArray(array); -} - -/*********************************************************************************/ -// -// ICorArgInfo -// -/*********************************************************************************/ - -// advance the pointer to the argument list. -// a ptr of 0, is special and always means the first argument -CORINFO_ARG_LIST_HANDLE MyICJI::getArgNext(CORINFO_ARG_LIST_HANDLE args /* IN */ - ) -{ - jitInstance->mc->cr->AddCall("getArgNext"); - return jitInstance->mc->repGetArgNext(args); -} - -// Get the type of a particular argument -// CORINFO_TYPE_UNDEF is returned when there are no more arguments -// If the type returned is a primitive type (or an enum) *vcTypeRet set to nullptr -// otherwise it is set to the TypeHandle associted with the type -// Enumerations will always look their underlying type (probably should fix this) -// Otherwise vcTypeRet is the type as would be seen by the IL, -// The return value is the type that is used for calling convention purposes -// (Thus if the EE wants a value class to be passed like an int, then it will -// return CORINFO_TYPE_INT -CorInfoTypeWithMod MyICJI::getArgType(CORINFO_SIG_INFO* sig, /* IN */ - CORINFO_ARG_LIST_HANDLE args, /* IN */ - CORINFO_CLASS_HANDLE* vcTypeRet /* OUT */ - ) -{ - DWORD exceptionCode = 0; - jitInstance->mc->cr->AddCall("getArgType"); - CorInfoTypeWithMod value = jitInstance->mc->repGetArgType(sig, args, vcTypeRet, &exceptionCode); - if (exceptionCode != 0) - ThrowRecordedException(exceptionCode); - return value; -} - -int MyICJI::getExactClasses(CORINFO_CLASS_HANDLE baseType, /* IN */ - int maxExactClasses, /* IN */ - CORINFO_CLASS_HANDLE* exactClsRet /* OUT */ - ) -{ - jitInstance->mc->cr->AddCall("getExactClasses"); - return jitInstance->mc->repGetExactClasses(baseType, maxExactClasses, exactClsRet); -} - -// If the Arg is a CORINFO_TYPE_CLASS fetch the class handle associated with it -CORINFO_CLASS_HANDLE MyICJI::getArgClass(CORINFO_SIG_INFO* sig, /* IN */ - CORINFO_ARG_LIST_HANDLE args /* IN */ - ) -{ - DWORD exceptionCode = 0; - jitInstance->mc->cr->AddCall("getArgClass"); - CORINFO_CLASS_HANDLE value = jitInstance->mc->repGetArgClass(sig, args, &exceptionCode); - if (exceptionCode != 0) - ThrowRecordedException(exceptionCode); - return value; -} - -// Returns type of HFA for valuetype -CorInfoHFAElemType MyICJI::getHFAType(CORINFO_CLASS_HANDLE hClass) -{ - jitInstance->mc->cr->AddCall("getHFAType"); - CorInfoHFAElemType value = jitInstance->mc->repGetHFAType(hClass); - return value; -} - -/***************************************************************************** - * ICorStaticInfo contains EE interface methods which return values that are - * constant from invocation to invocation. Thus they may be embedded in - * persisted information like statically generated code. (This is of course - * assuming that all code versions are identical each time.) - *****************************************************************************/ - -// Return details about EE internal data structures -void MyICJI::getEEInfo(CORINFO_EE_INFO* pEEInfoOut) -{ - jitInstance->mc->cr->AddCall("getEEInfo"); - jitInstance->mc->repGetEEInfo(pEEInfoOut); -} - -void MyICJI::getAsyncInfo(CORINFO_ASYNC_INFO* pAsyncInfo) -{ - jitInstance->mc->cr->AddCall("getAsyncInfo"); - jitInstance->mc->repGetAsyncInfo(pAsyncInfo); -} - -void MyICJI::getWasmWellKnownGlobals(CORINFO_WASM_WELLKNOWN_GLOBALS* pWellKnownGlobalsOut) -{ - jitInstance->mc->cr->AddCall("getWasmWellKnownGlobals"); - jitInstance->mc->repGetWasmWellKnownGlobals(pWellKnownGlobalsOut); -} -CORINFO_METHOD_HANDLE MyICJI::getAwaitReturnCall(CORINFO_METHOD_HANDLE callerHandle, CORINFO_CONTEXT_HANDLE* contextHandle, CORINFO_LOOKUP* instArg) -{ - jitInstance->mc->cr->AddCall("getAwaitReturnCall"); - return jitInstance->mc->repGetAwaitReturnCall(callerHandle, contextHandle, instArg); -} - -CORINFO_METHOD_HANDLE MyICJI::getAwaitAwaiterInContinuationCall( - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_RESOLVED_TOKEN* pResolvedToken, - bool isUnsafe, - CORINFO_CONTEXT_HANDLE* contextHandle, - CORINFO_LOOKUP* instArg) -{ - jitInstance->mc->cr->AddCall("getAwaitAwaiterInContinuationCall"); - return jitInstance->mc->repGetAwaitAwaiterInContinuationCall( - callerHandle, pResolvedToken, isUnsafe, contextHandle, instArg); -} - -/*********************************************************************************/ -// -// Diagnostic methods -// -/*********************************************************************************/ - -// this function is for debugging only. Returns method token. -// Returns mdMethodDefNil for dynamic methods. -mdMethodDef MyICJI::getMethodDefFromMethod(CORINFO_METHOD_HANDLE hMethod) -{ - jitInstance->mc->cr->AddCall("getMethodDefFromMethod"); - mdMethodDef result = jitInstance->mc->repGetMethodDefFromMethod(hMethod); - return result; -} - -size_t MyICJI::printMethodName(CORINFO_METHOD_HANDLE ftn, char* buffer, size_t bufferSize, size_t* pRequiredBufferSize) -{ - jitInstance->mc->cr->AddCall("printMethodName"); - return jitInstance->mc->repPrintMethodName(ftn, buffer, bufferSize, pRequiredBufferSize); -} - -const char* MyICJI::getMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftn, /* IN */ - const char** className, /* OUT */ - const char** namespaceName, /* OUT */ - const char** enclosingClassNames, /* OUT */ - size_t maxEnclosingClassNames - ) -{ - jitInstance->mc->cr->AddCall("getMethodNameFromMetadata"); - return jitInstance->mc->repGetMethodNameFromMetadata(ftn, className, namespaceName, enclosingClassNames, maxEnclosingClassNames); -} - -// this function is for debugging only. It returns a value that -// is will always be the same for a given method. It is used -// to implement the 'jitRange' functionality -unsigned MyICJI::getMethodHash(CORINFO_METHOD_HANDLE ftn /* IN */ - ) -{ - jitInstance->mc->cr->AddCall("getMethodHash"); - return jitInstance->mc->repGetMethodHash(ftn); -} - -bool MyICJI::getSystemVAmd64PassStructInRegisterDescriptor( - /* IN */ CORINFO_CLASS_HANDLE structHnd, - /* OUT */ SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr) -{ - jitInstance->mc->cr->AddCall("getSystemVAmd64PassStructInRegisterDescriptor"); - return jitInstance->mc->repGetSystemVAmd64PassStructInRegisterDescriptor(structHnd, structPassInRegDescPtr); -} - -void MyICJI::getSwiftLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_SWIFT_LOWERING* pLowering) -{ - jitInstance->mc->cr->AddCall("getSwiftLowering"); - jitInstance->mc->repGetSwiftLowering(structHnd, pLowering); -} - -void MyICJI::getFpStructLowering(CORINFO_CLASS_HANDLE structHnd, CORINFO_FPSTRUCT_LOWERING* pLowering) -{ - jitInstance->mc->cr->AddCall("getFpStructLowering"); - jitInstance->mc->repGetFpStructLowering(structHnd, pLowering); -} - -CorInfoWasmType MyICJI::getWasmLowering(CORINFO_CLASS_HANDLE structHnd) -{ - jitInstance->mc->cr->AddCall("getWasmLowering"); - return jitInstance->mc->repGetWasmLowering(structHnd); -} - -// Stuff on ICorDynamicInfo -uint32_t MyICJI::getThreadTLSIndex(void** ppIndirection) -{ - jitInstance->mc->cr->AddCall("getThreadTLSIndex"); - return jitInstance->mc->repGetThreadTLSIndex(ppIndirection); -} - -int32_t* MyICJI::getAddrOfCaptureThreadGlobal(void** ppIndirection) -{ - jitInstance->mc->cr->AddCall("getAddrOfCaptureThreadGlobal"); - return jitInstance->mc->repGetAddrOfCaptureThreadGlobal(ppIndirection); -} - -// return the native entry point to an EE helper (see CorInfoHelpFunc) -void MyICJI::getHelperFtn(CorInfoHelpFunc ftnNum, CORINFO_CONST_LOOKUP *pNativeEntrypoint, CORINFO_METHOD_HANDLE *methodHandle) -{ - jitInstance->mc->cr->AddCall("getHelperFtn"); - jitInstance->mc->repGetHelperFtn(ftnNum, pNativeEntrypoint, methodHandle); -} - -// return a callable address of the function (native code). This function -// may return a different value (depending on whether the method has -// been JITed or not. -void MyICJI::getFunctionEntryPoint(CORINFO_METHOD_HANDLE ftn, /* IN */ - CORINFO_CONST_LOOKUP* pResult, /* OUT */ - CORINFO_ACCESS_FLAGS accessFlags) -{ - jitInstance->mc->cr->AddCall("getFunctionEntryPoint"); - jitInstance->mc->repGetFunctionEntryPoint(ftn, pResult, accessFlags); -} - -// return a directly callable address. This can be used similarly to the -// value returned by getFunctionEntryPoint() except that it is -// guaranteed to be multi callable entrypoint. -void MyICJI::getFunctionFixedEntryPoint( - CORINFO_METHOD_HANDLE ftn, - bool isUnsafeFunctionPointer, - CORINFO_CONST_LOOKUP* pResult) -{ - jitInstance->mc->cr->AddCall("getFunctionFixedEntryPoint"); - jitInstance->mc->repGetFunctionFixedEntryPoint(ftn, isUnsafeFunctionPointer, pResult); -} - -// These entry points must be called if a handle is being embedded in -// the code to be passed to a JIT helper function. (as opposed to just -// being passed back into the ICorInfo interface.) - -CORINFO_MODULE_HANDLE MyICJI::embedModuleHandle(CORINFO_MODULE_HANDLE handle, void** ppIndirection) -{ - jitInstance->mc->cr->AddCall("embedModuleHandle"); - return jitInstance->mc->repEmbedModuleHandle(handle, ppIndirection); -} - -CORINFO_CLASS_HANDLE MyICJI::embedClassHandle(CORINFO_CLASS_HANDLE handle, void** ppIndirection) -{ - jitInstance->mc->cr->AddCall("embedClassHandle"); - return jitInstance->mc->repEmbedClassHandle(handle, ppIndirection); -} - -CORINFO_METHOD_HANDLE MyICJI::embedMethodHandle(CORINFO_METHOD_HANDLE handle, void** ppIndirection) -{ - jitInstance->mc->cr->AddCall("embedMethodHandle"); - return jitInstance->mc->repEmbedMethodHandle(handle, ppIndirection); -} - -CORINFO_FIELD_HANDLE MyICJI::embedFieldHandle(CORINFO_FIELD_HANDLE handle, void** ppIndirection) -{ - jitInstance->mc->cr->AddCall("embedFieldHandle"); - return jitInstance->mc->repEmbedFieldHandle(handle, ppIndirection); -} - -// Given a module scope (module), a method handle (context) and -// a metadata token (metaTOK), fetch the handle -// (type, field or method) associated with the token. -// If this is not possible at compile-time (because the current method's -// code is shared and the token contains generic parameters) -// then indicate how the handle should be looked up at run-time. -// -void MyICJI::embedGenericHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken, - bool fEmbedParent, // TRUE - embeds parent type handle of the field/method handle - CORINFO_METHOD_HANDLE callerHandle, - CORINFO_GENERICHANDLE_RESULT* pResult) -{ - jitInstance->mc->cr->AddCall("embedGenericHandle"); - jitInstance->mc->repEmbedGenericHandle(pResolvedToken, fEmbedParent, callerHandle, pResult); -} - -// Return information used to locate the exact enclosing type of the current method. -// Used only to invoke .cctor method from code shared across generic instantiations -// !needsRuntimeLookup statically known (enclosing type of method itself) -// needsRuntimeLookup: -// CORINFO_LOOKUP_THISOBJ use vtable pointer of 'this' param -// CORINFO_LOOKUP_CLASSPARAM use vtable hidden param -// CORINFO_LOOKUP_METHODPARAM use enclosing type of method-desc hidden param -void MyICJI::getLocationOfThisType(CORINFO_METHOD_HANDLE context, CORINFO_LOOKUP_KIND* pLookupKind) -{ - jitInstance->mc->cr->AddCall("getLocationOfThisType"); - jitInstance->mc->repGetLocationOfThisType(context, pLookupKind); -} - -// return address of fixup area for late-bound PInvoke calls. -void MyICJI::getAddressOfPInvokeTarget(CORINFO_METHOD_HANDLE method, CORINFO_CONST_LOOKUP* pLookup) -{ - jitInstance->mc->cr->AddCall("getAddressOfPInvokeTarget"); - jitInstance->mc->repGetAddressOfPInvokeTarget(method, pLookup); -} - -// Generate a cookie based on the signature to pass to INTOP_CALLI -LPVOID MyICJI::GetCookieForInterpreterCalliSig(CORINFO_SIG_INFO* szMetaSig) -{ - jitInstance->mc->cr->AddCall("GetCookieForInterpreterCalliSig"); - return jitInstance->mc->repGetCookieForInterpreterCalliSig(szMetaSig); -} - -// Gets a handle that is checked to see if the current method is -// included in "JustMyCode" -CORINFO_JUST_MY_CODE_HANDLE MyICJI::getJustMyCodeHandle(CORINFO_METHOD_HANDLE method, - CORINFO_JUST_MY_CODE_HANDLE** ppIndirection) -{ - jitInstance->mc->cr->AddCall("getJustMyCodeHandle"); - return jitInstance->mc->repGetJustMyCodeHandle(method, ppIndirection); -} - -// Gets a method handle that can be used to correlate profiling data. -// This is the IP of a native method, or the address of the descriptor struct -// for IL. Always guaranteed to be unique per process, and not to move. */ -void MyICJI::GetProfilingHandle(bool* pbHookFunction, void** pProfilerHandle, bool* pbIndirectedHandles) -{ - jitInstance->mc->cr->AddCall("GetProfilingHandle"); - jitInstance->mc->repGetProfilingHandle(pbHookFunction, pProfilerHandle, pbIndirectedHandles); -} - -// Returns instructions on how to make the call. See code:CORINFO_CALL_INFO for possible return values. -void MyICJI::getCallInfo( - // Token info - CORINFO_RESOLVED_TOKEN* pResolvedToken, - - // Generics info - CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, - - // Security info - CORINFO_METHOD_HANDLE callerHandle, - - // Jit info - CORINFO_CALLINFO_FLAGS flags, - - // out params - CORINFO_CALL_INFO* pResult) -{ - jitInstance->mc->cr->AddCall("getCallInfo"); - DWORD exceptionCode = 0; - jitInstance->mc->repGetCallInfo(pResolvedToken, pConstrainedResolvedToken, callerHandle, flags, pResult, - &exceptionCode); - if (exceptionCode != 0) - ThrowRecordedException(exceptionCode); -} - -bool MyICJI::getStaticFieldContent(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects) -{ - jitInstance->mc->cr->AddCall("getStaticFieldContent"); - return jitInstance->mc->repGetStaticFieldContent(field, buffer, bufferSize, valueOffset, ignoreMovableObjects); -} - -bool MyICJI::getObjectContent(CORINFO_OBJECT_HANDLE obj, uint8_t* buffer, int bufferSize, int valueOffset) -{ - jitInstance->mc->cr->AddCall("getObjectContent"); - return jitInstance->mc->repGetObjectContent(obj, buffer, bufferSize, valueOffset); -} - -// return the class handle for the current value of a static field -CORINFO_CLASS_HANDLE MyICJI::getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE field, bool* pIsSpeculative) -{ - jitInstance->mc->cr->AddCall("getStaticFieldCurrentClass"); - return jitInstance->mc->repGetStaticFieldCurrentClass(field, pIsSpeculative); -} - -// registers a vararg sig & returns a VM cookie for it (which can contain other stuff) -CORINFO_VARARGS_HANDLE MyICJI::getVarArgsHandle(CORINFO_SIG_INFO* pSig, CORINFO_METHOD_HANDLE methHnd, void** ppIndirection) -{ - jitInstance->mc->cr->AddCall("getVarArgsHandle"); - return jitInstance->mc->repGetVarArgsHandle(pSig, methHnd, ppIndirection); -} - -// Allocate a string literal on the heap and return a handle to it -InfoAccessType MyICJI::constructStringLiteral(CORINFO_MODULE_HANDLE module, mdToken metaTok, void** ppValue) -{ - jitInstance->mc->cr->AddCall("constructStringLiteral"); - return jitInstance->mc->repConstructStringLiteral(module, metaTok, ppValue); -} - -InfoAccessType MyICJI::emptyStringLiteral(void** ppValue) -{ - jitInstance->mc->cr->AddCall("emptyStringLiteral"); - return jitInstance->mc->repEmptyStringLiteral(ppValue); -} - -// (static fields only) given that 'field' refers to thread local store, -// return the ID (TLS index), which is used to find the beginning of the -// TLS data area for the particular DLL 'field' is associated with. -uint32_t MyICJI::getFieldThreadLocalStoreID(CORINFO_FIELD_HANDLE field, void** ppIndirection) -{ - jitInstance->mc->cr->AddCall("getFieldThreadLocalStoreID"); - return jitInstance->mc->repGetFieldThreadLocalStoreID(field, ppIndirection); -} - -CORINFO_METHOD_HANDLE MyICJI::GetDelegateCtor(CORINFO_METHOD_HANDLE methHnd, - CORINFO_CLASS_HANDLE clsHnd, - CORINFO_METHOD_HANDLE targetMethodHnd, - DelegateCtorArgs* pCtorData) -{ - jitInstance->mc->cr->AddCall("GetDelegateCtor"); - return jitInstance->mc->repGetDelegateCtor(methHnd, clsHnd, targetMethodHnd, pCtorData); -} - -void MyICJI::MethodCompileComplete(CORINFO_METHOD_HANDLE methHnd) -{ - jitInstance->mc->cr->AddCall("MethodCompileComplete"); - LogError("Hit unimplemented MethodCompileComplete"); - DebugBreakorAV(118); -} - -bool MyICJI::getTailCallHelpers( - CORINFO_RESOLVED_TOKEN* callToken, - CORINFO_SIG_INFO* sig, - CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, - CORINFO_TAILCALL_HELPERS* pResult) -{ - jitInstance->mc->cr->AddCall("getTailCallHelpers"); - return jitInstance->mc->repGetTailCallHelpers(callToken, sig, flags, pResult); -} - -CORINFO_METHOD_HANDLE MyICJI::getAsyncResumptionStub(void** entryPoint) -{ - jitInstance->mc->cr->AddCall("getAsyncResumptionStub"); - return jitInstance->mc->repGetAsyncResumptionStub(entryPoint); -} - -CORINFO_CLASS_HANDLE MyICJI::getContinuationType(size_t dataSize, bool* objRefs, size_t objRefsSize) -{ - jitInstance->mc->cr->AddCall("getContinuationType"); - CORINFO_CLASS_HANDLE result = jitInstance->mc->repGetContinuationType(dataSize, objRefs, objRefsSize); - return result; -} - -bool MyICJI::convertPInvokeCalliToCall(CORINFO_RESOLVED_TOKEN* pResolvedToken, bool fMustConvert) -{ - jitInstance->mc->cr->AddCall("convertPInvokeCalliToCall"); - return jitInstance->mc->repConvertPInvokeCalliToCall(pResolvedToken, fMustConvert); -} - -bool MyICJI::notifyInstructionSetUsage(CORINFO_InstructionSet instructionSet, bool supported, bool preserveNegativeDependency) -{ - jitInstance->mc->cr->AddCall("notifyInstructionSetUsage"); - return jitInstance->mc->repNotifyInstructionSetUsage(instructionSet, supported, preserveNegativeDependency); -} - -void MyICJI::updateEntryPointForTailCall(CORINFO_CONST_LOOKUP* entryPoint) -{ - jitInstance->mc->cr->AddCall("updateEntryPointForTailCall"); - jitInstance->mc->repUpdateEntryPointForTailCall(entryPoint); -} - -// Stuff directly on ICorJitInfo - -// Returns extended flags for a particular compilation instance. -uint32_t MyICJI::getJitFlags(CORJIT_FLAGS* jitFlags, uint32_t sizeInBytes) -{ - jitInstance->mc->cr->AddCall("getJitFlags"); - return jitInstance->getJitFlags(jitFlags, sizeInBytes); -} - -// Runs the given function with the given parameter under an error trap -// and returns true if the function completes successfully. We fake this -// up a bit for SuperPMI and simply catch all exceptions. -bool MyICJI::runWithErrorTrap(void (*function)(void*), void* param) -{ - return RunWithErrorTrap(function, param); -} - -// Runs the given function with the given parameter under an error trap -// and returns true if the function completes successfully. This catches -// all SPMI exceptions and lets others through. -bool MyICJI::runWithSPMIErrorTrap(void (*function)(void*), void* param) -{ - return RunWithSPMIErrorTrap(function, param); -} - -// Ideally we'd just use the copies of this in standardmacros.h -// however, superpmi is missing various other dependencies as well -static size_t ALIGN_UP_SPMI(size_t val, size_t alignment) -{ - return (val + (alignment - 1)) & ~(alignment - 1); -} - -static void* ALIGN_UP_SPMI(void* val, size_t alignment) -{ - return (void*)ALIGN_UP_SPMI((size_t)val, alignment); -} - -// get a block of memory for the code, readonly data, and read-write data -void MyICJI::allocMem(AllocMemArgs* pArgs) -{ - jitInstance->mc->cr->AddCall("allocMem"); - - uint8_t* hotCodeBlock = nullptr; - size_t hotCodeSize = 0; - uint8_t* coldCodeBlock = nullptr; - size_t coldCodeSize = 0; - uint8_t* roDataBlock = nullptr; - size_t roDataSize = 0; - unsigned roDataAlignment = 0; - - for (unsigned i = 0; i < pArgs->chunksCount; i++) - { - AllocMemChunk& chunk = pArgs->chunks[i]; - if ((chunk.flags & CORJIT_ALLOCMEM_HOT_CODE) != 0) - { - hotCodeSize = chunk.size; - unsigned codeAlignment = std::max((uint32_t)sizeof(void*), chunk.alignment); - size_t hotCodeSizePadded = chunk.size + codeAlignment - 1; - hotCodeBlock = (uint8_t*)jitInstance->mc->cr->allocateMemory(hotCodeSizePadded); - hotCodeBlock = (uint8_t*)ALIGN_UP_SPMI(hotCodeBlock, codeAlignment); - chunk.block = hotCodeBlock; - chunk.blockRW = chunk.block; - } - else if ((pArgs->chunks[i].flags & CORJIT_ALLOCMEM_COLD_CODE) != 0) - { - coldCodeSize = chunk.size; - coldCodeBlock = (uint8_t*)jitInstance->mc->cr->allocateMemory(coldCodeSize); - chunk.block = coldCodeBlock; - chunk.blockRW = chunk.block; - } - else - { - roDataAlignment = std::max(roDataAlignment, chunk.alignment); - roDataSize = ALIGN_UP_SPMI(roDataSize, chunk.alignment); - roDataSize += chunk.size; - } - } - - if (roDataSize > 0) - { - size_t roDataSizePadded = roDataSize + roDataAlignment - 1; - roDataBlock = (uint8_t*)jitInstance->mc->cr->allocateMemory(roDataSizePadded); - roDataBlock = (uint8_t*)ALIGN_UP_SPMI(roDataBlock, roDataAlignment); - size_t offset = 0; - // Zero the block to ensure all the padding we allocated is zeroed for the later comparisons - memset(roDataBlock, 0, roDataSize); - - for (unsigned i = 0; i < pArgs->chunksCount; i++) - { - AllocMemChunk& chunk = pArgs->chunks[i]; - if ((chunk.flags & (CORJIT_ALLOCMEM_HOT_CODE | CORJIT_ALLOCMEM_COLD_CODE)) != 0) - { - continue; - } - - offset = ALIGN_UP_SPMI(offset, chunk.alignment); - chunk.block = (uint8_t*)roDataBlock + offset; - chunk.blockRW = chunk.block; - - offset += chunk.size; - } - } - - jitInstance->mc->cr->recAllocMem((ULONG)hotCodeSize, (ULONG)coldCodeSize, (ULONG)roDataSize, pArgs->xcptnsCount, hotCodeBlock, - coldCodeBlock, roDataBlock); -} - -// Reserve memory for the method/funclet's unwind information. -// Note that this must be called before allocMem. It should be -// called once for the main method, once for every funclet, and -// once for every block of cold code for which allocUnwindInfo -// will be called. -// -// This is necessary because jitted code must allocate all the -// memory needed for the unwindInfo at the allocMem call. -// For prejitted code we split up the unwinding information into -// separate sections .rdata and .pdata. -// -void MyICJI::reserveUnwindInfo(bool isFunclet, /* IN */ - bool isColdCode, /* IN */ - uint32_t unwindSize /* IN */ - ) -{ - jitInstance->mc->cr->AddCall("reserveUnwindInfo"); - jitInstance->mc->cr->recReserveUnwindInfo(isFunclet, isColdCode, unwindSize); -} - -// Allocate and initialize the .rdata and .pdata for this method or -// funclet, and get the block of memory needed for the machine-specific -// unwind information (the info for crawling the stack frame). -// Note that allocMem must be called first. -// -// Parameters: -// -// pHotCode main method code buffer, always filled in -// pColdCode cold code buffer, only filled in if this is cold code, -// null otherwise -// startOffset start of code block, relative to appropriate code buffer -// (e.g. pColdCode if cold, pHotCode if hot). -// endOffset end of code block, relative to appropriate code buffer -// unwindSize size of unwind info pointed to by pUnwindBlock -// pUnwindBlock pointer to unwind info -// funcKind type of funclet (main method code, handler, filter) -// -void MyICJI::allocUnwindInfo(uint8_t* pHotCode, /* IN */ - uint8_t* pColdCode, /* IN */ - uint32_t startOffset, /* IN */ - uint32_t endOffset, /* IN */ - uint32_t unwindSize, /* IN */ - uint8_t* pUnwindBlock, /* IN */ - CorJitFuncKind funcKind /* IN */ - ) -{ - jitInstance->mc->cr->AddCall("allocUnwindInfo"); - jitInstance->mc->cr->recAllocUnwindInfo(pHotCode, pColdCode, startOffset, endOffset, unwindSize, pUnwindBlock, - funcKind); -} - -// Get a block of memory needed for the code manager information, -// (the info for enumerating the GC pointers while crawling the -// stack frame). -// Note that allocMem must be called first -void* MyICJI::allocGCInfo(size_t size /* IN */ - ) -{ - jitInstance->mc->cr->AddCall("allocGCInfo"); - void* temp = jitInstance->mc->cr->allocateMemory(size); - jitInstance->mc->cr->recAllocGCInfo(size, temp); - - return temp; -} - -// Indicate how many exception handler blocks are to be returned. -// This is guaranteed to be called before any 'setEHinfo' call. -// Note that allocMem must be called before this method can be called. -void MyICJI::setEHcount(unsigned cEH /* IN */ - ) -{ - jitInstance->mc->cr->AddCall("setEHcount"); - jitInstance->mc->cr->recSetEHcount(cEH); -} - -// Set the values for one particular exception handler block. -// -// Handler regions should be lexically contiguous. -// This is because FinallyIsUnwinding() uses lexicality to -// determine if a "finally" clause is executing. -void MyICJI::setEHinfo(unsigned EHnumber, /* IN */ - const CORINFO_EH_CLAUSE* clause /* IN */ - ) -{ - jitInstance->mc->cr->AddCall("setEHinfo"); - jitInstance->mc->cr->recSetEHinfo(EHnumber, clause); -} - -// Level 1 -> fatalError, Level 2 -> Error, Level 3 -> Warning -// Level 4 means happens 10 times in a run, level 5 means 100, level 6 means 1000 ... -// returns non-zero if the logging succeeded -bool MyICJI::logMsg(unsigned level, const char* fmt, va_list args) -{ - jitInstance->mc->cr->AddCall("logMsg"); - - // if(level<=2) - // { - // jitInstance->mc->cr->recMessageLog(fmt, args); - // DebugBreakorAV(0x99); - //} - jitInstance->mc->cr->recMessageLog(fmt, args); - return 0; -} - -// do an assert. will return true if the code should retry (DebugBreak) -// returns false, if the assert should be ignored. -int MyICJI::doAssert(const char* szFile, int iLine, const char* szExpr) -{ - jitInstance->mc->cr->AddCall("doAssert"); - char buff[16 * 1024]; - sprintf_s(buff, sizeof(buff), "%s (%d) - %s", szFile, iLine, szExpr); - - LogIssue(ISSUE_ASSERT, "#%d %s", jitInstance->mc->index, buff); - jitInstance->mc->cr->recMessageLog("%s", buff); - - // Under "/boa", ask the user if they want to attach a debugger. If they do, the debugger will be attached, - // then we'll call DebugBreakorAV(), which will issue a __debugbreak() and actually cause - // us to stop in the debugger. - if (BreakOnDebugBreakorAV()) - { - DbgBreakCheck(szFile, iLine, szExpr); - } - - DebugBreakorAV(0x7b); - return 0; -} - -void MyICJI::reportFatalError(CorJitResult result) -{ - jitInstance->mc->cr->AddCall("reportFatalError"); - jitInstance->mc->cr->recReportFatalError(result); -} - -// allocate a basic block profile buffer where execution counts will be stored -// for jitted basic blocks. -HRESULT MyICJI::allocPgoInstrumentationBySchema(CORINFO_METHOD_HANDLE ftnHnd, - PgoInstrumentationSchema* pSchema, - uint32_t countSchemaItems, - uint8_t** pInstrumentationData) -{ - jitInstance->mc->cr->AddCall("allocPgoInstrumentationBySchema"); - return jitInstance->mc->repAllocPgoInstrumentationBySchema(ftnHnd, pSchema, countSchemaItems, pInstrumentationData); -} - -// get profile information to be used for optimizing the current method. The format -// of the buffer is the same as the format the JIT passes to allocMethodBlockCounts. -HRESULT MyICJI::getPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftnHnd, - PgoInstrumentationSchema **pSchema, // pointer to the schema table which describes the instrumentation results (pointer will not remain valid after jit completes) - uint32_t * pCountSchemaItems, // pointer to the count schema items - uint8_t ** pInstrumentationData, // pointer to the actual instrumentation data (pointer will not remain valid after jit completes) - PgoSource* pPgoSource, - bool* pDynamicPgo) - -{ - jitInstance->mc->cr->AddCall("getPgoInstrumentationResults"); - return jitInstance->mc->repGetPgoInstrumentationResults(ftnHnd, pSchema, pCountSchemaItems, pInstrumentationData, pPgoSource, pDynamicPgo); -} - -// Associates a native call site, identified by its offset in the native code stream, with -// the signature information and method handle the JIT used to lay out the call site. If -// the call site has no signature information (e.g. a helper call) or has no method handle -// (e.g. a CALLI P/Invoke), then null should be passed instead. -void MyICJI::recordCallSite(uint32_t instrOffset, /* IN */ - CORINFO_SIG_INFO* callSig, /* IN */ - CORINFO_METHOD_HANDLE methodHandle /* IN */ - ) -{ - jitInstance->mc->cr->AddCall("recordCallSite"); - jitInstance->mc->cr->repRecordCallSite(instrOffset, callSig, methodHandle); -} - -void MyICJI::recordWasmManagedCallSig(CORINFO_SIG_INFO* callSig /* IN */) -{ - jitInstance->mc->cr->AddCall("recordWasmManagedCallSig"); - // No-op for SuperPMI replay. Only meaningful for ReadyToRun Wasm compilation. -} - -// A relocation is recorded if we are pre-jitting. -// A jump thunk may be inserted if we are jitting -void MyICJI::recordRelocation(void* location, /* IN */ - void* locationRW, /* IN */ - void* target, /* IN */ - CorInfoReloc fRelocType, /* IN */ - int32_t addlDelta /* IN */ - ) -{ - jitInstance->mc->cr->AddCall("recordRelocation"); - jitInstance->mc->cr->repRecordRelocation(location, target, fRelocType, addlDelta); -} - -CorInfoReloc MyICJI::getRelocTypeHint(void* target) -{ - jitInstance->mc->cr->AddCall("getRelocTypeHint"); - CorInfoReloc result = jitInstance->mc->repGetRelocTypeHint(target); - return result; -} - -uint32_t MyICJI::getAddressAlignment(void* address) -{ - jitInstance->mc->cr->AddCall("getAddressAlignment"); - uint32_t result = jitInstance->mc->repGetAddressAlignment(address); - return result; -} - -// For what machine does the VM expect the JIT to generate code? The VM -// returns one of the IMAGE_FILE_MACHINE_* values. Note that if the VM -// is cross-compiling (such as the case for crossgen2), it will return a -// different value than if it was compiling for the host architecture. -// -uint32_t MyICJI::getExpectedTargetArchitecture() -{ - jitInstance->mc->cr->AddCall("getExpectedTargetArchitecture"); - DWORD result = jitInstance->mc->repGetExpectedTargetArchitecture(); - return result; -} - -CORINFO_WASM_TYPE_SYMBOL_HANDLE MyICJI::getWasmTypeSymbol(CorInfoWasmType* types, size_t typesSize) -{ - jitInstance->mc->cr->AddCall("getWasmTypeSymbol"); - CORINFO_WASM_TYPE_SYMBOL_HANDLE result = jitInstance->mc->repGetWasmTypeSymbol(types, typesSize); - return result; -} - -CORINFO_METHOD_HANDLE MyICJI::getSpecialCopyHelper(CORINFO_CLASS_HANDLE type) -{ - jitInstance->mc->cr->AddCall("getSpecialCopyHelper"); - CORINFO_METHOD_HANDLE result = jitInstance->mc->repGetSpecialCopyHelper(type); - return result; -} diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.h b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.h deleted file mode 100644 index 98389e42cd7857..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.h +++ /dev/null @@ -1,28 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#ifndef _ICorJitInfo -#define _ICorJitInfo - -#include "runtimedetails.h" -#include "jitinstance.h" - -extern ICorJitInfo* pICJI; - -class MyICJI : public ICorJitInfo -{ - -#include "icorjitinfoimpl.h" - -public: - // Added extras... todo add padding to detect corruption? - JitInstance* jitInstance; - -private: - // Index to start the next search for a reported metric at. See - // MyICJI::reportMetadata. - size_t m_metricSearchStart = 0; -}; - -ICorJitInfo* InitICorJitInfo(JitInstance* jitInstance); -#endif diff --git a/src/coreclr/tools/superpmi/superpmi/jitdebugger.cpp b/src/coreclr/tools/superpmi/superpmi/jitdebugger.cpp deleted file mode 100644 index e2878935ba45dd..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi/jitdebugger.cpp +++ /dev/null @@ -1,441 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//***************************************************************************** -// JitDebugger.cpp -// -// Code to help with invoking the just-in-time debugger -// -//***************************************************************************** - -#include "standardpch.h" -#include "runtimedetails.h" -#include "logging.h" -#include "jitdebugger.h" - -// JIT debugging is broken due to utilcode changes to support LongFile. We need to re-copy -// or adjust the implementation of the below functions so they link properly. -#if 0 -#ifndef TARGET_UNIX // No just-in-time debugger under PAL -#define FEATURE_JIT_DEBUGGING -#endif // !TARGET_UNIX -#endif // 0 - -#ifndef FEATURE_JIT_DEBUGGING - -int DbgBreakCheck(const char* szFile, int iLine, const char* szExpr) -{ - LogError("SuperPMI: Assert Failure (PID %d, Thread %d/%x)\n" - "%s\n" - "\n" - "%s, Line: %d\n", - GetCurrentProcessId(), GetCurrentThreadId(), GetCurrentThreadId(), szExpr, szFile, iLine); - - return 1; -} - -#else // FEATURE_JIT_DEBUGGING - -// Some definitions to make this code look more like the CLR utilcode versions it was stolen from. -#define WszGetModuleFileName GetModuleFileNameW - -#ifndef _WIN64 -//------------------------------------------------------------------------------ -// Returns TRUE if we are running on a 64-bit OS in WoW, FALSE otherwise. -BOOL RunningInWow64() -{ - static int s_Wow64Process; - - if (s_Wow64Process == 0) - { - BOOL fWow64Process = FALSE; - - if (!IsWow64Process(GetCurrentProcess(), &fWow64Process)) - fWow64Process = FALSE; - - s_Wow64Process = fWow64Process ? 1 : -1; - } - - return (s_Wow64Process == 1) ? TRUE : FALSE; -} -#endif - -//------------------------------------------------------------------------------ -// -// GetRegistryLongValue - Reads a configuration LONG value from the registry. -// -// Parameters -// hKeyParent -- Parent key -// szKey -- key to open -// szName -- name of the value -// pValue -- put value here, if found -// fReadNonVirtualizedKey -- whether to read 64-bit hive on WOW64 -// -// Returns -// TRUE -- If the value was found and read -// FALSE -- The value was not found, could not be read, or was not DWORD -// -// Exceptions -// None -//------------------------------------------------------------------------------ -BOOL GetRegistryLongValue(HKEY hKeyParent, LPCWSTR szKey, LPCWSTR szName, long* pValue, BOOL fReadNonVirtualizedKey) -{ - DWORD ret; // Return value from registry operation. - HKEY hkey; // Registry key. - long iValue; // The value to read. - DWORD iType; // Type of value to get. - DWORD iSize; // Size of buffer. - REGSAM samDesired = KEY_READ; // Desired access rights to the key - - if (fReadNonVirtualizedKey) - { - if (RunningInWow64()) - { - samDesired |= KEY_WOW64_64KEY; - } - } - - ret = RegOpenKeyEx(hKeyParent, szKey, 0, samDesired, &hkey); - - // If we opened the key, see if there is a value. - if (ret == ERROR_SUCCESS) - { - iType = REG_DWORD; - iSize = sizeof(long); - ret = RegQueryValueExW(hkey, szName, NULL, &iType, reinterpret_cast(&iValue), &iSize); - - if (ret == ERROR_SUCCESS && iType == REG_DWORD && iSize == sizeof(long)) - { // We successfully read a DWORD value. - *pValue = iValue; - return TRUE; - } - } - - return FALSE; -} // GetRegistryLongValue - -//---------------------------------------------------------------------------- -// -// GetCurrentModuleFileName - Retrieve the current module's filename -// -// Arguments: -// pBuffer - output string buffer -// pcchBuffer - the number of characters of the string buffer -// -// Return Value: -// S_OK on success, else detailed error code. -// -// Note: -// -//---------------------------------------------------------------------------- -HRESULT GetCurrentModuleFileName(_Out_writes_(*pcchBuffer) LPWSTR pBuffer, __inout DWORD* pcchBuffer) -{ - LIMITED_METHOD_CONTRACT; - - if ((pBuffer == NULL) || (pcchBuffer == NULL)) - { - return E_INVALIDARG; - } - - // Get the appname to look up in the exclusion or inclusion list. - WCHAR appPath[MAX_PATH + 2]; - - DWORD ret = WszGetModuleFileName(NULL, appPath, ARRAY_SIZE(appPath)); - - if ((ret == ARRAY_SIZE(appPath)) || (ret == 0)) - { - // The module file name exceeded maxpath, or GetModuleFileName failed. - return E_UNEXPECTED; - } - - // Pick off the part after the path. - WCHAR* appName = (WCHAR*)u16_strrchr(appPath, DIRECTORY_SEPARATOR_CHAR_W); - - // If no backslash, use the whole name; if there is a backslash, skip it. - appName = appName ? appName + 1 : appPath; - - if (*pcchBuffer < u16_strlen(appName)) - { - *pcchBuffer = static_cast(u16_strlen(appName)) + 1; - return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); - } - - wcscpy_s(pBuffer, *pcchBuffer, appName); - return S_OK; -} - -//---------------------------------------------------------------------------- -// -// IsCurrentModuleFileNameInAutoExclusionList - decide if the current module's filename -// is in the AutoExclusionList list -// -// Arguments: -// None -// -// Return Value: -// TRUE or FALSE -// -// Note: -// This function cannot be used in out of process scenarios like DAC because it -// looks at current module's filename. In OOP we want to use target process's -// module's filename. -// -//---------------------------------------------------------------------------- -BOOL IsCurrentModuleFileNameInAutoExclusionList() -{ - HKEY hKeyHolder; - - // Look for "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug\\AutoExclusionList" - DWORD ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, kUnmanagedDebuggerAutoExclusionListKey, 0, KEY_READ, &hKeyHolder); - - if (ret != ERROR_SUCCESS) - { - // there's not even an AutoExclusionList hive - return FALSE; - } - - WCHAR wszAppName[MAX_PATH]; - DWORD cchAppName = ARRAY_SIZE(wszAppName); - - // Get the appname to look up in the exclusion or inclusion list. - if (GetCurrentModuleFileName(wszAppName, &cchAppName) != S_OK) - { - // Assume it is not on the exclusion list if we cannot find the module's filename. - return FALSE; - } - - // Look in AutoExclusionList key for appName get the size of any value stored there. - DWORD value, valueType, valueSize = sizeof(value); - ret = RegQueryValueExW(hKeyHolder, wszAppName, 0, &valueType, reinterpret_cast(&value), &valueSize); - if ((ret == ERROR_SUCCESS) && (valueType == REG_DWORD) && (value == 1)) - { - return TRUE; - } - - return FALSE; -} // IsCurrentModuleFileNameInAutoExclusionList - -//***************************************************************************** -// Retrieve information regarding what registered default debugger -//***************************************************************************** -void GetDebuggerSettingInfo(LPWSTR wszDebuggerString, DWORD cchDebuggerString, BOOL* pfAuto) -{ - HRESULT hr = GetDebuggerSettingInfoWorker(wszDebuggerString, &cchDebuggerString, pfAuto); - - if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) - { - // error! - } -} // GetDebuggerSettingInfo - -//--------------------------------------------------------------------------------------- -// -// GetDebuggerSettingInfoWorker - retrieve information regarding what registered default debugger -// -// Arguments: -// * wszDebuggerString - [out] the string buffer to store the registered debugger launch -// string -// * pcchDebuggerString - [in, out] the size of string buffer in characters -// * pfAuto - [in] the flag to indicate whether the debugger neeeds to be launched -// automatically -// -// Return Value: -// HRESULT indicating success or failure. -// -// Notes: -// * wszDebuggerString can be NULL. When wszDebuggerString is NULL, pcchDebuggerString should -// * point to a DWORD of zero. pcchDebuggerString cannot be NULL, and the DWORD pointed by -// * pcchDebuggerString will store the used or required string buffer size in characters. -HRESULT GetDebuggerSettingInfoWorker(_Out_writes_to_opt_(*pcchDebuggerString, *pcchDebuggerString) - LPWSTR wszDebuggerString, - DWORD* pcchDebuggerString, - BOOL* pfAuto) -{ - if ((pcchDebuggerString == NULL) || ((wszDebuggerString == NULL) && (*pcchDebuggerString != 0))) - { - return E_INVALIDARG; - } - - // Initialize the output values before we start. - if ((wszDebuggerString != NULL) && (*pcchDebuggerString > 0)) - { - *wszDebuggerString = L'\0'; - } - - if (pfAuto != NULL) - { - *pfAuto = FALSE; - } - - HKEY hKey; - - // Look for "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug" - DWORD ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, kUnmanagedDebuggerKey, 0, KEY_READ, &hKey); - - if (ret != ERROR_SUCCESS) - { // Wow, there's not even an AeDebug hive, so no native debugger, no auto. - return S_OK; - } - - // Look in AeDebug key for "Debugger"; get the size of any value stored there. - DWORD valueType, valueSize; - ret = RegQueryValueExW(hKey, kUnmanagedDebuggerValue, 0, &valueType, 0, &valueSize); - - if ((wszDebuggerString == NULL) || (*pcchDebuggerString < valueSize / sizeof(WCHAR))) - { - *pcchDebuggerString = valueSize / sizeof(WCHAR) + 1; - RegCloseKey(hKey); - return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); - } - - *pcchDebuggerString = valueSize / sizeof(WCHAR); - - // The size of an empty string with the null terminator is 2. - BOOL fIsDebuggerStringEmpty = valueSize <= 2 ? TRUE : FALSE; - - if ((ret != ERROR_SUCCESS) || (valueType != REG_SZ) || fIsDebuggerStringEmpty) - { - RegCloseKey(hKey); - return S_OK; - } - - ret = RegQueryValueExW(hKey, kUnmanagedDebuggerValue, NULL, NULL, reinterpret_cast(wszDebuggerString), - &valueSize); - if (ret != ERROR_SUCCESS) - { - *wszDebuggerString = L'\0'; - RegCloseKey(hKey); - return S_OK; - } - - if (pfAuto != NULL) - { - BOOL fAuto = FALSE; - - // Get the appname to look up in DebugApplications key. - WCHAR wzAppName[MAX_PATH]; - DWORD cchAppName = ARRAY_SIZE(wzAppName); - long iValue; - - // Check DebugApplications setting - if ((SUCCEEDED(GetCurrentModuleFileName(wzAppName, &cchAppName))) && - (GetRegistryLongValue(HKEY_LOCAL_MACHINE, kDebugApplicationsPoliciesKey, wzAppName, &iValue, TRUE) || - GetRegistryLongValue(HKEY_LOCAL_MACHINE, kDebugApplicationsKey, wzAppName, &iValue, TRUE) || - GetRegistryLongValue(HKEY_CURRENT_USER, kDebugApplicationsPoliciesKey, wzAppName, &iValue, TRUE) || - GetRegistryLongValue(HKEY_CURRENT_USER, kDebugApplicationsKey, wzAppName, &iValue, TRUE)) && - (iValue == 1)) - { - fAuto = TRUE; - } - else - { - // Look in AeDebug key for "Auto"; get the size of any value stored there. - ret = RegQueryValueExW(hKey, kUnmanagedDebuggerAutoValue, 0, &valueType, 0, &valueSize); - if ((ret == ERROR_SUCCESS) && (valueType == REG_SZ) && (valueSize / sizeof(WCHAR) < MAX_PATH)) - { - WCHAR wzAutoKey[MAX_PATH]; - valueSize = ARRAY_SIZE(wzAutoKey) * sizeof(WCHAR); - RegQueryValueExW(hKey, kUnmanagedDebuggerAutoValue, NULL, NULL, reinterpret_cast(wzAutoKey), - &valueSize); - - // The OS's behavior is to consider Auto to be FALSE unless the first character is set - // to 1. They don't take into consideration the following characters. Also if the value - // isn't present they assume an Auto value of FALSE. - if ((wzAutoKey[0] == L'1') && !IsCurrentModuleFileNameInAutoExclusionList()) - { - fAuto = TRUE; - } - } - } - - *pfAuto = fAuto; - } - - RegCloseKey(hKey); - return S_OK; -} // GetDebuggerSettingInfoWorker - -BOOL LaunchJITDebugger() -{ - BOOL fSuccess = FALSE; - - WCHAR debugger[1000]; - GetDebuggerSettingInfo(debugger, ARRAY_SIZE(debugger), NULL); - - SECURITY_ATTRIBUTES sa; - sa.nLength = sizeof(sa); - sa.lpSecurityDescriptor = NULL; - sa.bInheritHandle = TRUE; - - // We can leave this event as it is since it is inherited by a child process. - // We will block one scheduler, but the process is asking a user if they want to attach debugger. - HANDLE eventHandle = CreateEvent(&sa, TRUE, FALSE, NULL); - if (eventHandle == NULL) - { - return FALSE; - } - - WCHAR cmdLine[1000]; - swprintf_s(cmdLine, debugger, GetCurrentProcessId(), eventHandle); - - STARTUPINFOW StartupInfo; - memset(&StartupInfo, 0, sizeof(StartupInfo)); - StartupInfo.cb = sizeof(StartupInfo); - StartupInfo.lpDesktop = L"Winsta0\\Default"; - - PROCESS_INFORMATION ProcessInformation; - if (CreateProcessW(NULL, cmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &StartupInfo, &ProcessInformation)) - { - WaitForSingleObject(eventHandle, INFINITE); - fSuccess = TRUE; - } - - CloseHandle(eventHandle); - - return fSuccess; -} - -// See if we should invoke the just-in-time debugger on an assert. -int DbgBreakCheck(const char* szFile, int iLine, const char* szExpr) -{ - char dialogText[1000]; - char dialogTitle[1000]; - - sprintf_s(dialogText, sizeof(dialogText), - "%s\n\n%s, Line: %d\n\nAbort - Kill program\nRetry - Debug\nIgnore - Keep running\n", szExpr, szFile, - iLine); - sprintf_s(dialogTitle, sizeof(dialogTitle), "SuperPMI: Assert Failure (PID %d, Thread %d/%x) ", - GetCurrentProcessId(), GetCurrentThreadId(), GetCurrentThreadId()); - - // Tell user there was an error. - int ret = MessageBoxA(NULL, dialogText, dialogTitle, MB_ABORTRETRYIGNORE | MB_ICONEXCLAMATION | MB_TOPMOST); - - switch (ret) - { - case IDABORT: - TerminateProcess(GetCurrentProcess(), 1); - break; - - // Tell caller to break at the correct location. - case IDRETRY: - - if (minipal_is_native_debugger_present()) - { - SetErrorMode(0); - } - else - { - LaunchJITDebugger(); - } - - return 1; - - case IDIGNORE: - // nothing to do - break; - } - - return 0; -} - -#endif // FEATURE_JIT_DEBUGGING diff --git a/src/coreclr/tools/superpmi/superpmi/jitdebugger.h b/src/coreclr/tools/superpmi/superpmi/jitdebugger.h deleted file mode 100644 index a7f1eec42765de..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi/jitdebugger.h +++ /dev/null @@ -1,32 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#ifndef _JitDebugger -#define _JitDebugger - -// -// Functions to support just-in-time debugging. -// - -BOOL GetRegistryLongValue(HKEY hKeyParent, // Parent key. - LPCWSTR szKey, // Key name to look at. - LPCWSTR szName, // Name of value to get. - long* pValue, // Put value here, if found. - BOOL fReadNonVirtualizedKey); // Whether to read 64-bit hive on WOW64 - -HRESULT GetCurrentModuleFileName(_Out_writes_(*pcchBuffer) LPWSTR pBuffer, __inout DWORD* pcchBuffer); - -#ifndef _WIN64 -BOOL RunningInWow64(); -#endif - -BOOL IsCurrentModuleFileNameInAutoExclusionList(); -HRESULT GetDebuggerSettingInfoWorker(_Out_writes_to_opt_(*pcchDebuggerString, *pcchDebuggerString) - LPWSTR wszDebuggerString, - DWORD* pcchDebuggerString, - BOOL* pfAuto); -void GetDebuggerSettingInfo(LPWSTR wszDebuggerString, DWORD cchDebuggerString, BOOL* pfAuto); - -int DbgBreakCheck(const char* szFile, int iLine, const char* szExpr); - -#endif // !_JitDebugger diff --git a/src/coreclr/tools/superpmi/superpmi/jithost.cpp b/src/coreclr/tools/superpmi/superpmi/jithost.cpp deleted file mode 100644 index 5bf155d9d0d1ca..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi/jithost.cpp +++ /dev/null @@ -1,242 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "standardpch.h" -#include "superpmi.h" -#include "jitinstance.h" -#include "icorjitinfo.h" -#include "jithost.h" - -#include - -WCHAR* GetPrefixedEnvironmentVariable(const WCHAR* prefix, size_t prefixLen, const WCHAR* key, JitInstance& jitInstance) -{ - // Prepend prefix to the provided key - size_t keyLen = u16_strlen(key); - size_t keyBufferLen = keyLen + prefixLen + 1; - WCHAR* keyBuffer = - reinterpret_cast(jitInstance.allocateArray(sizeof(WCHAR) * keyBufferLen)); - wcscpy_s(keyBuffer, keyBufferLen, prefix); - wcscpy_s(&keyBuffer[prefixLen], keyLen + 1, key); - - // Look up the environment variable - DWORD valueLen = GetEnvironmentVariableW(keyBuffer, nullptr, 0); - if (valueLen == 0) - { - jitInstance.freeArray(keyBuffer); - return nullptr; - } - - // Note this value must live as long as the jit instance does. - WCHAR* value = reinterpret_cast(jitInstance.allocateLongLivedArray(sizeof(WCHAR) * valueLen)); - DWORD newValueLen = GetEnvironmentVariableW(keyBuffer, value, valueLen); - - jitInstance.freeArray(keyBuffer); - if (valueLen < newValueLen) - { - jitInstance.freeLongLivedArray(value); - return nullptr; - } - - return value; -} - -// Look for 'key' as an environment variable named DOTNET_ and fallback to COMPlus_. -// The returned value is nullptr if it is not found, or a string if found. If not nullptr, -// the returned value must be freed with jitInstance.freeLongLivedArray(value). -char* GetConfigFromEnvironmentVariable(const char* key, JitInstance& jitInstance) -{ - int keyLen = MultiByteToWideChar(CP_UTF8, 0, key, -1, nullptr, 0); - if (keyLen == 0) - { - return nullptr; - } - - WCHAR* keyUtf8 = new WCHAR[keyLen]; - if (MultiByteToWideChar(CP_UTF8, 0, key, -1, keyUtf8, keyLen) == 0) - { - delete[] keyUtf8; - return nullptr; - } - - WCHAR* result = GetPrefixedEnvironmentVariable(DOTNET_PREFIX, LEN_OF_DOTNET_PREFIX, keyUtf8, jitInstance); - if (result == nullptr) - { - result = GetPrefixedEnvironmentVariable(COMPLUS_PREFIX, LEN_OF_COMPLUS_PREFIX, keyUtf8, jitInstance); - } - - delete[] keyUtf8; - - if (result == nullptr) - { - return nullptr; - } - - int resultLen = WideCharToMultiByte(CP_UTF8, 0, result, -1, nullptr, 0, nullptr, nullptr); - if (resultLen == 0) - { - jitInstance.freeLongLivedArray(result); - return nullptr; - } - - char* resultUtf8 = (char*)jitInstance.allocateLongLivedArray((size_t)resultLen); - - if (WideCharToMultiByte(CP_UTF8, 0, result, -1, resultUtf8, resultLen, nullptr, nullptr) == 0) - { - jitInstance.freeLongLivedArray(result); - jitInstance.freeLongLivedArray(resultUtf8); - return nullptr; - } - - jitInstance.freeLongLivedArray(result); - - return resultUtf8; -} - -JitHost::JitHost(JitInstance& jitInstance) : jitInstance(jitInstance) -{ -} - -void* JitHost::allocateMemory(size_t size) -{ - return jitInstance.allocateLongLivedArray(size); -} - -void JitHost::freeMemory(void* block) -{ - jitInstance.freeLongLivedArray((void*)block); -} - -bool JitHost::convertStringValueToInt(const char* key, const char* stringValue, int& result) -{ - if (stringValue == nullptr) - { - return false; - } - - char* endPtr; - errno = 0; - unsigned long longResult = strtoul(stringValue, &endPtr, 16); - bool succeeded = (errno != ERANGE) && (endPtr != stringValue) && (longResult <= UINT_MAX); - if (!succeeded) - { - LogWarning("Can't convert int config value from string, key: %s, string value: %s\n", key, stringValue); - return false; - } - - result = static_cast(longResult); - return true; -} - -int JitHost::getIntConfigValue(const char* key, int defaultValue) -{ - jitInstance.mc->cr->AddCall("getIntConfigValue"); - - // First check the force options, then the mc value. If value is not presented there, probe the JIT options, then - // check - // the special cases and then the environment. - - int result = defaultValue; - - bool valueFound; - - valueFound = convertStringValueToInt(key, jitInstance.getForceOption(key), result); - - if (!valueFound) - { - // Right now we can't distinguish between the default value that was set explicitly and the default value - // from the key that was not set. See comments in CLRConfig::GetConfigValue. - result = jitInstance.mc->repGetIntConfigValue(key, defaultValue); - if (result != defaultValue) - { - valueFound = true; - } - } - - if (!valueFound) - { - // Look for special case keys. - if (strcmp(key, "SuperPMIMethodContextNumber") == 0) - { - result = jitInstance.mc->index; - valueFound = true; - } - else if (strcmp(key, "JitReportMetrics") == 0) - { - result = 1; - valueFound = true; - } - } - - if (!valueFound) - { - valueFound = convertStringValueToInt(key, jitInstance.getOption(key), result); - } - - if (!valueFound) - { - char* envVar = GetConfigFromEnvironmentVariable(key, jitInstance); - valueFound = convertStringValueToInt(key, envVar, result); - if (envVar != nullptr) - { - jitInstance.freeLongLivedArray(envVar); - } - } - - if (valueFound) - { - LogDebug("Environment variable %s=%d", key, result); - } - - return valueFound ? result : defaultValue; -} - -const char* JitHost::getStringConfigValue(const char* key) -{ - jitInstance.mc->cr->AddCall("getStringConfigValue"); - - bool needToDup = true; - const char* result = nullptr; - - // First check the force options, then mc value. If value is not presented there, probe the JIT options and then the - // environment. - - result = jitInstance.getForceOption(key); - - if (result == nullptr) - { - result = jitInstance.mc->repGetStringConfigValue(key); - } - - if (result == nullptr) - { - result = jitInstance.getOption(key); - } - - if (result == nullptr) - { - result = GetConfigFromEnvironmentVariable(key, jitInstance); - needToDup = false; - } - - if (result != nullptr && needToDup) - { - // Now we need to dup it, so you can call freeStringConfigValue() on what we return. - size_t resultLenInChars = strlen(result) + 1; - char* dupResult = (char*)jitInstance.allocateLongLivedArray(sizeof(char) * resultLenInChars); - strcpy_s(dupResult, resultLenInChars, result); - result = dupResult; - } - - if (result != nullptr) - { - LogDebug("Environment variable %s=%s", key, result); - } - return result; -} - -void JitHost::freeStringConfigValue(const char* value) -{ - jitInstance.mc->cr->AddCall("freeStringConfigValue"); - jitInstance.freeLongLivedArray((void*)value); -} diff --git a/src/coreclr/tools/superpmi/superpmi/jithost.h b/src/coreclr/tools/superpmi/superpmi/jithost.h deleted file mode 100644 index 201609da1301d7..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi/jithost.h +++ /dev/null @@ -1,20 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#ifndef _JITHOST -#define _JITHOST - -class JitHost final : public ICorJitHost -{ -public: - JitHost(JitInstance& jitInstance); - -#include "icorjithostimpl.h" - -private: - bool convertStringValueToInt(const char* key, const char* stringValue, int& result); - - JitInstance& jitInstance; -}; - -#endif diff --git a/src/coreclr/tools/superpmi/superpmi/jitinstance.cpp b/src/coreclr/tools/superpmi/superpmi/jitinstance.cpp deleted file mode 100644 index 753452a80a4b2d..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi/jitinstance.cpp +++ /dev/null @@ -1,596 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "standardpch.h" -#include "superpmi.h" -#include "jitinstance.h" -#include "icorjitinfo.h" -#include "jithost.h" -#include "errorhandling.h" -#include "spmiutil.h" - -JitInstance* JitInstance::InitJit(char* nameOfJit, - bool breakOnAssert, - SimpleTimer* st1, - MethodContext* firstContext, - LightWeightMap* forceOptions, - LightWeightMap* options) -{ - JitInstance* jit = new JitInstance(); - if (jit == nullptr) - { - LogError("Failed to allocate a JitInstance"); - return nullptr; - } - - jit->forceOptions = forceOptions; - jit->options = options; - - // The flag to cause the JIT to be invoked as an altjit is stored in the jit flags, not in - // the environment. If the user uses the "-jitoption force" flag to force AltJit off - // or to force it on, then propagate that to the jit flags. - jit->forceClearAltJitFlag = false; - jit->forceSetAltJitFlag = false; - const char* altJitFlag = jit->getForceOption("AltJit"); - if (altJitFlag != nullptr) - { - if (strcmp(altJitFlag, "") == 0) - { - jit->forceClearAltJitFlag = true; - } - else - { - jit->forceSetAltJitFlag = true; - } - } - const char* altJitNgenFlag = jit->getForceOption("AltJitNgen"); - if (altJitNgenFlag != nullptr) - { - if (strcmp(altJitNgenFlag, "") == 0) - { - jit->forceClearAltJitFlag = true; - } - else - { - jit->forceSetAltJitFlag = true; - } - } - - jit->environment.getIntConfigValue = nullptr; - jit->environment.getStringConfigValue = nullptr; - - if (st1 != nullptr) - st1->Start(); - HRESULT hr = jit->StartUp(nameOfJit, breakOnAssert, firstContext); - if (st1 != nullptr) - st1->Stop(); - if (hr != S_OK) - { - LogError("Startup of JIT(%s) failed %d", nameOfJit, hr); - return nullptr; - } - if (st1 != nullptr) - LogVerbose("Jit startup took %fms", st1->GetMilliseconds()); - - return jit; -} - -HRESULT JitInstance::StartUp(char* PathToJit, bool breakOnDebugBreakorAV, MethodContext* firstContext) -{ - // startup jit - DWORD dwRetVal = 0; - UINT uRetVal = 0; - BOOL bRetVal = FALSE; - - SetBreakOnDebugBreakOrAV(breakOnDebugBreakorAV); - - char pFullPathName[MAX_PATH]; - - // find the full jit path - dwRetVal = ::GetFullPathNameA(PathToJit, MAX_PATH, pFullPathName, nullptr); - if (dwRetVal == 0) - { - LogError("GetFullPathName failed (0x%08x)", ::GetLastError()); - return E_FAIL; - } - -#ifndef TARGET_UNIX // No file version APIs in the PAL - // Do a quick version check - DWORD dwHandle = 0; - DWORD fviSize = GetFileVersionInfoSizeA(pFullPathName, &dwHandle); - - if ((fviSize != 0) && (dwHandle == 0)) - { - unsigned char* fviData = new unsigned char[fviSize]; - if (GetFileVersionInfoA(pFullPathName, dwHandle, fviSize, fviData)) - { - UINT size = 0; - VS_FIXEDFILEINFO* verInfo = nullptr; - if (VerQueryValueA(fviData, "\\", (LPVOID*)&verInfo, &size)) - { - if (size) - { - if (verInfo->dwSignature == 0xfeef04bd) - LogDebug("'%s' is version %u.%u.%u.%u", pFullPathName, (verInfo->dwFileVersionMS) >> 16, - (verInfo->dwFileVersionMS) & 0xFFFF, (verInfo->dwFileVersionLS) >> 16, - (verInfo->dwFileVersionLS) & 0xFFFF); - } - } - } - delete[] fviData; - } -#endif // !TARGET_UNIX - - // Load Library - hLib = ::LoadLibraryExA(pFullPathName, NULL, 0); - if (hLib == 0) - { - LogError("LoadLibrary failed (0x%08x)", ::GetLastError()); - return E_FAIL; - } - - // get entry points - pngetJit = (PgetJit)::GetProcAddress(hLib, "getJit"); - if (pngetJit == 0) - { - LogError("GetProcAddress 'getJit' failed (0x%08x)", ::GetLastError()); - return -1; - } - pnjitStartup = (PjitStartup)::GetProcAddress(hLib, "jitStartup"); - - // Setup ICorJitHost and call jitStartup if necessary - if (pnjitStartup != nullptr) - { - mc = firstContext; - jitHost = new JitHost(*this); - if (!callJitStartup(jitHost)) - { - LogError("jitStartup failed"); - return -1; - } - } - - pJitInstance = pngetJit(); - if (pJitInstance == nullptr) - { - LogError("pngetJit gave us null"); - return -1; - } - - // Check the JIT version identifier. - - GUID versionId; - memset(&versionId, 0, sizeof(GUID)); - pJitInstance->getVersionIdentifier(&versionId); - - if (memcmp(&versionId, &JITEEVersionIdentifier, sizeof(GUID)) != 0) - { - // Mismatched version ID. Fail the load. - pJitInstance = NULL; - - GUID expected = JITEEVersionIdentifier; - GUID actual = versionId; - LogError("Jit Compiler has wrong version identifier. Expected: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x. Actual: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x.", - expected.Data1, expected.Data2, expected.Data3, - expected.Data4[0], expected.Data4[1], expected.Data4[2], expected.Data4[3], - expected.Data4[4], expected.Data4[5], expected.Data4[6], expected.Data4[7], - actual.Data1, actual.Data2, actual.Data3, - actual.Data4[0], actual.Data4[1], actual.Data4[2], actual.Data4[3], - actual.Data4[4], actual.Data4[5], actual.Data4[6], actual.Data4[7]); - - return -1; - } - - icji = InitICorJitInfo(this); - - return S_OK; -} - -#undef DLLEXPORT -#ifdef _MSC_VER -#define DLLEXPORT __declspec(dllexport) -#else -#define DLLEXPORT __attribute__((visibility("default"))) -#endif - -DLLEXPORT volatile UINT64 s_globalZero; -// A dynamic instrumentor can rewrite this function to provide precise -// instruction counts that SPMI will report in metrics. We need the volatile -// read here to model to the compiler that something might actually happen in -// this function. -extern "C" DLLEXPORT NOINLINE void Instrumentor_GetInsCount(UINT64* result) -{ - // Instrumentor may have written the value already. - if (*result == 0) - { - *result = s_globalZero; - } -} - -ReplayResults JitInstance::CompileMethod(MethodContext* MethodToCompile, int mcIndex, bool collectThroughput) -{ - struct Param : FilterSuperPMIExceptionsParam_CaptureException - { - JitInstance* pThis; - CORINFO_METHOD_INFO info; - unsigned flags; - int mcIndex; - bool collectThroughput; - bool* isMinOpts; - ReplayResults results; - } param; - param.pThis = this; - param.flags = 0; - param.mcIndex = mcIndex; - param.collectThroughput = collectThroughput; - param.results.Result = ReplayResult::Success; - - // store to instance field our raw values, so we can figure things out a bit later... - mc = MethodToCompile; - - times[0] = 0; - times[1] = 0; - - stj.Start(); - - UINT64 insCountBefore = 0; - Instrumentor_GetInsCount(&insCountBefore); - - PAL_TRY(Param*, pParam, ¶m) - { - uint8_t* NEntryBlock = nullptr; - uint32_t NCodeSizeBlock = 0; - CORINFO_OS os = CORINFO_WINNT; - - pParam->pThis->mc->repCompileMethod(&pParam->info, &pParam->flags, &os); - CORJIT_FLAGS jitFlags; - pParam->pThis->getJitFlags(&jitFlags, sizeof(jitFlags)); - - pParam->results.IsMinOpts = - jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE) || - jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MIN_OPT) || - jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_TIER0); - - if (pParam->collectThroughput) - { - pParam->pThis->lt.Start(); - } - pParam->pThis->pJitInstance->setTargetOS(os); - CorJitResult jitResult = pParam->pThis->pJitInstance->compileMethod(pParam->pThis->icji, &pParam->info, - pParam->flags, &NEntryBlock, &NCodeSizeBlock); - if (pParam->collectThroughput) - { - pParam->pThis->lt.Stop(); - pParam->pThis->times[0] = pParam->pThis->lt.GetCycles(); - } - - CorInfoMethodRuntimeFlags flags = pParam->pThis->mc->cr->repSetMethodAttribs(pParam->info.ftn); - if ((flags & CORINFO_FLG_SWITCHED_TO_MIN_OPT) != 0) - { - pParam->results.IsMinOpts = true; - } - else if ((flags & CORINFO_FLG_SWITCHED_TO_OPTIMIZED) != 0) - { - pParam->results.IsMinOpts = false; - } - - if (jitResult == CORJIT_SKIPPED) - { - SPMI_TARGET_ARCHITECTURE targetArch = GetSpmiTargetArchitecture(); - bool matchesTargetArch = false; - - switch (pParam->pThis->mc->repGetExpectedTargetArchitecture()) - { - case CORINFO_ARCH_X64: - matchesTargetArch = (targetArch == SPMI_TARGET_ARCHITECTURE_AMD64); - break; - - case CORINFO_ARCH_X86: - matchesTargetArch = (targetArch == SPMI_TARGET_ARCHITECTURE_X86); - break; - - case CORINFO_ARCH_ARM: - matchesTargetArch = (targetArch == SPMI_TARGET_ARCHITECTURE_ARM); - break; - - case CORINFO_ARCH_ARM64: - matchesTargetArch = (targetArch == SPMI_TARGET_ARCHITECTURE_ARM64); - break; - - case CORINFO_ARCH_LOONGARCH64: - matchesTargetArch = (targetArch == SPMI_TARGET_ARCHITECTURE_LOONGARCH64); - break; - - case CORINFO_ARCH_RISCV64: - matchesTargetArch = (targetArch == SPMI_TARGET_ARCHITECTURE_RISCV64); - break; - - case CORINFO_ARCH_WASM32: - matchesTargetArch = (targetArch == SPMI_TARGET_ARCHITECTURE_WASM32); - break; - - default: - LogError("Unknown target architecture"); - break; - } - - // If the target architecture doesn't match the expected target architecture - // then we have an altjit, so treat SKIPPED as OK to avoid counting the compilation as failed. - - if (!matchesTargetArch) - { - jitResult = CORJIT_OK; - } - else - { - // If the target matches, but the JIT is an altjit and the user specified RunAltJitCode=0, - // then the JIT will also return CORJIT_SKIPPED, to prevent the generated code from being used. - // However, we don't want to treat that as a replay failure. - if (jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_ALT_JIT) && - (pParam->pThis->jitHost->getIntConfigValue("RunAltJitCode", 1) == 0)) - { - jitResult = CORJIT_OK; - } - } - } - - if ((jitResult == CORJIT_OK) || (jitResult == CORJIT_BADCODE) || (jitResult == CORJIT_R2R_UNSUPPORTED)) - { - // capture the results of compilation - pParam->pThis->mc->cr->recCompileMethod(&NEntryBlock, &NCodeSizeBlock, jitResult); - pParam->pThis->mc->cr->recAllocMemCapture(); - pParam->pThis->mc->cr->recAllocGCInfoCapture(); - - pParam->pThis->mc->cr->recMessageLog(jitResult == CORJIT_OK ? "Successful Compile" : "Successful Compile (BADCODE)"); - } - else - { - LogDebug("compileMethod failed with result %d", jitResult); - pParam->results.Result = ReplayResult::Error; - } - } - PAL_EXCEPT_FILTER(FilterSuperPMIExceptions_CaptureExceptionAndStop) - { - SpmiException e(¶m); - - if (e.GetCode() == EXCEPTIONCODE_MC) - { - char* message = e.GetExceptionMessage(); - LogMissing("Method context %d failed to replay: %s", mcIndex, message); - e.DeleteMessage(); - param.results.Result = ReplayResult::Miss; - } - else if (e.GetCode() == EXCEPTIONCODE_RECORDED_EXCEPTION) - { - // Exception thrown by EE during recording, for example a managed - // MissingFieldException thrown by resolveToken. Several JIT-EE - // APIs can throw exceptions and the recorder expects and rethrows - // their exceptions under this exception code. We do not consider - // these a replay failure. - - // Call these methods to capture that no code/GC info was generated. - mc->cr->recAllocMemCapture(); - mc->cr->recAllocGCInfoCapture(); - - mc->cr->recMessageLog("Successful Compile (EE API exception)"); - } - else - { - e.ShowAndDeleteMessage(); - param.results.Result = ReplayResult::Error; - } - } - PAL_ENDTRY - - stj.Stop(); - if (collectThroughput) - { - // If we get here, we know it compiles - timeResult(param.info, param.flags); - } - - mc->cr->secondsToCompile = stj.GetSeconds(); - param.results.CompileResults = mc->cr; - - UINT64 insCountAfter = 0; - Instrumentor_GetInsCount(&insCountAfter); - - param.results.NumExecutedInstructions = static_cast(insCountAfter - insCountBefore); - return param.results; -} - -void JitInstance::timeResult(CORINFO_METHOD_INFO info, unsigned flags) -{ - uint8_t* NEntryBlock = nullptr; - uint32_t NCodeSizeBlock = 0; - - int sampleSize = 10; - // Save 2 smallest times. To help reduce noise, we will look at the closest pair of these. - uint64_t time; - - for (int i = 0; i < sampleSize; i++) - { - delete mc->cr; - mc->cr = new CompileResult(); - lt.Start(); - pJitInstance->compileMethod(icji, &info, flags, &NEntryBlock, &NCodeSizeBlock); - lt.Stop(); - time = lt.GetCycles(); - if (times[1] == 0) - { - if (time < times[0]) - { - times[1] = times[0]; - times[0] = time; - } - else - times[1] = time; - } - else if (time < times[1]) - { - if (time < times[0]) - { - times[1] = times[0]; - times[0] = time; - } - else - times[1] = time; - } - } -} - -/*-------------------------- Misc ---------------------------------------*/ - -const char* JitInstance::getForceOption(const char* key) -{ - return getOption(key, forceOptions); -} - -const char* JitInstance::getOption(const char* key) -{ - return getOption(key, options); -} - -const char* JitInstance::getOption(const char* key, LightWeightMap* options) -{ - if (options == nullptr) - { - return nullptr; - } - - size_t keyLenInBytes = sizeof(char) * (strlen(key) + 1); - int keyIndex = options->Contains((unsigned char*)key, (unsigned int)keyLenInBytes); - if (keyIndex == -1) - { - return nullptr; - } - - return (const char*)options->GetBuffer(options->Get(keyIndex)); -} - -// Returns extended flags for a particular compilation instance, adjusted for altjit. -// This is a helper call; it does not record the call in the CompileResult. -uint32_t JitInstance::getJitFlags(CORJIT_FLAGS* jitFlags, uint32_t sizeInBytes) -{ - uint32_t ret = mc->repGetJitFlags(jitFlags, sizeInBytes); - if (forceClearAltJitFlag) - { - jitFlags->Clear(CORJIT_FLAGS::CORJIT_FLAG_ALT_JIT); - } - else if (forceSetAltJitFlag) - { - jitFlags->Set(CORJIT_FLAGS::CORJIT_FLAG_ALT_JIT); - } - return ret; -} - -// Used to allocate memory that needs to handed to the EE. -// For eg, use this to allocated memory for reporting debug info, -// which will be handed to the EE by setVars() and setBoundaries() -void* JitInstance::allocateArray(size_t cBytes) -{ - mc->cr->AddCall("allocateArray"); - return mc->cr->allocateMemory(cBytes); -} - -// Used to allocate memory that needs to live as long as the jit -// instance does. -void* JitInstance::allocateLongLivedArray(size_t cBytes) -{ - return new BYTE[cBytes]; -} - -// JitCompiler will free arrays passed by the EE using this -// For eg, The EE returns memory in getVars() and getBoundaries() -// to the JitCompiler, which the JitCompiler should release using -// freeArray() -void JitInstance::freeArray(void* array) -{ - mc->cr->AddCall("freeArray"); - // We don't bother freeing this until the mc->cr itself gets freed. -} - -// Used to free memory allocated by JitInstance::allocateLongLivedArray. -void JitInstance::freeLongLivedArray(void* array) -{ - delete [] (BYTE*)array; -} - -// Helper for calling pnjitStartup. Needed to allow SEH here. -bool JitInstance::callJitStartup(ICorJitHost* jithost) -{ - // Calling into the collection, which could fail, especially - // for altjits. So protect the call. - - struct Param : FilterSuperPMIExceptionsParam_CaptureException - { - JitInstance* pThis; - ICorJitHost* jithost; - bool result; - } param; - param.pThis = this; - param.jithost = jithost; - param.result = false; - - PAL_TRY(Param*, pParam, ¶m) - { - pParam->pThis->pnjitStartup(pParam->jithost); - pParam->result = true; - } - PAL_EXCEPT_FILTER(FilterSuperPMIExceptions_CaptureExceptionAndStop) - { - SpmiException e(¶m); - - LogError("failed to call jitStartup."); - e.ShowAndDeleteMessage(); - } - PAL_ENDTRY - - Assert(environment.getIntConfigValue == nullptr && environment.getStringConfigValue == nullptr); - environment = mc->cloneEnvironment(); - - return param.result; -} - -// Reset JitConfig, that stores Environment variables. -bool JitInstance::resetConfig(MethodContext* firstContext) -{ - if (pnjitStartup == nullptr) - { - return false; - } - - if (environment.getIntConfigValue != nullptr) - { - delete environment.getIntConfigValue; - environment.getIntConfigValue = nullptr; - } - - if (environment.getStringConfigValue != nullptr) - { - delete environment.getStringConfigValue; - environment.getStringConfigValue = nullptr; - } - - mc = firstContext; - ICorJitHost* newHost = new JitHost(*this); - - if (!callJitStartup(newHost)) - { - return false; - } - - delete static_cast(jitHost); - jitHost = newHost; - return true; -} - -const MethodContext::Environment& JitInstance::getEnvironment() -{ - return environment; -} - -void JitInstance::updateForceOptions(LightWeightMap* newForceOptions) -{ - forceOptions = newForceOptions; -} diff --git a/src/coreclr/tools/superpmi/superpmi/jitinstance.h b/src/coreclr/tools/superpmi/superpmi/jitinstance.h deleted file mode 100644 index cbc6e5f5043ad5..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi/jitinstance.h +++ /dev/null @@ -1,91 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#ifndef _JitInstance -#define _JitInstance - -#include "superpmi.h" -#include "simpletimer.h" -#include "methodcontext.h" -#include "cycletimer.h" - -enum class ReplayResult -{ - Success, - Error, - Miss, -}; - -struct ReplayResults -{ - ReplayResult Result = ReplayResult::Success; - bool IsMinOpts = false; - uint64_t NumExecutedInstructions = 0; - CompileResult* CompileResults = nullptr; -}; - -class JitInstance -{ -private: - HMODULE hLib; - PgetJit pngetJit; - PjitStartup pnjitStartup; - ICorJitHost* jitHost; - ICorJitInfo* icji; - SimpleTimer stj; - - LightWeightMap* forceOptions; - LightWeightMap* options; - - MethodContext::Environment environment; - - JitInstance(){}; - void timeResult(CORINFO_METHOD_INFO info, unsigned flags); - -public: - - bool forceClearAltJitFlag; - bool forceSetAltJitFlag; - - CycleTimer lt; - MethodContext* mc; - ULONGLONG times[2]; - ICorJitCompiler* pJitInstance; - - // The loaded JIT module handle. Used to detect when the baseline and diff - // JITs resolve to the same loaded module (which shares global state). - HMODULE getModule() const { return hLib; } - - // Allocate and initialize the jit provided - static JitInstance* InitJit(char* nameOfJit, - bool breakOnAssert, - SimpleTimer* st1, - MethodContext* firstContext, - LightWeightMap* forceOptions, - LightWeightMap* options); - - HRESULT StartUp(char* PathToJit, bool breakOnDebugBreakorAV, MethodContext* firstContext); - - bool callJitStartup(ICorJitHost* newHost); - - bool resetConfig(MethodContext* firstContext); - - ReplayResults CompileMethod(MethodContext* MethodToCompile, int mcIndex, bool collectThroughput); - - const char* getForceOption(const char* key); - const char* getOption(const char* key); - const char* getOption(const char* key, LightWeightMap* options); - - uint32_t getJitFlags(CORJIT_FLAGS* jitFlags, uint32_t sizeInBytes); - - const MethodContext::Environment& getEnvironment(); - - void* allocateArray(size_t size); - void* allocateLongLivedArray(size_t size); - void freeArray(void* array); - void freeLongLivedArray(void* array); - - void updateForceOptions(LightWeightMap* newForceOptions); -}; - -#endif diff --git a/src/coreclr/tools/superpmi/superpmi/methodstatsemitter.cpp b/src/coreclr/tools/superpmi/superpmi/methodstatsemitter.cpp deleted file mode 100644 index 36cee7c6ccdb2d..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi/methodstatsemitter.cpp +++ /dev/null @@ -1,127 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//----------------------------------------------------------------------------- -// MethodStatsEmitter.cpp - Emits useful method stats for compiled methods for analysis -//----------------------------------------------------------------------------- - -#include "standardpch.h" -#include "methodstatsemitter.h" -#include "logging.h" - -MethodStatsEmitter::MethodStatsEmitter(char* nameOfInput) -{ - char filename[MAX_PATH + 1]; - sprintf_s(filename, MAX_PATH + 1, "%s.stats", nameOfInput); - - hStatsFile = - CreateFileA(filename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (hStatsFile == INVALID_HANDLE_VALUE) - { - LogError("Failed to open output file '%s'. GetLastError()=%u", filename, GetLastError()); - } -} - -MethodStatsEmitter::~MethodStatsEmitter() -{ - if (hStatsFile != INVALID_HANDLE_VALUE) - { - if (CloseHandle(hStatsFile) == 0) - { - LogError("CloseHandle failed. GetLastError()=%u", GetLastError()); - } - } -} - -void MethodStatsEmitter::Emit(int methodNumber, MethodContext* mc, ULONGLONG firstTime, ULONGLONG secondTime) -{ - if (hStatsFile != INVALID_HANDLE_VALUE) - { - // Print the CSV header row - char rowData[2048]; - DWORD charCount = 0; - DWORD bytesWritten = 0; - - if (strchr(statsTypes, '*') != NULL || strchr(statsTypes, 'h') != NULL || strchr(statsTypes, 'H') != NULL) - { - // Obtain the method Hash - char md5Hash[MM3_HASH_BUFFER_SIZE]; - if (mc->dumpMethodHashToBuffer(md5Hash, MM3_HASH_BUFFER_SIZE) != MM3_HASH_BUFFER_SIZE) - md5Hash[0] = 0; - - charCount += sprintf_s(rowData + charCount, ARRAY_SIZE(rowData) - charCount, "%s,", md5Hash); - } - if (strchr(statsTypes, '*') != NULL || strchr(statsTypes, 'n') != NULL || strchr(statsTypes, 'N') != NULL) - { - charCount += sprintf_s(rowData + charCount, ARRAY_SIZE(rowData) - charCount, "%d,", methodNumber); - } - if (strchr(statsTypes, '*') != NULL || strchr(statsTypes, 'i') != NULL || strchr(statsTypes, 'I') != NULL) - { - // Obtain the IL code size for this method - CORINFO_METHOD_INFO info; - unsigned flags = 0; - CORINFO_OS os = CORINFO_WINNT; - mc->repCompileMethod(&info, &flags, &os); - - charCount += sprintf_s(rowData + charCount, ARRAY_SIZE(rowData) - charCount, "%d,", info.ILCodeSize); - } - if (strchr(statsTypes, '*') != NULL || strchr(statsTypes, 'a') != NULL || strchr(statsTypes, 'A') != NULL) - { - // Obtain the compiled method ASM size - BYTE* temp; - DWORD codeSize; - CorJitResult result; - if (mc->cr->CompileMethod != nullptr) - mc->cr->repCompileMethod(&temp, &codeSize, &result); - else - codeSize = 0; // this is likely a thin mc - - charCount += sprintf_s(rowData + charCount, ARRAY_SIZE(rowData) - charCount, "%d,", codeSize); - } - if (strchr(statsTypes, '*') != NULL || strchr(statsTypes, 't') != NULL || strchr(statsTypes, 'T') != NULL) - { - charCount += - sprintf_s(rowData + charCount, ARRAY_SIZE(rowData) - charCount, "%llu,%llu,", firstTime, secondTime); - } - - // get rid of the final ',' and replace it with a '\n' - rowData[charCount - 1] = '\n'; - - if (!WriteFile(hStatsFile, rowData, charCount, &bytesWritten, nullptr) || bytesWritten != charCount) - { - LogError("Failed to write row header '%s'. GetLastError()=%u", rowData, GetLastError()); - } - } -} - -void MethodStatsEmitter::SetStatsTypes(char* types) -{ - statsTypes = types; - - if (hStatsFile != INVALID_HANDLE_VALUE) - { - // Print the CSV header row - char rowHeader[1024]; - DWORD charCount = 0; - DWORD bytesWritten = 0; - - if (strchr(statsTypes, '*') != NULL || strchr(statsTypes, 'h') != NULL || strchr(statsTypes, 'H') != NULL) - charCount += sprintf_s(rowHeader + charCount, ARRAY_SIZE(rowHeader) - charCount, "HASH,"); - if (strchr(statsTypes, '*') != NULL || strchr(statsTypes, 'n') != NULL || strchr(statsTypes, 'N') != NULL) - charCount += sprintf_s(rowHeader + charCount, ARRAY_SIZE(rowHeader) - charCount, "METHOD_NUMBER,"); - if (strchr(statsTypes, '*') != NULL || strchr(statsTypes, 'i') != NULL || strchr(statsTypes, 'I') != NULL) - charCount += sprintf_s(rowHeader + charCount, ARRAY_SIZE(rowHeader) - charCount, "IL_CODE_SIZE,"); - if (strchr(statsTypes, '*') != NULL || strchr(statsTypes, 'a') != NULL || strchr(statsTypes, 'A') != NULL) - charCount += sprintf_s(rowHeader + charCount, ARRAY_SIZE(rowHeader) - charCount, "ASM_CODE_SIZE,"); - if (strchr(statsTypes, '*') != NULL || strchr(statsTypes, 't') != NULL || strchr(statsTypes, 'T') != NULL) - charCount += sprintf_s(rowHeader + charCount, ARRAY_SIZE(rowHeader) - charCount, "Time1,Time2,"); - - // get rid of the final ',' and replace it with a '\n' - rowHeader[charCount - 1] = '\n'; - - if (!WriteFile(hStatsFile, rowHeader, charCount, &bytesWritten, nullptr) || bytesWritten != charCount) - { - LogError("Failed to write row header '%s'. GetLastError()=%u", rowHeader, GetLastError()); - } - } -} diff --git a/src/coreclr/tools/superpmi/superpmi/methodstatsemitter.h b/src/coreclr/tools/superpmi/superpmi/methodstatsemitter.h deleted file mode 100644 index 40d38698b3d446..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi/methodstatsemitter.h +++ /dev/null @@ -1,28 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//----------------------------------------------------------------------------- -// MethodStatsEmitter.h - Emits useful method stats for compiled methods for analysis -//----------------------------------------------------------------------------- -#ifndef _MethodStatsEmitter -#define _MethodStatsEmitter - -#include "methodcontext.h" -#include "jitinstance.h" - -class MethodStatsEmitter -{ - -private: - char* statsTypes; - HANDLE hStatsFile; - -public: - MethodStatsEmitter(char* nameOfInput); - ~MethodStatsEmitter(); - - void Emit(int methodNumber, MethodContext* mc, ULONGLONG firstTime, ULONGLONG secondTime); - void SetStatsTypes(char* types); -}; - -#endif diff --git a/src/coreclr/tools/superpmi/superpmi/neardiffer.cpp b/src/coreclr/tools/superpmi/superpmi/neardiffer.cpp deleted file mode 100644 index 9bb7f913393056..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi/neardiffer.cpp +++ /dev/null @@ -1,1508 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// nearDiffer.cpp - differ that handles code that is very similar -//---------------------------------------------------------- - -#include "standardpch.h" - -#ifdef USE_COREDISTOOLS -#include "coredistools.h" -#endif // USE_COREDISTOOLS - -#include "logging.h" -#include "neardiffer.h" -#include "spmiutil.h" - -#ifdef USE_COREDISTOOLS - -// -// Helper functions to print messages from CoreDisTools Library -// The file/linenumber information is from this helper itself, -// since we are only linking with the CoreDisTools library. -// -static void LogFromCoreDisToolsHelper(LogLevel level, const char* msg, va_list argList) -{ - Logger::LogVprintf(__func__, __FILE__, __LINE__, level, argList, msg); -} - -#define LOGGER(L) \ -static void __cdecl CorDisToolsLog##L(const char* msg, ...) \ -{ \ - va_list argList; \ - va_start(argList, msg); \ - LogFromCoreDisToolsHelper(LOGLEVEL_##L, msg, argList); \ - va_end(argList); \ -} - -LOGGER(VERBOSE) -LOGGER(ERROR) -LOGGER(WARNING) - -const PrintControl CorPrinter = {CorDisToolsLogERROR, CorDisToolsLogWARNING, CorDisToolsLogVERBOSE, - CorDisToolsLogVERBOSE}; - -#endif // USE_COREDISTOOLS - -#ifdef USE_COREDISTOOLS -NewDiffer_t* g_PtrNewDiffer = nullptr; // For temporary backwards-compatibility with older coredistools -NewDiffer2_t* g_PtrNewDiffer2 = nullptr; -FinishDiff_t* g_PtrFinishDiff = nullptr; -NearDiffCodeBlocks_t* g_PtrNearDiffCodeBlocks = nullptr; -DumpDiffBlocks_t* g_PtrDumpDiffBlocks = nullptr; -#endif // USE_COREDISTOOLS - -// -// The NearDiff Disassembler initialization. -// -// Returns true on success, false on failure. -// -bool NearDiffer::InitAsmDiff() -{ -#ifdef USE_COREDISTOOLS - - if (UseCoreDisTools) - { - const WCHAR* coreDisToolsLibrary = MAKEDLLNAME_W("coredistools"); -#ifdef TARGET_UNIX - // Unix will require the full path to coredistools. Assume that the - // location is next to the full path to the superpmi.so. - - WCHAR coreCLRLoadedPath[MAX_LONGPATH]; - HMODULE result = 0; - int returnVal = ::GetModuleFileNameW(result, coreCLRLoadedPath, MAX_LONGPATH); - - if (returnVal == 0) - { - LogError("GetModuleFileNameW failed (0x%08x)", ::GetLastError()); - return false; - } - - WCHAR* ptr = (WCHAR*)u16_strrchr(coreCLRLoadedPath, '/'); - - // Move past the / character. - ptr = ptr + 1; - - const WCHAR* coreDisToolsLibraryName = MAKEDLLNAME_W("coredistools"); - ::wcscpy_s(ptr, &coreCLRLoadedPath[MAX_LONGPATH] - ptr, coreDisToolsLibraryName); - coreDisToolsLibrary = coreCLRLoadedPath; -#endif // TARGET_UNIX - - HMODULE hCoreDisToolsLib = ::LoadLibraryExW(coreDisToolsLibrary, NULL, 0); - if (hCoreDisToolsLib == 0) - { - LogError("LoadLibrary(%s) failed (0x%08x)", MAKEDLLNAME_A("coredistools"), ::GetLastError()); - return false; - } - - g_PtrNewDiffer = (NewDiffer_t*)::GetProcAddress(hCoreDisToolsLib, "NewDiffer"); - if (g_PtrNewDiffer == nullptr) - { - LogError("GetProcAddress 'NewDiffer' failed (0x%08x)", ::GetLastError()); - return false; - } - g_PtrNewDiffer2 = (NewDiffer2_t*)::GetProcAddress(hCoreDisToolsLib, "NewDiffer2"); - if (g_PtrNewDiffer2 == nullptr) - { - // Just a warning; fall back to NewDiffer - LogWarning("GetProcAddress 'NewDiffer2' failed (0x%08x)", ::GetLastError()); - } - g_PtrFinishDiff = (FinishDiff_t*)::GetProcAddress(hCoreDisToolsLib, "FinishDiff"); - if (g_PtrFinishDiff == nullptr) - { - LogError("GetProcAddress 'FinishDiff' failed (0x%08x)", ::GetLastError()); - return false; - } - g_PtrNearDiffCodeBlocks = (NearDiffCodeBlocks_t*)::GetProcAddress(hCoreDisToolsLib, "NearDiffCodeBlocks"); - if (g_PtrNearDiffCodeBlocks == nullptr) - { - LogError("GetProcAddress 'NearDiffCodeBlocks' failed (0x%08x)", ::GetLastError()); - return false; - } - g_PtrDumpDiffBlocks = (DumpDiffBlocks_t*)::GetProcAddress(hCoreDisToolsLib, "DumpDiffBlocks"); - if (g_PtrDumpDiffBlocks == nullptr) - { - LogError("GetProcAddress 'DumpDiffBlocks' failed (0x%08x)", ::GetLastError()); - return false; - } - - TargetArch coreDisTargetArchitecture = Target_Host; - OffsetMunger munger = nullptr; // Only arm32 uses this feature currently - - if (TargetArchitecture != nullptr) - { - if ((0 == _stricmp(TargetArchitecture, "x64")) || (0 == _stricmp(TargetArchitecture, "amd64"))) - { - coreDisTargetArchitecture = Target_X64; - } - else if (0 == _stricmp(TargetArchitecture, "x86")) - { - coreDisTargetArchitecture = Target_X86; - } - else if ((0 == _stricmp(TargetArchitecture, "arm")) || (0 == _stricmp(TargetArchitecture, "arm32"))) - { - coreDisTargetArchitecture = Target_Thumb; - munger = NearDiffer::CoreDisMungeOffsetsCallback; - } - else if (0 == _stricmp(TargetArchitecture, "arm64")) - { - coreDisTargetArchitecture = Target_Arm64; - } - else if (0 == _stricmp(TargetArchitecture, "loongarch64")) - { - coreDisTargetArchitecture = Target_LoongArch64; - } - else if (0 == _stricmp(TargetArchitecture, "riscv64")) - { - coreDisTargetArchitecture = Target_RiscV64; - } - else if ((0 == _stricmp(TargetArchitecture, "wasm")) || (0 == _stricmp(TargetArchitecture, "wasm32"))) - { - // Requires coredistools >= 1.7.0 (Target_Wasm32 + framed entry points). - // Existing NearDiffCodeBlocks / DumpCodeBlock / DumpDiffBlocks auto-route - // to the Wasm framing-aware implementations inside coredistools. - coreDisTargetArchitecture = Target_Wasm32; - } - else - { - LogError("Illegal target architecture '%s'", TargetArchitecture); - } - } - - if (g_PtrNewDiffer2 == nullptr) - { - corAsmDiff = (*g_PtrNewDiffer)(coreDisTargetArchitecture, &CorPrinter, - NearDiffer::CoreDisCompareOffsetsCallback); - } - else - { - corAsmDiff = (*g_PtrNewDiffer2)(coreDisTargetArchitecture, &CorPrinter, - NearDiffer::CoreDisCompareOffsetsCallback, munger); - } - } -#endif // USE_COREDISTOOLS - - return true; -} - -#ifdef USE_COREDISTOOLS -// static -bool __cdecl NearDiffer::CoreDisCompareOffsetsCallback( - const void* payload, size_t blockOffset, size_t instrLen, uint64_t offset1, uint64_t offset2) -{ - return compareOffsets(payload, blockOffset, instrLen, offset1, offset2); -} - -// static -bool __cdecl NearDiffer::CoreDisMungeOffsetsCallback( - const void* payload, size_t blockOffset, size_t instrLen, uint64_t* offset1, uint64_t* offset2, uint32_t* skip1, uint32_t* skip2) -{ - return mungeOffsets(payload, blockOffset, instrLen, offset1, offset2, skip1, skip2); -} -#endif // USE_COREDISTOOLS - -// -// The NearDiff destructor -// -NearDiffer::~NearDiffer() -{ -#ifdef USE_COREDISTOOLS - if (corAsmDiff != nullptr) - { - (*g_PtrFinishDiff)(corAsmDiff); - } -#endif // USE_COREDISTOOLS -} - -// At a high level, the near differ takes in a method context and two compile results, performs -// some simple fixups, and then compares the main artifacts of the compile result (i.e. generated -// code, GC info, EH info, debug info, etc.) for equality. In order to be fast, the fixups and -// definitions of "equality" are minimal; for example, the GC info check just does a simple memcmp. -// -// The entrypoint into the near differ is nearDiffer::compare; its doc comments will have more -// details on what it does. That function in turn fans out to various other components. For asm -// diffing, the main function of interest will be nearDiffer::compareCodeSection. -// -// Most of the diffing logic is architecture-independent, with the following exceptions: -// -// - The MSDIS instance must be created with knowledge of the architecture it is working with. -// - The heuristics to compare different literal operand values has some architecture-specific -// assumptions. -// - The code stream is fixed up using relocations recorded during compilation time. The logic -// for applying these should, in theory, be architecture independent, but depending on how -// the runtime implements this from platform to platform, there might be subtle differences here. -// - -#ifdef USE_MSVCDIS - -DIS* NearDiffer::GetMsVcDis() -{ - DIS* disasm; - -#ifdef TARGET_AMD64 - if ((TargetArchitecture != nullptr) && (0 == _stricmp(TargetArchitecture, "arm64"))) - { - disasm = DIS::PdisNew(DIS::distArm64); - } - else - { - disasm = DIS::PdisNew(DIS::distX8664); - } -#elif defined(TARGET_X86) - disasm = DIS::PdisNew(DIS::distX86); -#endif - - return disasm; -} - -#endif // USE_MSVCDIS - -// -// Simple, quick-and-dirty disassembler. If NearDiffer::compareCodeSection finds that two code -// streams differ, it will call this to dump the two differing code blocks to the log. The dump -// is logged under the verbose logging level. -// -// The output format is in MSDIS's disassembly format. -// -// Arguments: -// block - A pointer to the code block to disassemble. -// blocksize - The size of the code block to disassemble. -// originalAddr - The original base address of the code block. -// -void NearDiffer::DumpCodeBlock(unsigned char* block, ULONG blocksize, void* originalAddr) -{ -#ifdef USE_MSVCDIS - DIS* disasm = GetMsVcDis(); - size_t offset = 0; - std::string codeBlock; - - while (offset < blocksize) - { - DIS::INSTRUCTION instr; - DIS::OPERAND ops[3]; - - size_t instrSize = disasm->CbDisassemble((DIS::ADDR)originalAddr + offset, (void*)(block + offset), 15); - if (instrSize == 0) - { - LogWarning("Zero sized instruction"); - break; - } - disasm->FDecode(&instr, ops, 3); - - WCHAR instrMnemonicWide[64]; // I never know how much to allocate... - disasm->CchFormatInstr(instrMnemonicWide, 64); - char instrMnemonic[128]; - size_t count; - wcstombs_s(&count, instrMnemonic, 128, instrMnemonicWide, 64); - - const size_t minInstrBytes = 7; - size_t instrBytes = max(instrSize, minInstrBytes); - size_t buffSize = sizeof("%p %s\n") + 10 + count + 3 * instrBytes + 1; - char* buff = new char[buffSize]; - int written = 0; - written += sprintf_s(buff, buffSize, "%p ", (void*)((size_t)originalAddr + offset)); - for (size_t i = 0; i < instrBytes; i++) - { - if (i < instrSize) - { - written += - sprintf_s(buff + written, buffSize - written, "%02X ", *(const uint8_t*)(block + offset + i)); - } - else - { - written += sprintf_s(buff + written, buffSize - written, " "); - } - } - written += sprintf_s(buff + written, buffSize - written, "%s\n", instrMnemonic); - codeBlock += buff; - delete[] buff; - offset += instrSize; - } - LogVerbose("Code dump:\n%s", codeBlock.c_str()); - delete disasm; -#else // !USE_MSVCDIS - LogVerbose("No disassembler"); -#endif // !USE_MSVCDIS -} - -// -// Struct to capture the information required by offset comparator. -// -struct DiffData -{ - // Common Data - CompileResult* cr1; - CompileResult* cr2; - - // Details of the first block - unsigned char* block1; - size_t blocksize1; - unsigned char* datablock1; - size_t datablockSize1; - size_t originalBlock1; - size_t originalDataBlock1; - size_t otherCodeBlock1; - size_t otherCodeBlockSize1; - - // Details of the second block - unsigned char* block2; - size_t blocksize2; - unsigned char* datablock2; - size_t datablockSize2; - size_t originalBlock2; - size_t originalDataBlock2; - size_t otherCodeBlock2; - size_t otherCodeBlockSize2; -}; - -bool NearDiffer::mungeOffsets( - const void* payload, size_t blockOffset, size_t instrLen, uint64_t* offset1, uint64_t* offset2, uint32_t* skip1, uint32_t* skip2) -{ - const SPMI_TARGET_ARCHITECTURE targetArch = GetSpmiTargetArchitecture(); - const DiffData* data = (const DiffData*)payload; - - // On Thumb-2, we often have movw/movt pairs to generate a 32-bit address. Treat these pairs as - // a single instruction. - // - if (targetArch == SPMI_TARGET_ARCHITECTURE_ARM) - { - bool pair1 = false, pair2 = false; - unsigned reg1_w = 0, reg1_t; - unsigned reg2_w = 0, reg2_t; - unsigned con1_w, con1_t; - unsigned con2_w, con2_t; - - UINT32* iaddr1 = (UINT32*)(data->block1 + blockOffset); - UINT32* iaddr2 = (UINT32*)(data->block2 + blockOffset); - UINT32* iaddr1end = (UINT32*)(data->block1 + data->blocksize1); - UINT32* iaddr2end = (UINT32*)(data->block2 + data->blocksize2); - - uint64_t addr1 = 0; - uint64_t addr2 = 0; - - // Look for a movw/movt address pattern in code stream 1. - - if ((iaddr1 < iaddr1end) && - GetArm32MovwConstant(iaddr1, ®1_w, &con1_w)) - { - if ((iaddr1 + 1 < iaddr1end) && - GetArm32MovtConstant(iaddr1 + 1, ®1_t, &con1_t) && - (reg1_w == reg1_t)) - { - addr1 = con1_w + (con1_t << 16); - pair1 = true; - } - } - - // Look for a movw/movt address pattern in code stream 2. - - if ((iaddr2 < iaddr2end) && - GetArm32MovwConstant(iaddr2, ®2_w, &con2_w)) - { - if ((iaddr2 + 1 < iaddr2end) && - GetArm32MovtConstant(iaddr2 + 1, ®2_t, &con2_t) && - (reg2_w == reg2_t)) - { - addr2 = con2_w + (con2_t << 16); - pair2 = true; - } - } - - if (pair1 && pair2 && (reg1_w == reg2_w)) - { - // Use the constructed constant instead. - *offset1 = addr1; - *offset2 = addr2; - *skip1 = *skip2 = 1; // skip the `movt` instruction - return true; - } - } - -#if 0 - // We might want to do something similar for mov/movk/movk/movk sequences on Arm64. The following code was - // previously used, but currently is not active. - // - // One difference is we might see a different number of movk on arm64 depending on the data. Our "hack" - // of zeroing out the constant so they compare equal doesn't work well. In this case, we really do want - // a callback to the disassembler to skip the instructions. - // - // Another solution is to have the coredistools disassembler have this logic, but that seems like the wrong - // place for that logic, and it's hard to update coredistools. - // - // The instruction sequence is something like this: - // mov x0, #63408 - // movk x0, #23602, lsl #16 - // movk x0, #606, lsl #32 - // - // Since the mov/movk sequence is specific to the replay address constant, we don't assume the baseline - // and diff have the same number of instructions (e.g., it's possible to skip a `movk` if it is zero). - // - if (targetArch == SPMI_TARGET_ARCHITECTURE_ARM64) - { - int numMovk_1 = 0, numMovk_2 = 0; - - unsigned reg1_1 = 0, reg2_1, reg3_1, reg4_1; - unsigned reg1_2 = 0, reg2_2, reg3_2, reg4_2; - unsigned con1_1, con2_1, con3_1, con4_1; - unsigned con1_2, con2_2, con3_2, con4_2; - unsigned shift2_1, shift3_1, shift4_1; - unsigned shift2_2, shift3_2, shift4_2; - - UINT32* iaddr1 = (UINT32*)(data->block1 + blockOffset); - UINT32* iaddr2 = (UINT32*)(data->block2 + blockOffset); - UINT32* iaddr1end = (UINT32*)(data->block1 + data->blocksize1); - UINT32* iaddr2end = (UINT32*)(data->block2 + data->blocksize2); - - uint64_t addr1 = 0; - uint64_t addr2 = 0; - - // Look for a mov/movk address pattern in code stream 1. - - if ((iaddr1 < iaddr1end) && - GetArm64MovConstant(iaddr1, ®1_1, &con1_1)) - { - // We assume the address requires at least 1 'movk' instruction. - if ((iaddr1 + 1 < iaddr1end) && - GetArm64MovkConstant(iaddr1 + 1, ®2_1, &con2_1, &shift2_1) && - (reg1_1 == reg2_1)) - { - ++numMovk_1; - addr1 = (uint64_t)con1_1 + ((uint64_t)con2_1 << shift2_1); - - if ((iaddr1 + 2 < iaddr1end) && - GetArm64MovkConstant(iaddr1 + 2, ®3_1, &con3_1, &shift3_1) && - (reg1_1 == reg3_1)) - { - ++numMovk_1; - addr1 += (uint64_t)con3_1 << shift3_1; - - if ((iaddr1 + 3 < iaddr1end) && - GetArm64MovkConstant(iaddr1 + 3, ®4_1, &con4_1, &shift4_1) && - (reg1_1 == reg4_1)) - { - ++numMovk_1; - addr1 += (uint64_t)con4_1 << shift4_1; - } - } - } - } - - // Look for a mov/movk address pattern in code stream 2. - - if ((iaddr2 < iaddr2end) && - GetArm64MovConstant(iaddr2, ®1_2, &con1_2)) - { - // We assume the address requires at least 1 'movk' instruction. - if ((iaddr2 + 1 < iaddr2end) && - GetArm64MovkConstant(iaddr2 + 1, ®2_2, &con2_2, &shift2_2) && - (reg1_2 == reg2_2)) - { - ++numMovk_2; - addr2 = (uint64_t)con1_2 + ((uint64_t)con2_2 << shift2_2); - - if ((iaddr2 + 2 < iaddr2end) && - GetArm64MovkConstant(iaddr2 + 2, ®3_2, &con3_2, &shift3_2) && - (reg1_2 == reg3_2)) - { - ++numMovk_2; - addr2 += (uint64_t)con3_2 << shift3_2; - - if ((iaddr2 + 3 < iaddr2end) && - GetArm64MovkConstant(iaddr2 + 3, ®4_2, &con4_2, &shift4_2) && - (reg1_2 == reg4_2)) - { - ++numMovk_2; - addr2 += (uint64_t)con4_2 << shift4_2; - } - } - } - } - - // Note: when replaying on a 32-bit platform, we must have - // numMovk_1 == numMovk_2 == 1 - - if ((addr1 != 0) && (addr2 != 0) && (reg1_1 == reg1_2)) - { - offset1 = addr1; - offset2 = addr2; - - *skip1 = numMovk_1; - *skip2 = numMovk_2; - - return true; - } - } -#endif // 0 - - return false; -} - -// -// NearDiff Offset Comparator. -// Determine whether two syntactically different constants are -// semantically equivalent, using certain heuristics. -// -bool NearDiffer::compareOffsets( - const void* payload, size_t blockOffset, size_t instrLen, uint64_t offset1, uint64_t offset2) -{ - // The trivial case - if (offset1 == offset2) - { - return true; - } - - // For wasm32, recorded relocations are the source of truth: handles materialize - // as i32.const immediates with padded ULEB128/SLEB128 placeholders that the JIT - // separately records in a reloc table. Defer the "are these two distinct - // immediates semantically equivalent" decision to a wasm-specific path that - // consults the reloc tables instead of replaying generic IP-relative heuristics. - if (GetSpmiTargetArchitecture() == SPMI_TARGET_ARCHITECTURE_WASM32) - { - return compareOffsetsWasm(payload, blockOffset, instrLen, offset1, offset2); - } - - const DiffData* data = (const DiffData*)payload; - size_t ip1 = data->originalBlock1 + blockOffset; - size_t ip2 = data->originalBlock2 + blockOffset; - size_t ipRelOffset1 = ip1 + instrLen + (size_t)offset1; - size_t ipRelOffset2 = ip2 + instrLen + (size_t)offset2; - - // Case where we have a call into flat address -- the most common case. - size_t gOffset1 = ipRelOffset1; - size_t gOffset2 = ipRelOffset2; - if ((DWORD)gOffset1 == - (DWORD)gOffset2) // make sure the lower 32bits match (best we can do in the current replay form) - return true; - - // Case where we have an offset into the read only section (e.g. loading a float value) - size_t roOffset1a = (size_t)offset1 - data->originalDataBlock1; - size_t roOffset2a = (size_t)offset2 - data->originalDataBlock2; - if ((roOffset1a == roOffset2a) && - (roOffset1a < data->datablockSize1)) // Confirm its an offset that fits inside our RoRegion - return true; - - // Case for IP-relative offset to the RO data-section - size_t roOffset1b = ipRelOffset1 - data->originalDataBlock1; - size_t roOffset2b = ipRelOffset2 - data->originalDataBlock2; - if ((roOffset1b == roOffset2b) && - (roOffset1b < data->datablockSize1)) // Confirm its an offset that fits inside our RoRegion - return true; - - // Case where we have an address to our own code section. - size_t gOffset1a = (size_t)offset1 - data->originalBlock1; - size_t gOffset2a = (size_t)offset2 - data->originalBlock2; - if ((gOffset1a == gOffset2a) && (gOffset1a < data->blocksize1)) // Confirm its in our code region - return true; - - // Case where we have an address in the other codeblock. - size_t gOffset1b = (size_t)offset1 - data->otherCodeBlock1; - size_t gOffset2b = (size_t)offset2 - data->otherCodeBlock2; - if ((gOffset1b == gOffset2b) && (gOffset1b < data->otherCodeBlockSize1)) // Confirm it's in the other code region - return true; - - // Case where we have an offset into the hot codeblock from the cold code block (why?) - size_t ocOffset1 = ipRelOffset1 - data->otherCodeBlock1; - size_t ocOffset2 = ipRelOffset2 - data->otherCodeBlock2; - if (ocOffset1 == ocOffset2) // Would be nice to check to see if it fits in the other code block - return true; - - // In the below, it seems rather odd to pass artifacts from cr1 into queries for cr2. - // - // One would generally expect to ask if cr1->map(artifact1) == cr2->map(artifact2). - // Leaving things this way for now as it seems to work. - - // VSD calling case. - size_t Offset1 = (ipRelOffset1 - 8); - if (data->cr2->CallTargetTypes->GetIndex((DWORDLONG)Offset1) != -1) - { - // This logging is too noisy, so disable it. - // LogVerbose("Found VSD callsite, did softer compare than ideal"); - return true; - } - - // x86 VSD calling cases. - size_t Offset1b = (size_t)offset1 - 4; - size_t Offset2b = (size_t)offset2; - if (data->cr2->CallTargetTypes->GetIndex((DWORDLONG)Offset1b) != -1) - { - // This logging is too noisy, so disable it. - // LogVerbose("Found VSD callsite, did softer compare than ideal"); - return true; - } - if (data->cr2->CallTargetTypes->GetIndex((DWORDLONG)Offset2b) != -1) - { - // This logging is too noisy, so disable it. - // LogVerbose("Found VSD callsite, did softer compare than ideal"); - return true; - } - - return false; -} - -// -// Wasm32-specific offset comparator. -// -// For wasm32, integer immediates that materialize JIT handles (function indices, -// type indices, memory addresses, globals) are emitted as 5-byte ULEB128/SLEB128 -// placeholders (`80 80 80 80 00`) that the JIT separately records in a reloc -// table. For un-prefixed forms like `i32.const`/`call`, the placeholder sits at -// `opcode-byte + 1`. For un-prefixed memory ops (`i32.load`, `i32.store`, ...), -// the layout is ` :u32 :u32`, so the relocatable -// payload sits at `opcode-byte + 2`. Either way, both baseline and diff JITs -// write the same placeholder bytes, so byte-by-byte comparison naturally -// succeeds at reloc sites without any patching. Any immediate mismatch surfaced -// to this comparator therefore falls into one of three cases: -// -// 1. Hard-coded non-reloc literal that genuinely differs across baseline/diff. -// This is a real codegen change; return false. -// -// 2. Reloc sites where both sides recorded a reloc but the immediates somehow -// differ (e.g. a future change patches the placeholder into real bytes). -// Treat as equivalent when both reloc kinds match and the targets are equal -// after addlDelta correction. -// -// 3. A reloc on one side but not the other - genuinely asymmetric codegen. -// Return false. -// -// `blockOffset` is the opcode-byte offset within the framed buffer, per the -// coredistools Wasm32 contract. The recorded reloc location is the payload byte, -// which may be `opcode-byte + 1` (un-prefixed i32.const/call/etc.), -// `opcode-byte + 2` (un-prefixed loads/stores after the align u32), or further -// for prefixed opcodes. We search the entire immediate window -// `[blockOffset+1, blockOffset+instrLen)` to handle all of these uniformly. -// -bool NearDiffer::compareOffsetsWasm( - const void* payload, size_t blockOffset, size_t instrLen, uint64_t offset1, uint64_t offset2) -{ - if (offset1 == offset2) - { - return true; - } - - const DiffData* data = (const DiffData*)payload; - - // The relocated payload byte may live at `opcode-byte + 1` (un-prefixed - // i32.const/call/etc.), `opcode-byte + 2` (un-prefixed memory ops, after - // the align u32), or even deeper for prefixed forms (0xFC/0xFD/0xFE). - // Rather than threading per-opcode payload offsets through coredistools, - // walk the entire immediate window [blockOffset+1, blockOffset+instrLen) - // and accept the first reloc found. Multiple relocs in a single instruction - // are not emitted today. - const size_t windowStart = blockOffset + 1; - const size_t windowSize = (instrLen > 1) ? (instrLen - 1) : 0; - - if (windowSize == 0) - { - // Single-byte opcode (no immediate) -- this comparator should not have - // been called at all. Treat as a real mismatch. - return false; - } - - const Agnostic_RecordRelocation* reloc1 = - data->cr1->findRelocationInRange(data->originalBlock1, windowStart, windowSize); - const Agnostic_RecordRelocation* reloc2 = - data->cr2->findRelocationInRange(data->originalBlock2, windowStart, windowSize); - - if ((reloc1 == nullptr) || (reloc2 == nullptr)) - { - // At most one side has a reloc here. Either a genuine non-reloc immediate - // mismatch (case 1) or an asymmetric reloc (case 3). Real diff. - return false; - } - - if (reloc1->fRelocType != reloc2->fRelocType) - { - // Different reloc kinds at the same site is a real codegen change. - return false; - } - - const uint64_t target1 = (uint64_t)reloc1->target + (int32_t)reloc1->addlDelta; - const uint64_t target2 = (uint64_t)reloc2->target + (int32_t)reloc2->addlDelta; - if (target1 == target2) - { - return true; - } - - // Targets differ. This is the "different handle picked for the same source" - // case. For now, treat as a real mismatch; a future revision can plug in - // handle-equivalence logic mirroring the cr1->cr2 handle remapping used by - // the non-wasm `compareOffsets` heuristics. - return false; -} - -// -// Compares two code sections for syntactic equality. This is the core of the asm diffing logic. -// -// This mostly relies on MSDIS's decoded representation of an instruction to compare for equality. -// That is, using MSDIS's internal IR, this goes through the code stream and compares, instruction -// by instruction, op code and operand values for equality. -// -// Obviously, just blindly comparing operand values will raise a lot of false alarms. In order to -// compensate for phenomena like literal pointer addresses in the code stream changing, this applies -// some heuristics on mismatching operand values to try to normalize them a little bit. Essentially, -// if operand values don't match, they are re-interpreted as various relative deltas from known base -// addresses. For example, a common case is a pointer into the read-only data section. One of the -// heuristics subtracts both operand values from the base address of the read-only data section and -// checks to see if they are the same distance away from their respective read-only base addresses. -// -// Notes: -// - The core syntactic comparison is platform agnostic; we compare op codes and operand values -// using MSDIS's architecture-independent IR (i.e. the data structures defined in msvcdis.h). -// Only the disassembler instance itself is initialized differently based on the target arch- -// itecture. -// - That being said, the heuristics themselves are not guaranteed to be platform agnostic. For -// instance, there is a case that applies only to x86 VSD calls. When porting the near differ -// to new platforms, these special cases should be examined and ported with care. -// -// Arguments: -// mc - The method context of the method to diff. Unused. -// cr1 - The first compile result to compare. Unused. -// cr2 - The second compile result to compare. Unused. -// block1 - A pointer to the first code block to disassemble. -// blocksize1 - The size of the first code block to compare. -// datablock1 - A pointer to the first read-only data block to compare. Unused. -// datablockSize1 - The size of the first read-only data block to compare. -// originalBlock1 - The original base address of the first code block. -// originalDataBlock1 - The original base address of the first read-only data block. -// otherCodeBlock1 - The original base address of the first cold code block. Note that this is -// just an address; we don't need the cold code buffer. -// otherCodeBlockSize1- The size of the first cold code block. -// block2 - A pointer to the second code block to disassemble. -// blocksize2 - The size of the second code block to compare. -// datablock2 - A pointer to the second read-only data block to compare. -// datablockSize2 - The size of the second read-only data block to compare. -// originalBlock2 - The original base address of the second code block. -// originalDataBlock2 - The original base address of the second read-only data block. -// otherCodeBlock2 - The original base address of the second cold code block. Note that this is -// just an address; we don't need the cold code buffer. -// otherCodeBlockSize2- The size of the second cold code block. -// -// Return Value: -// True if the code sections are syntactically identical; false otherwise. -// - -bool NearDiffer::compareCodeSection(MethodContext* mc, - CompileResult* cr1, - CompileResult* cr2, - unsigned char* block1, - ULONG blocksize1, - unsigned char* datablock1, - ULONG datablockSize1, - void* originalBlock1, - void* originalDataBlock1, - void* otherCodeBlock1, - ULONG otherCodeBlockSize1, - unsigned char* block2, - ULONG blocksize2, - unsigned char* datablock2, - ULONG datablockSize2, - void* originalBlock2, - void* originalDataBlock2, - void* otherCodeBlock2, - ULONG otherCodeBlockSize2) -{ - DiffData data = {cr1, - cr2, - - // Details of the first block - block1, (size_t)blocksize1, datablock1, (size_t)datablockSize1, (size_t)originalBlock1, - (size_t)originalDataBlock1, (size_t)otherCodeBlock1, (size_t)otherCodeBlockSize1, - - // Details of the second block - block2, (size_t)blocksize2, datablock2, (size_t)datablockSize2, (size_t)originalBlock2, - (size_t)originalDataBlock2, (size_t)otherCodeBlock2, (size_t)otherCodeBlockSize2}; - -#ifdef USE_COREDISTOOLS - if (UseCoreDisTools) - { - bool areSame = (*g_PtrNearDiffCodeBlocks)(corAsmDiff, &data, (const uint8_t*)originalBlock1, block1, blocksize1, - (const uint8_t*)originalBlock2, block2, blocksize2); - - if (!areSame) - { - (*g_PtrDumpDiffBlocks)(corAsmDiff, (const uint8_t*)originalBlock1, block1, blocksize1, - (const uint8_t*)originalBlock2, block2, blocksize2); - } - - return areSame; - } -#endif // USE_COREDISTOOLS - -#ifdef USE_MSVCDIS - bool haveSeenRet = false; - DIS* disasm_1 = GetMsVcDis(); - DIS* disasm_2 = GetMsVcDis(); - - size_t offset = 0; - - if (blocksize1 != blocksize2) - { - LogVerbose("Code sizes don't match %u != %u", blocksize1, blocksize2); - goto DumpDetails; - } - - while (offset < blocksize1) - { - DIS::INSTRUCTION instr_1; - DIS::INSTRUCTION instr_2; - const int MaxOperandCount = 5; - DIS::OPERAND ops_1[MaxOperandCount]; - DIS::OPERAND ops_2[MaxOperandCount]; - - // Zero out the locals, just in case. - memset(&instr_1, 0, sizeof(instr_1)); - memset(&instr_2, 0, sizeof(instr_2)); - memset(&ops_1, 0, sizeof(ops_1)); - memset(&ops_2, 0, sizeof(ops_2)); - - size_t instrSize_1 = disasm_1->CbDisassemble((DIS::ADDR)originalBlock1 + offset, (void*)(block1 + offset), 15); - size_t instrSize_2 = disasm_2->CbDisassemble((DIS::ADDR)originalBlock2 + offset, (void*)(block2 + offset), 15); - - if (instrSize_1 != instrSize_2) - { - LogVerbose("Different instruction sizes %llu %llu", instrSize_1, instrSize_2); - goto DumpDetails; - } - if (instrSize_1 == 0) - { - if (haveSeenRet) - { - // This logging is pretty noisy, so disable it. - // LogVerbose("instruction size of zero after seeing a ret (soft issue?)."); - break; - } - LogWarning("instruction size of zero."); - goto DumpDetails; - } - - bool FDecodeError = false; - if (!disasm_1->FDecode(&instr_1, ops_1, MaxOperandCount)) - { - LogWarning("FDecode of instr_1 returned false."); - FDecodeError = true; - } - if (!disasm_2->FDecode(&instr_2, ops_2, MaxOperandCount)) - { - LogWarning("FDecode of instr_2 returned false."); - FDecodeError = true; - } - - WCHAR instrMnemonic_1[64]; // I never know how much to allocate... - disasm_1->CchFormatInstr(instrMnemonic_1, 64); - WCHAR instrMnemonic_2[64]; // I never know how much to allocate... - disasm_2->CchFormatInstr(instrMnemonic_2, 64); - if (u16_strcmp(instrMnemonic_1, L"ret") == 0) - haveSeenRet = true; - if (u16_strcmp(instrMnemonic_1, L"rep ret") == 0) - haveSeenRet = true; - - // First, check to see if these instructions are actually identical. - // This is done 1) to avoid the detailed comparison of the fields of instr_1 - // and instr_2 if they are identical, and 2) because in the event that - // there are bugs or unimplemented instructions in FDecode, we don't want - // to count them as diffs if they are bitwise identical. - - if (memcmp((block1 + offset), (block2 + offset), instrSize_1) != 0) - { - if (FDecodeError) - { - LogWarning("FDecode returned false."); - goto DumpDetails; - } - - if (instr_1.opa != instr_2.opa) - { - LogVerbose("different opa %d %d", instr_1.opa, instr_2.opa); - goto DumpDetails; - } - if (instr_1.coperand != instr_2.coperand) - { - LogVerbose("different coperand %u %u", (unsigned int)instr_1.coperand, (unsigned int)instr_2.coperand); - goto DumpDetails; - } - if (instr_1.dwModifiers != instr_2.dwModifiers) - { - LogVerbose("different dwModifiers %u %u", instr_1.dwModifiers, instr_2.dwModifiers); - goto DumpDetails; - } - - for (size_t i = 0; i < instr_1.coperand; i++) - { - if (ops_1[i].cb != ops_2[i].cb) - { - LogVerbose("different cb %llu %llu", ops_1[i].cb, ops_2[i].cb); - goto DumpDetails; - } - if (ops_1[i].imcls != ops_2[i].imcls) - { - LogVerbose("different imcls %d %d", ops_1[i].imcls, ops_2[i].imcls); - goto DumpDetails; - } - if (ops_1[i].opcls != ops_2[i].opcls) - { - LogVerbose("different opcls %d %d", ops_1[i].opcls, ops_2[i].opcls); - goto DumpDetails; - } - if (ops_1[i].rega1 != ops_2[i].rega1) - { - LogVerbose("different rega1 %d %d", ops_1[i].rega1, ops_2[i].rega1); - goto DumpDetails; - } - if (ops_1[i].rega2 != ops_2[i].rega2) - { - LogVerbose("different rega2 %d %d", ops_1[i].rega2, ops_2[i].rega2); - goto DumpDetails; - } - if (ops_1[i].rega3 != ops_2[i].rega3) - { - LogVerbose("different rega3 %d %d", ops_1[i].rega3, ops_2[i].rega3); - goto DumpDetails; - } - if (ops_1[i].wScale != ops_2[i].wScale) - { - LogVerbose("different wScale %u %u", ops_1[i].wScale, ops_2[i].wScale); - goto DumpDetails; - } - - // - // These are special.. we can often reason out exactly why these values - // are different using heuristics. - // - // Why is Instruction size passed as zero? - // Ans: Because the implementation of areOffsetsEquivalent() uses - // the instruction size to compute absolute offsets in the case of - // PC-relative addressing, and MSVCDis already reports the - // absolute offsets! For example: - // 0F 2E 05 67 00 9A FD ucomiss xmm0, dword ptr[FFFFFFFFFD9A006Eh] - // - - if (compareOffsets(&data, offset, 0, ops_1[i].dwl, ops_2[i].dwl)) - { - continue; - } - else - { - size_t gOffset1 = (size_t)originalBlock1 + offset + (size_t)ops_1[i].dwl; - size_t gOffset2 = (size_t)originalBlock2 + offset + (size_t)ops_2[i].dwl; - - LogVerbose("operand %d dwl is different", i); -#ifdef TARGET_AMD64 - LogVerbose("gOffset1 %016llX", gOffset1); - LogVerbose("gOffset2 %016llX", gOffset2); - LogVerbose("gOffset1 - gOffset2 %016llX", gOffset1 - gOffset2); -#elif defined(TARGET_X86) - LogVerbose("gOffset1 %08X", gOffset1); - LogVerbose("gOffset2 %08X", gOffset2); - LogVerbose("gOffset1 - gOffset2 %08X", gOffset1 - gOffset2); -#endif - LogVerbose("dwl1 %016llX", ops_1[i].dwl); - LogVerbose("dwl2 %016llX", ops_2[i].dwl); - goto DumpDetails; - } - } - } - offset += instrSize_1; - } - delete disasm_1; - delete disasm_2; - return true; - -DumpDetails: - LogVerbose("block1 %p", block1); - LogVerbose("block2 %p", block2); - LogVerbose("originalBlock1 [%p,%p)", originalBlock1, (const uint8_t*)originalBlock1 + blocksize1); - LogVerbose("originalBlock2 [%p,%p)", originalBlock2, (const uint8_t*)originalBlock2 + blocksize2); - LogVerbose("blocksize1 %08X", blocksize1); - LogVerbose("blocksize2 %08X", blocksize2); - LogVerbose("dataBlock1 [%p,%p)", originalDataBlock1, (const uint8_t*)originalDataBlock1 + datablockSize1); - LogVerbose("dataBlock2 [%p,%p)", originalDataBlock2, (const uint8_t*)originalDataBlock2 + datablockSize2); - LogVerbose("datablockSize1 %08X", datablockSize1); - LogVerbose("datablockSize2 %08X", datablockSize2); - LogVerbose("otherCodeBlock1 [%p,%p)", otherCodeBlock1, (const uint8_t*)otherCodeBlock1 + otherCodeBlockSize1); - LogVerbose("otherCodeBlock2 [%p,%p)", otherCodeBlock2, (const uint8_t*)otherCodeBlock2 + otherCodeBlockSize2); - LogVerbose("otherCodeBlockSize1 %08X", otherCodeBlockSize1); - LogVerbose("otherCodeBlockSize2 %08X", otherCodeBlockSize2); - -#ifdef TARGET_AMD64 - LogVerbose("offset %016llX", offset); - LogVerbose("addr1 %016llX", (size_t)originalBlock1 + offset); - LogVerbose("addr2 %016llX", (size_t)originalBlock2 + offset); -#elif defined(TARGET_X86) - LogVerbose("offset %08X", offset); - LogVerbose("addr1 %08X", (size_t)originalBlock1 + offset); - LogVerbose("addr2 %08X", (size_t)originalBlock2 + offset); -#endif - - LogVerbose("Block1:"); - DumpCodeBlock(block1, blocksize1, originalBlock1); - LogVerbose("Block2:"); - DumpCodeBlock(block2, blocksize2, originalBlock2); - - if (disasm_1 != nullptr) - delete disasm_1; - if (disasm_2 != nullptr) - delete disasm_2; - return false; -#else // !USE_MSVCDIS - return false; // No disassembler; assume there are differences -#endif // !USE_MSVCDIS -} - -// -// Compares two read-only data sections for equality. -// -// Arguments: -// mc - The method context of the method to diff. -// cr1 - The first compile result to compare. -// cr2 - The second compile result to compare. -// block1 - A pointer to the first code block to disassemble. -// blocksize1 - The size of the first code block to compare. -// originalDataBlock1 - The original base address of the first read-only data block. -// block2 - A pointer to the second code block to disassemble. -// blocksize2 - The size of the second code block to compare. -// originalDataBlock2 - The original base address of the second read-only data block. -// -// Return Value: -// True if the read-only data sections are identical; false otherwise. -// -bool NearDiffer::compareReadOnlyDataBlock(MethodContext* mc, - CompileResult* cr1, - CompileResult* cr2, - unsigned char* block1, - ULONG blocksize1, - void* originalDataBlock1, - unsigned char* block2, - ULONG blocksize2, - void* originalDataBlock2) -{ - // no rodata - if (blocksize1 == 0 && blocksize2 == 0) - return true; - - if (blocksize1 != blocksize2) - { - LogVerbose("compareReadOnlyDataBlock found non-matching sizes %u %u", blocksize1, blocksize2); - return false; - } - - // TODO-Cleanup: The values on the datablock seem to wobble. Need further investigation to evaluate a good near - // comparison for these - return true; -} - -// -// Compares two EH info blocks for equality. -// -// Arguments: -// mc - The method context of the method to diff. -// cr1 - The first compile result to compare. -// cr2 - The second compile result to compare. -// -// Return Value: -// True if the EH info blocks are identical; false otherwise. -// -bool NearDiffer::compareEHInfo(MethodContext* mc, CompileResult* cr1, CompileResult* cr2) -{ - ULONG cEHSize_1; - ULONG ehFlags_1; - ULONG tryOffset_1; - ULONG tryLength_1; - ULONG handlerOffset_1; - ULONG handlerLength_1; - ULONG classToken_1; - - ULONG cEHSize_2; - ULONG ehFlags_2; - ULONG tryOffset_2; - ULONG tryLength_2; - ULONG handlerOffset_2; - ULONG handlerLength_2; - ULONG classToken_2; - - cEHSize_1 = cr1->repSetEHcount(); - cEHSize_2 = cr2->repSetEHcount(); - - // no exception - if (cEHSize_1 == 0 && cEHSize_2 == 0) - return true; - - if (cEHSize_1 != cEHSize_2) - { - LogVerbose("compareEHInfo found non-matching sizes %u %u", cEHSize_1, cEHSize_2); - return false; - } - - for (unsigned int i = 0; i < cEHSize_1; i++) - { - cr1->repSetEHinfo(i, &ehFlags_1, &tryOffset_1, &tryLength_1, &handlerOffset_1, &handlerLength_1, &classToken_1); - cr2->repSetEHinfo(i, &ehFlags_2, &tryOffset_2, &tryLength_2, &handlerOffset_2, &handlerLength_2, &classToken_2); - if (ehFlags_1 != ehFlags_2) - { - LogVerbose("EH flags don't match %u != %u", ehFlags_1, ehFlags_2); - return false; - } - if ((tryOffset_1 != tryOffset_2) || (tryLength_1 != tryLength_2)) - { - LogVerbose("EH try information don't match, offset: %u %u, length: %u %u", tryOffset_1, tryOffset_2, - tryLength_1, tryLength_2); - return false; - } - if ((handlerOffset_1 != handlerOffset_2) || (handlerLength_1 != handlerLength_2)) - { - LogVerbose("EH handler information don't match, offset: %u %u, length: %u %u", handlerOffset_1, - handlerOffset_2, handlerLength_1, handlerLength_2); - return false; - } - if (classToken_1 != classToken_2) - { - LogVerbose("EH class tokens don't match %u!=%u", classToken_1, classToken_2); - return false; - } - } - - return true; -} - -// -// Compares two GC info blocks for equality. -// -// Arguments: -// mc - The method context of the method to diff. -// cr1 - The first compile result to compare. -// cr2 - The second compile result to compare. -// -// Return Value: -// True if the GC info blocks are identical; false otherwise. -// -bool NearDiffer::compareGCInfo(MethodContext* mc, CompileResult* cr1, CompileResult* cr2) -{ - void* gcInfo1; - size_t gcInfo1Size; - void* gcInfo2; - size_t gcInfo2Size; - - cr1->repAllocGCInfo(&gcInfo1Size, &gcInfo1); - cr2->repAllocGCInfo(&gcInfo2Size, &gcInfo2); - - if (gcInfo1Size != gcInfo2Size) - { - LogVerbose("Reported GCInfo sizes don't match: %u != %u", (unsigned int)gcInfo1Size, (unsigned int)gcInfo2Size); - return false; - } - - if (memcmp(gcInfo1, gcInfo2, gcInfo1Size) != 0) - { - LogVerbose("GCInfo doesn't match."); - return false; - } - - return true; -} - -// -// Compares two sets of native var info for equality. -// -// Arguments: -// mc - The method context of the method to diff. -// cr1 - The first compile result to compare. -// cr2 - The second compile result to compare. -// -// Return Value: -// True if the native var info is identical; false otherwise. -// -bool NearDiffer::compareVars(MethodContext* mc, CompileResult* cr1, CompileResult* cr2) -{ - CORINFO_METHOD_HANDLE ftn_1; - ULONG32 cVars_1; - ICorDebugInfo::NativeVarInfo* vars_1; - - CORINFO_METHOD_HANDLE ftn_2; - ULONG32 cVars_2; - ICorDebugInfo::NativeVarInfo* vars_2; - - CORINFO_METHOD_INFO info; - unsigned flags = 0; - CORINFO_OS os = CORINFO_WINNT; - mc->repCompileMethod(&info, &flags, &os); - - bool set1 = cr1->repSetVars(&ftn_1, &cVars_1, &vars_1); - bool set2 = cr2->repSetVars(&ftn_2, &cVars_2, &vars_2); - if ((set1 == false) && (set2 == false)) - return true; // we don't have boundaries for either of these. - if (((set1 == true) && (set2 == false)) || ((set1 == false) && (set2 == true))) - { - LogVerbose("missing matching vars sets"); - return false; - } - - // no vars - if (cVars_1 == 0 && cVars_2 == 0) - { - return true; - } - - if (ftn_1 != ftn_2) - { - // We would like to find out this situation - DEBUG_BREAK; - LogVerbose("compareVars found non-matching CORINFO_METHOD_HANDLE %p %p", ftn_1, ftn_2); - return false; - } - if (ftn_1 != info.ftn) - { - LogVerbose("compareVars found issues with the CORINFO_METHOD_HANDLE %p %p", ftn_1, info.ftn); - return false; - } - - if (cVars_1 != cVars_2) - { - LogVerbose("compareVars found non-matching var count %u %u", cVars_1, cVars_2); - return false; - } - - // TODO-Cleanup: The values on the NativeVarInfo array seem to wobble. Need further investigation to evaluate a good - // near comparison for these for(unsigned int i=0;irepCompileMethod(&info, &flags, &os); - - bool set1 = cr1->repSetBoundaries(&ftn_1, &cMap_1, &map_1); - bool set2 = cr2->repSetBoundaries(&ftn_2, &cMap_2, &map_2); - if ((set1 == false) && (set2 == false)) - return true; // we don't have boundaries for either of these. - if (((set1 == true) && (set2 == false)) || ((set1 == false) && (set2 == true))) - { - LogVerbose("missing matching boundary sets"); - return false; - } - - if (ftn_1 != ftn_2) - { - LogVerbose("compareBoundaries found non-matching CORINFO_METHOD_HANDLE %p %p", ftn_1, ftn_2); - return false; - } - - // no maps - if (cMap_1 == 0 && cMap_2 == 0) - return true; - - if (cMap_1 != cMap_2) - { - LogVerbose("compareBoundaries found non-matching var count %u %u", cMap_1, cMap_2); - return false; - } - - for (unsigned int i = 0; i < cMap_1; i++) - { - if (map_1[i].ilOffset != map_2[i].ilOffset) - { - LogVerbose("compareBoundaries found non-matching ilOffset %u %u for map: %u", map_1[i].ilOffset, - map_2[i].ilOffset, i); - return false; - } - if (map_1[i].nativeOffset != map_2[i].nativeOffset) - { - LogVerbose("compareBoundaries found non-matching nativeOffset %u %u for map: %u", map_1[i].nativeOffset, - map_2[i].nativeOffset, i); - return false; - } - if (map_1[i].source != map_2[i].source) - { - LogVerbose("compareBoundaries found non-matching source %u %u for map: %u", (unsigned int)map_1[i].source, - (unsigned int)map_2[i].source, i); - return false; - } - } - - return true; -} - -// -// Compares two compiled versions of a method for equality. This is the main driver for the various -// components of near diffing. -// -// Before starting the diffing process, this applies some fixups to the code stream based on relocations -// recorded during compilation, using the original base address that was used when compiling the method. -// -// Arguments: -// mc - The method context of the method to diff. -// cr1 - The first compile result to compare. -// cr2 - The second compile result to compare. -// -// Return Value: -// True if the compile results are identical; false otherwise. -// -bool NearDiffer::compare(MethodContext* mc, CompileResult* cr1, CompileResult* cr2) -{ - ULONG hotCodeSize_1; - ULONG coldCodeSize_1; - ULONG roDataSize_1_1; - ULONG roDataSize_1_2 = 0; - ULONG xcptnsCount_1; - unsigned char* hotCodeBlock_1; - unsigned char* coldCodeBlock_1; - unsigned char* roDataBlock_1; - void* orig_hotCodeBlock_1; - void* orig_coldCodeBlock_1; - void* orig_roDataBlock_1_1; - void* orig_roDataBlock_1_2 = nullptr; - - ULONG hotCodeSize_2; - ULONG coldCodeSize_2; - ULONG roDataSize_2_1; - ULONG roDataSize_2_2 = 0; - ULONG xcptnsCount_2; - unsigned char* hotCodeBlock_2; - unsigned char* coldCodeBlock_2; - unsigned char* roDataBlock_2; - void* orig_hotCodeBlock_2; - void* orig_coldCodeBlock_2; - void* orig_roDataBlock_2_1; - void* orig_roDataBlock_2_2 = nullptr; - - cr1->repAllocMem(&hotCodeSize_1, &coldCodeSize_1, &roDataSize_1_1, &xcptnsCount_1, &hotCodeBlock_1, - &coldCodeBlock_1, &roDataBlock_1, &orig_hotCodeBlock_1, &orig_coldCodeBlock_1, - &orig_roDataBlock_1_1); - cr2->repAllocMem(&hotCodeSize_2, &coldCodeSize_2, &roDataSize_2_1, &xcptnsCount_2, &hotCodeBlock_2, - &coldCodeBlock_2, &roDataBlock_2, &orig_hotCodeBlock_2, &orig_coldCodeBlock_2, - &orig_roDataBlock_2_1); - - // On Arm64 the constant pool is appended at the end of the method code section, hence hotCodeSize_{1,2} - // is a sum of their sizes. The following is to adjust their sizes and the roDataBlock_{1,2} pointers. - if (GetSpmiTargetArchitecture() == SPMI_TARGET_ARCHITECTURE_ARM64) - { - if (hotCodeSize_1 > 0) - { - BYTE* nativeEntry_1; - ULONG nativeSizeOfCode_1; - CorJitResult jitResult_1; - cr1->repCompileMethod(&nativeEntry_1, &nativeSizeOfCode_1, &jitResult_1); - roDataSize_1_2 = roDataSize_1_1; - roDataSize_1_1 = hotCodeSize_1 - nativeSizeOfCode_1; - roDataBlock_1 = hotCodeBlock_1 + nativeSizeOfCode_1; - orig_roDataBlock_1_2 = orig_roDataBlock_1_1; - orig_roDataBlock_1_1 = (void*)((size_t)orig_hotCodeBlock_1 + nativeSizeOfCode_1); - hotCodeSize_1 = nativeSizeOfCode_1; - } - - if (hotCodeSize_2 > 0) - { - BYTE* nativeEntry_2; - ULONG nativeSizeOfCode_2; - CorJitResult jitResult_2; - cr2->repCompileMethod(&nativeEntry_2, &nativeSizeOfCode_2, &jitResult_2); - roDataSize_2_2 = roDataSize_2_1; - roDataSize_2_1 = hotCodeSize_2 - nativeSizeOfCode_2; - roDataBlock_2 = hotCodeBlock_2 + nativeSizeOfCode_2; - orig_roDataBlock_2_2 = orig_roDataBlock_2_1; - orig_roDataBlock_2_1 = (void*)((size_t)orig_hotCodeBlock_2 + nativeSizeOfCode_2); - hotCodeSize_2 = nativeSizeOfCode_2; - } - } - - LogDebug("HCS1 %d CCS1 %d RDS1 %d xcpnt1 %d HCB %p CCB %p RDB %p ohcb %p occb %p odb %p", hotCodeSize_1, - coldCodeSize_1, roDataSize_1_1, xcptnsCount_1, hotCodeBlock_1, coldCodeBlock_1, roDataBlock_1, - orig_hotCodeBlock_1, orig_coldCodeBlock_1, orig_roDataBlock_1_1); - LogDebug("HCS2 %d CCS2 %d RDS2 %d xcpnt2 %d HCB %p CCB %p RDB %p ohcb %p occb %p odb %p", hotCodeSize_2, - coldCodeSize_2, roDataSize_2_1, xcptnsCount_2, hotCodeBlock_2, coldCodeBlock_2, roDataBlock_2, - orig_hotCodeBlock_2, orig_coldCodeBlock_2, orig_roDataBlock_2_1); - - RelocContext rc; - rc.mc = mc; - - rc.hotCodeAddress = (size_t)hotCodeBlock_1; - rc.hotCodeSize = hotCodeSize_1; - rc.coldCodeAddress = (size_t)coldCodeBlock_1; - rc.coldCodeSize = coldCodeSize_1; - rc.roDataAddress = (size_t)roDataBlock_1; - rc.roDataSize1 = roDataSize_1_1; - rc.roDataSize2 = roDataSize_1_2; - rc.originalHotCodeAddress = (size_t)orig_hotCodeBlock_1; - rc.originalColdCodeAddress = (size_t)orig_coldCodeBlock_1; - rc.originalRoDataAddress1 = (size_t)orig_roDataBlock_1_1; - rc.originalRoDataAddress2 = (size_t)orig_roDataBlock_1_2; - - cr1->applyRelocs(&rc, hotCodeBlock_1, hotCodeSize_1, orig_hotCodeBlock_1); - cr1->applyRelocs(&rc, coldCodeBlock_1, coldCodeSize_1, orig_coldCodeBlock_1); - cr1->applyRelocs(&rc, roDataBlock_1, roDataSize_1_1, orig_roDataBlock_1_1); - - rc.hotCodeAddress = (size_t)hotCodeBlock_2; - rc.hotCodeSize = hotCodeSize_2; - rc.coldCodeAddress = (size_t)coldCodeBlock_2; - rc.coldCodeSize = coldCodeSize_2; - rc.roDataAddress = (size_t)roDataBlock_2; - rc.roDataSize1 = roDataSize_2_1; - rc.roDataSize2 = roDataSize_2_2; - rc.originalHotCodeAddress = (size_t)orig_hotCodeBlock_2; - rc.originalColdCodeAddress = (size_t)orig_coldCodeBlock_2; - rc.originalRoDataAddress1 = (size_t)orig_roDataBlock_2_1; - rc.originalRoDataAddress2 = (size_t)orig_roDataBlock_2_2; - - cr2->applyRelocs(&rc, hotCodeBlock_2, hotCodeSize_2, orig_hotCodeBlock_2); - cr2->applyRelocs(&rc, coldCodeBlock_2, coldCodeSize_2, orig_coldCodeBlock_2); - cr2->applyRelocs(&rc, roDataBlock_2, roDataSize_2_1, orig_roDataBlock_2_1); - - if (!compareCodeSection(mc, cr1, cr2, hotCodeBlock_1, hotCodeSize_1, roDataBlock_1, roDataSize_1_1, - orig_hotCodeBlock_1, orig_roDataBlock_1_1, orig_coldCodeBlock_1, coldCodeSize_1, - hotCodeBlock_2, hotCodeSize_2, roDataBlock_2, roDataSize_2_1, orig_hotCodeBlock_2, - orig_roDataBlock_2_1, orig_coldCodeBlock_2, coldCodeSize_2)) - return false; - - if (!compareCodeSection(mc, cr1, cr2, coldCodeBlock_1, coldCodeSize_1, roDataBlock_1, roDataSize_1_1, - orig_coldCodeBlock_1, orig_roDataBlock_1_1, orig_hotCodeBlock_1, hotCodeSize_1, - coldCodeBlock_2, coldCodeSize_2, roDataBlock_2, roDataSize_2_1, orig_coldCodeBlock_2, - orig_roDataBlock_2_1, orig_hotCodeBlock_2, hotCodeSize_2)) - return false; - - if (!compareReadOnlyDataBlock(mc, cr1, cr2, roDataBlock_1, roDataSize_1_1, orig_roDataBlock_1_1, roDataBlock_2, - roDataSize_2_1, orig_roDataBlock_2_1)) - return false; - - if (!compareEHInfo(mc, cr1, cr2)) - return false; - - if (!compareGCInfo(mc, cr1, cr2)) - return false; - - if (!compareVars(mc, cr1, cr2)) - return false; - - if (!compareBoundaries(mc, cr1, cr2)) - return false; - - return true; -} diff --git a/src/coreclr/tools/superpmi/superpmi/neardiffer.h b/src/coreclr/tools/superpmi/superpmi/neardiffer.h deleted file mode 100644 index e7957ba755b702..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi/neardiffer.h +++ /dev/null @@ -1,97 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//---------------------------------------------------------- -// nearDiffer.h - differ that handles code that is very similar -//---------------------------------------------------------- -#ifndef _nearDiffer -#define _nearDiffer - -#include "methodcontext.h" -#include "compileresult.h" - -class NearDiffer -{ -public: - NearDiffer(const char* targetArch, bool useCorDisTools) - : TargetArchitecture(targetArch) - , UseCoreDisTools(useCorDisTools) -#ifdef USE_COREDISTOOLS - , corAsmDiff(nullptr) -#endif // USE_COREDISTOOLS - { - } - - ~NearDiffer(); - - bool InitAsmDiff(); - - bool compare(MethodContext* mc, CompileResult* cr1, CompileResult* cr2); - - const char* TargetArchitecture; - const bool UseCoreDisTools; - -private: - void DumpCodeBlock(unsigned char* block, ULONG blocksize, void* originalAddr); - - bool compareCodeSection(MethodContext* mc, - CompileResult* cr1, - CompileResult* cr2, - unsigned char* block1, - ULONG blocksize1, - unsigned char* datablock1, - ULONG datablockSize1, - void* originalBlock1, - void* originalDataBlock1, - void* otherCodeBlock1, - ULONG otherCodeBlockSize1, - unsigned char* block2, - ULONG blocksize2, - unsigned char* datablock2, - ULONG datablockSize2, - void* originalBlock2, - void* originalDataBlock2, - void* otherCodeBlock2, - ULONG otherCodeBlockSize2); - - bool compareReadOnlyDataBlock(MethodContext* mc, - CompileResult* cr1, - CompileResult* cr2, - unsigned char* block1, - ULONG blocksize1, - void* originalDataBlock1, - unsigned char* block2, - ULONG blocksize2, - void* originalDataBlock2); - bool compareEHInfo(MethodContext* mc, CompileResult* cr1, CompileResult* cr2); - bool compareGCInfo(MethodContext* mc, CompileResult* cr1, CompileResult* cr2); - bool compareVars(MethodContext* mc, CompileResult* cr1, CompileResult* cr2); - bool compareBoundaries(MethodContext* mc, CompileResult* cr1, CompileResult* cr2); - - static bool compareOffsets( - const void* payload, size_t blockOffset, size_t instrLen, uint64_t offset1, uint64_t offset2); - - static bool compareOffsetsWasm( - const void* payload, size_t blockOffset, size_t instrLen, uint64_t offset1, uint64_t offset2); - - static bool mungeOffsets( - const void* payload, size_t blockOffset, size_t instrLen, uint64_t* offset1, uint64_t* offset2, uint32_t* skip1, uint32_t* skip2); - -#ifdef USE_COREDISTOOLS - - static bool __cdecl CoreDisCompareOffsetsCallback( - const void* payload, size_t blockOffset, size_t instrLen, uint64_t offset1, uint64_t offset2); - - static bool __cdecl CoreDisMungeOffsetsCallback( - const void* payload, size_t blockOffset, size_t instrLen, uint64_t* offset1, uint64_t* offset2, uint32_t* skip1, uint32_t* skip2); - - CorAsmDiff* corAsmDiff; - -#endif // USE_COREDISTOOLS - -#ifdef USE_MSVCDIS - DIS* GetMsVcDis(); -#endif // USE_MSVCDIS -}; - -#endif // _nearDiffer diff --git a/src/coreclr/tools/superpmi/superpmi/parallelsuperpmi.cpp b/src/coreclr/tools/superpmi/superpmi/parallelsuperpmi.cpp deleted file mode 100644 index 26362868f660f8..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi/parallelsuperpmi.cpp +++ /dev/null @@ -1,1137 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "standardpch.h" -#include "superpmi.h" -#include "simpletimer.h" -#include "mclist.h" -#include "lightweightmap.h" -#include "commandline.h" -#include "errorhandling.h" -#include "fileio.h" -#include - -#include - -#ifdef TARGET_UNIX -#include -#include -#include -#include -#include -#endif // TARGET_UNIX - -// Forward declare the conversion method. Including spmiutil.h pulls in other headers -// that cause build breaks. -std::string ConvertToUtf8(const WCHAR* str); - -// Platform-specific process handle type. -#ifdef TARGET_UNIX -typedef pid_t SpmiProcessHandle; -#else -typedef HANDLE SpmiProcessHandle; -#endif // TARGET_UNIX - -#define MAX_LOG_LINE_SIZE 0x1000 // 4 KB - -volatile sig_atomic_t closeRequested = 0; // global variable to communicate CTRL+C between threads. - -#ifndef TARGET_UNIX - -bool StartProcess(char* commandLine, HANDLE hStdOutput, HANDLE hStdError, HANDLE* hProcess) -{ - LogDebug("StartProcess commandLine=%s", commandLine); - - STARTUPINFO si; - PROCESS_INFORMATION pi; - - ZeroMemory(&si, sizeof(si)); - si.cb = sizeof(si); - si.dwFlags = STARTF_USESTDHANDLES; - si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); - si.hStdOutput = hStdOutput; - si.hStdError = hStdError; - - ZeroMemory(&pi, sizeof(pi)); - - // Start the child process. - if (!CreateProcess(NULL, // No module name (use command line) - commandLine, // Command line - NULL, // Process handle not inheritable - NULL, // Thread handle not inheritable - TRUE, // Set handle inheritance to TRUE (required to use STARTF_USESTDHANDLES) - 0, // No creation flags - NULL, // Use parent's environment block - NULL, // Use parent's starting directory - &si, // Pointer to STARTUPINFO structure - &pi)) // Pointer to PROCESS_INFORMATION structure - { - LogError("CreateProcess failed (%d). CommandLine: %s", GetLastError(), commandLine); - *hProcess = INVALID_HANDLE_VALUE; - return false; - } - - *hProcess = pi.hProcess; - CloseHandle(pi.hThread); - return true; -} - -#else // TARGET_UNIX - -// Parse a command line string into an argv array for execv. Supports single-quote, -// double-quote, and backslash escaping. The returned array and its strings are -// heap-allocated and must be freed by the caller. -static char** ParseCommandLineToArgv(char* commandLine, int* argc) -{ - // First pass: count tokens so we know how big to make argv. - int count = 0; - bool inArg = false; - bool inSingleQuote = false; - bool inDoubleQuote = false; - for (char* p = commandLine; *p != '\0'; ++p) - { - char c = *p; - if (c == '\\' && !inSingleQuote) - { - if (*(p + 1) != '\0') - ++p; // skip escaped character - if (!inArg) { inArg = true; count++; } - } - else if (!inSingleQuote && c == '"') - { - inDoubleQuote = !inDoubleQuote; - if (!inArg) { inArg = true; count++; } - } - else if (!inDoubleQuote && c == '\'') - { - inSingleQuote = !inSingleQuote; - if (!inArg) { inArg = true; count++; } - } - else if (!inSingleQuote && !inDoubleQuote && (c == ' ' || c == '\t')) - { - inArg = false; - } - else - { - if (!inArg) { inArg = true; count++; } - } - } - - *argc = count; - char** argv = new char*[count + 1]; - int idx = 0; - - // Second pass: extract tokens. - inArg = false; - inSingleQuote = false; - inDoubleQuote = false; - // Temporary buffer (upper-bound: length of the entire commandLine). - size_t cmdLen = strlen(commandLine); - char* buf = new char[cmdLen + 1]; - int bufLen = 0; - - for (char* p = commandLine; ; ++p) - { - char c = *p; - - if (c == '\0' || (!inSingleQuote && !inDoubleQuote && (c == ' ' || c == '\t'))) - { - if (inArg) - { - buf[bufLen] = '\0'; - argv[idx] = new char[bufLen + 1]; - memcpy(argv[idx], buf, bufLen + 1); - ++idx; - bufLen = 0; - inArg = false; - } - if (c == '\0') - break; - continue; - } - - inArg = true; - - if (c == '\\' && !inSingleQuote) - { - char next = *(p + 1); - if (next != '\0') - { - buf[bufLen++] = next; - ++p; - } - else - { - buf[bufLen++] = c; - } - } - else if (!inSingleQuote && c == '"') - { - inDoubleQuote = !inDoubleQuote; - } - else if (!inDoubleQuote && c == '\'') - { - inSingleQuote = !inSingleQuote; - } - else - { - buf[bufLen++] = c; - } - } - - delete[] buf; - argv[idx] = nullptr; - return argv; -} - -bool StartProcess(char* commandLine, int hStdOutput, int hStdError, pid_t* pid) -{ - LogDebug("StartProcess commandLine=%s", commandLine); - - int argc; - char** argv = ParseCommandLineToArgv(commandLine, &argc); - if (argc == 0) - { - LogError("StartProcess: empty command line"); - delete[] argv; - return false; - } - - *pid = fork(); - if (*pid == -1) - { - LogError("fork() failed: %s", strerror(errno)); - for (int i = 0; i < argc; i++) - delete[] argv[i]; - delete[] argv; - return false; - } - - if (*pid == 0) - { - // Child process: redirect stdout and stderr then exec. - if (dup2(hStdOutput, STDOUT_FILENO) == -1) - { - fprintf(stderr, "dup2(stdout) failed: %s\n", strerror(errno)); - _exit(1); - } - if (dup2(hStdError, STDERR_FILENO) == -1) - { - fprintf(stderr, "dup2(stderr) failed: %s\n", strerror(errno)); - _exit(1); - } - - // Close the original fds now that they are duplicated to STDOUT/STDERR. - // The O_CLOEXEC on the parent's open() handles the sibling worker fds. - if (hStdOutput != STDOUT_FILENO) - close(hStdOutput); - if (hStdError != STDERR_FILENO) - close(hStdError); - - execv(argv[0], argv); - // If execv returns, it failed. - fprintf(stderr, "execv(%s) failed: %s\n", argv[0], strerror(errno)); - _exit(1); - } - - // Parent process: free argv and return. - for (int i = 0; i < argc; i++) - delete[] argv[i]; - delete[] argv; - return true; -} - -#endif // TARGET_UNIX - -void ReadMCLToArray(char* mclFilename, int** arr, int* count) -{ - *count = 0; - *arr = nullptr; - char* buff = nullptr; - - HANDLE hFile = CreateFileA(mclFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); - - if (hFile == INVALID_HANDLE_VALUE) - { - LogError("Unable to open '%s'. GetLastError()=%u", mclFilename, GetLastError()); - goto Cleanup; - } - - LARGE_INTEGER DataTemp; - if (GetFileSizeEx(hFile, &DataTemp) == 0) - { - LogError("GetFileSizeEx failed. GetLastError()=%u", GetLastError()); - goto Cleanup; - } - - if (DataTemp.QuadPart > MAXMCLFILESIZE) - { - LogError("Size %d exceeds max size of %d", DataTemp.QuadPart, MAXMCLFILESIZE); - goto Cleanup; - } - - int sz; - sz = (int)(DataTemp.QuadPart); - - buff = new char[sz]; - DWORD bytesRead; - if (ReadFile(hFile, buff, sz, &bytesRead, nullptr) == 0) - { - LogError("ReadFile failed. GetLastError()=%u", GetLastError()); - goto Cleanup; - } - - for (int i = 0; i < sz; i++) - { - if (buff[i] == 0x0d) - (*count)++; - } - - if (*count <= 0) - return; - - *arr = new int[*count]; - for (int j = 0, arrIndex = 0; j < sz;) - { - // seek the first number on the line - while (!isdigit((unsigned char)buff[j])) - j++; - // read in the number - (*arr)[arrIndex++] = atoi(&buff[j]); - // seek to the start of next line - while ((j < sz) && (buff[j] != 0x0a)) - j++; - j++; - } - -Cleanup: - if (buff != nullptr) - delete[] buff; - - if (hFile != INVALID_HANDLE_VALUE) - CloseHandle(hFile); -} - -bool WriteArrayToMCL(char* mclFilename, int* arr, int count) -{ - HANDLE hMCLFile = - CreateFileA(mclFilename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - bool result = true; - - if (hMCLFile == INVALID_HANDLE_VALUE) - { - LogError("Failed to open output file '%s'. GetLastError()=%u", mclFilename, GetLastError()); - result = false; - goto Cleanup; - } - - for (int i = 0; i < count; i++) - { - char strMethodIndex[12]; - DWORD charCount = 0; - DWORD bytesWritten = 0; - - charCount = sprintf_s(strMethodIndex, sizeof(strMethodIndex), "%d\r\n", arr[i]); - - if (!WriteFile(hMCLFile, strMethodIndex, charCount, &bytesWritten, nullptr) || (bytesWritten != charCount)) - { - LogError("Failed to write method index '%d'. GetLastError()=%u", strMethodIndex, GetLastError()); - result = false; - goto Cleanup; - } - } - -Cleanup: - if (hMCLFile != INVALID_HANDLE_VALUE) - CloseHandle(hMCLFile); - - return result; -} - -void ProcessChildStdErr(char* stderrFilename) -{ - char buff[MAX_LOG_LINE_SIZE]; - - FILE* fp = fopen(stderrFilename, "r"); - - if (fp == NULL) - { - LogError("Unable to open '%s'.", stderrFilename); - goto Cleanup; - } - - while (fgets(buff, MAX_LOG_LINE_SIZE, fp) != NULL) - { - // get rid of the '\n' at the end of line - size_t buffLen = strlen(buff); - if (buff[buffLen - 1] == '\n') - buff[buffLen - 1] = 0; - - LogPassThroughStderr("%s", buff); - } - -Cleanup: - if (fp != NULL) - fclose(fp); -} - -void ProcessChildStdOut(const CommandLine::Options& o, - char* stdoutFilename, - int* loaded, - int* jitted, - int* failed, - int* excluded, - int* missing, - int* diffs, - bool* usageError) -{ - char buff[MAX_LOG_LINE_SIZE]; - - FILE* fp = fopen(stdoutFilename, "r"); - - if (fp == NULL) - { - LogError("Unable to open '%s'.", stdoutFilename); - goto Cleanup; - } - - while (fgets(buff, MAX_LOG_LINE_SIZE, fp) != NULL) - { - // get rid of the '\n' at the end of line - size_t buffLen = strlen(buff); - if (buff[buffLen - 1] == '\n') - buff[buffLen - 1] = 0; - - if (strncmp(buff, g_SuperPMIUsageFirstLine, strlen(g_SuperPMIUsageFirstLine)) == 0) - { - *usageError = true; // Signals that we had a SuperPMI command line usage error - LogPassThroughStdout("%s", buff); - } - else if (strncmp(buff, g_AllFormatStringFixedPrefix, strlen(g_AllFormatStringFixedPrefix)) == 0) - { - int childLoaded = 0, childJitted = 0, childFailed = 0, childExcluded = 0, childMissing = 0; - if (o.applyDiff) - { - int childDiffs = 0; - int converted = sscanf_s(buff, g_AsmDiffsSummaryFormatString, &childLoaded, &childJitted, &childFailed, - &childExcluded, &childMissing, &childDiffs); - if (converted != 6) - { - LogError("Couldn't parse status message: \"%s\"", buff); - continue; - } - *diffs += childDiffs; - } - else - { - int converted = - sscanf_s(buff, g_SummaryFormatString, &childLoaded, &childJitted, &childFailed, &childExcluded, &childMissing); - if (converted != 5) - { - LogError("Couldn't parse status message: \"%s\"", buff); - continue; - } - *diffs = -1; - } - *loaded += childLoaded; - *jitted += childJitted; - *failed += childFailed; - *excluded += childExcluded; - *missing += childMissing; - } - else - { - // Do output pass-through. - // Note that the same logging verbosity level is passed to the child processes. - LogPassThroughStdout("%s", buff); - } - } - -Cleanup: - if (fp != NULL) - { - fclose(fp); - } -} - -#ifndef TARGET_UNIX -BOOL WINAPI CtrlHandler(DWORD fdwCtrlType) -{ - // Since the child SuperPMI.exe processes share the same console - // We don't need to kill them individually as they also receive the Ctrl-C - - closeRequested = 1; // set a flag to indicate we need to quit - return TRUE; -} -#else // TARGET_UNIX -static void PosixCtrlHandler(int signum) -{ - (void)signum; - closeRequested = 1; -} -#endif // TARGET_UNIX - -int __cdecl compareInt(const void* arg1, const void* arg2) -{ - return (*(const int*)arg1) - (*(const int*)arg2); -} - -struct PerWorkerData -{ -#ifdef TARGET_UNIX - int hStdOutput = -1; - int hStdError = -1; -#else - HANDLE hStdOutput = INVALID_HANDLE_VALUE; - HANDLE hStdError = INVALID_HANDLE_VALUE; -#endif - - char* failingMCListPath = nullptr; - char* detailsPath = nullptr; - char* stdOutputPath = nullptr; - char* stdErrorPath = nullptr; - SpmiResult resultCode = SpmiResult::GeneralFailure; -}; - -static void MergeWorkerMCLs(char* mclFilename, PerWorkerData* workerData, int workerCount, char* PerWorkerData::*mclPath) -{ - int **MCL = new int *[workerCount], *MCLCount = new int[workerCount], totalCount = 0; - - for (int i = 0; i < workerCount; i++) - { - // Read the next partial MCL file - ReadMCLToArray(workerData[i].*mclPath, &MCL[i], &MCLCount[i]); - - totalCount += MCLCount[i]; - } - - int* mergedMCL = new int[totalCount]; - int index = 0; - - for (int i = 0; i < workerCount; i++) - { - for (int j = 0; j < MCLCount[i]; j++) - mergedMCL[index++] = MCL[i][j]; - } - - qsort(mergedMCL, totalCount, sizeof(int), compareInt); - - // Write the merged MCL array back to disk - if (!WriteArrayToMCL(mclFilename, mergedMCL, totalCount)) - LogError("Unable to write to MCL file %s.", mclFilename); - - delete[] MCL; - delete[] MCLCount; - delete[] mergedMCL; -} - -static void MergeWorkerCsvs(char* csvFilename, PerWorkerData* workerData, int workerCount, char* PerWorkerData::* csvPath) -{ - FileWriter fw; - if (!FileWriter::CreateNew(csvFilename, &fw)) - { - LogError("Could not create file %s", csvFilename); - return; - } - - bool hasHeader = false; - for (int i = 0; i < workerCount; i++) - { - switch (workerData[i].resultCode) - { - case SpmiResult::Success: - case SpmiResult::Diffs: - case SpmiResult::Misses: - case SpmiResult::Error: - break; - - default: - LogWarning("Skipping merging CSV from child %d due to result code %d", i, (int)workerData[i].resultCode); - continue; - } - - FileLineReader reader; - if (!FileLineReader::Open(workerData[i].*csvPath, &reader)) - { - LogError("Could not open child CSV file %s", workerData[i].*csvPath); - continue; - } - - if (hasHeader && !reader.AdvanceLine()) - { - continue; - } - - while (reader.AdvanceLine()) - { - fw.Printf("%s\n", reader.GetCurrentLine()); - } - - hasHeader = true; - } -} - -#define MAX_CMDLINE_SIZE 0x1000 // 4 KB - -//------------------------------------------------------------- -// addJitOptionArgument: Writes jitOption arguments to the argument string for a child spmi process. -// -// Arguments: -// jitOptions - map with options -// bytesWritten - size of the argument string in bytes -// spmiArgs - pointer to the argument string -// optionName - the jitOption name, can include [force] flag. -// -void addJitOptionArgument(LightWeightMap* jitOptions, - int& bytesWritten, - char* spmiArgs, - const char* optionName) -{ - if (jitOptions != nullptr) - { - for (unsigned i = 0; i < jitOptions->GetCount(); i++) - { - const char* key = (const char*)jitOptions->GetBuffer(jitOptions->GetKey(i)); - const char* value = (const char*)jitOptions->GetBuffer(jitOptions->GetItem(i)); - bytesWritten += sprintf_s(spmiArgs + bytesWritten, MAX_CMDLINE_SIZE - bytesWritten, " -%s %s=%s", - optionName, key, value); - } - } -} - -// From the arguments that we parsed, construct the arguments to pass to the child processes. -char* ConstructChildProcessArgs(const CommandLine::Options& o) -{ - int bytesWritten = 0; - char* spmiArgs = new char[MAX_CMDLINE_SIZE]; - *spmiArgs = '\0'; - -#define ADDSTRING(s) \ - if (s != nullptr) \ - { \ - bytesWritten += sprintf_s(spmiArgs + bytesWritten, MAX_CMDLINE_SIZE - bytesWritten, " %s", s); \ - } -#define ADDARG_BOOL(b, arg) \ - if (b) \ - { \ - bytesWritten += sprintf_s(spmiArgs + bytesWritten, MAX_CMDLINE_SIZE - bytesWritten, " %s", arg); \ - } -#define ADDARG_STRING(s, arg) \ - if (s != nullptr) \ - { \ - bytesWritten += sprintf_s(spmiArgs + bytesWritten, MAX_CMDLINE_SIZE - bytesWritten, " %s %s", arg, s); \ - } - - // Only pass through an integer argument if it is not the same as the default (which must be specified here). - // (This is a proxy for "did the command-line parser actually parse something for this argument".) -#define ADDARG_INT(i, arg, defaultValue) \ - if (i != defaultValue) \ - { \ - bytesWritten += sprintf_s(spmiArgs + bytesWritten, MAX_CMDLINE_SIZE - bytesWritten, " %s %d", arg, i); \ - } - - // We don't pass through: - // - // -parallel - // -writeLogFile (the parent process writes the log file based on the output of the child processes) - // -reproName - // -coredistools - // -skipCleanup - // -metricsSummary - // -baseMetricsSummary - // -diffMetricsSummary - // -failingMCList - // -diffMCList - // - // Everything else we need to reconstruct and pass through. - // - // Note that for -verbosity, if the level includes LOGLEVEL_INFO, the process will output a - // "Loaded/Jitted/FailedCompile/Excluded/Missing[/Diffs]" line which is parsed and summarized by - // the parent process. If it isn't output, the summary doesn't happen. - - ADDARG_BOOL(o.breakOnError, "-boe"); - ADDARG_BOOL(o.breakOnAssert, "-boa"); - ADDARG_BOOL(o.breakOnException, "-box"); - ADDARG_BOOL(o.ignoreStoredConfig, "-ignoreStoredConfig"); - ADDARG_BOOL(o.applyDiff, "-applyDiff"); - ADDARG_STRING(o.verbosity, "-verbosity"); - ADDARG_STRING(o.reproName, "-reproName"); - ADDARG_STRING(o.methodStatsTypes, "-emitMethodStats"); - ADDARG_STRING(o.hash, "-matchHash"); - ADDARG_STRING(o.targetArchitecture, "-target"); - ADDARG_STRING(o.compileList, "-compile"); - ADDARG_INT(o.failureLimit, "-failureLimit", -1); - ADDARG_INT(o.repeatCount, "-repeatCount", 1); - - addJitOptionArgument(o.forceJitOptions, bytesWritten, spmiArgs, "jitoption force"); - addJitOptionArgument(o.forceJit2Options, bytesWritten, spmiArgs, "jit2option force"); - - addJitOptionArgument(o.jitOptions, bytesWritten, spmiArgs, "jitoption"); - addJitOptionArgument(o.jit2Options, bytesWritten, spmiArgs, "jit2option"); - - ADDSTRING(o.nameOfJit); - ADDSTRING(o.nameOfJit2); - ADDSTRING(o.nameOfInputMethodContextFile); - -#undef ADDSTRING -#undef ADDARG_BOOL -#undef ADDARG_STRING -#undef ADDARG_INT - - return spmiArgs; -} - -#ifdef TARGET_UNIX - -static bool RegisterCtrlHandler() -{ - if (signal(SIGINT, PosixCtrlHandler) == SIG_ERR) - { - LogError("Failed to register SIGINT handler."); - return false; - } - return true; -} - -static bool GetTempFolderPath(char* tempPath) -{ - const char* tmpDir = getenv("TMPDIR"); - if (tmpDir == nullptr) - tmpDir = "/tmp"; - snprintf(tempPath, MAX_PATH, "%s/", tmpDir); - return true; -} - -static int GetDefaultWorkerCount() -{ - long nprocs = sysconf(_SC_NPROCESSORS_ONLN); - return (nprocs > 0) ? (int)nprocs : 1; -} - -static bool GetCurrentExePath(char* path) -{ - char* exePath = minipal_getexepath(); - if (exePath == nullptr) - { - LogError("Failed to get current exe path."); - return false; - } - strncpy(path, exePath, MAX_PATH - 1); - path[MAX_PATH - 1] = '\0'; - free(exePath); - return true; -} - -static bool OpenWorkerOutputFiles(PerWorkerData& wd, int workerIndex) -{ - LogDebug("stdout %i=%s", workerIndex, wd.stdOutputPath); - wd.hStdOutput = open(wd.stdOutputPath, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0666); - if (wd.hStdOutput == -1) - { - LogError("Unable to open '%s'. errno=%d", wd.stdOutputPath, errno); - return false; - } - - LogDebug("stderr %i=%s", workerIndex, wd.stdErrorPath); - wd.hStdError = open(wd.stdErrorPath, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0666); - if (wd.hStdError == -1) - { - LogError("Unable to open '%s'. errno=%d", wd.stdErrorPath, errno); - close(wd.hStdOutput); - wd.hStdOutput = -1; - return false; - } - return true; -} - -static void CloseWorkerOutputFiles(PerWorkerData& wd) -{ - close(wd.hStdOutput); - close(wd.hStdError); -} - -// Returns a heap-allocated array of per-worker exit codes; caller must free with FreeWorkerExitCodes. -static int* WaitForWorkerProcesses(SpmiProcessHandle* handles, int count) -{ - int* exitCodes = new int[count]; - for (int i = 0; i < count; i++) - { - int status; - pid_t result; - do - { - result = waitpid(handles[i], &status, 0); - } while (result == -1 && errno == EINTR); - - if (result == -1) - { - LogError("waitpid failed for child %d: %s", i, strerror(errno)); - exitCodes[i] = -1; - } - else if (WIFEXITED(status)) - { - exitCodes[i] = WEXITSTATUS(status); - } - else - { - // Terminated by a signal (e.g., OOM killer). - exitCodes[i] = -1; - } - } - return exitCodes; -} - -static bool GetWorkerExitCode(SpmiProcessHandle* handles, int* exitCodes, int workerIndex, unsigned& exitCode) -{ - if (exitCodes[workerIndex] == -1) - return false; - exitCode = (unsigned)exitCodes[workerIndex]; - return true; -} - -static void FreeWorkerExitCodes(int* exitCodes) -{ - delete[] exitCodes; -} - -#else // !TARGET_UNIX - -static bool RegisterCtrlHandler() -{ - if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) - { - LogError("Failed to set control handler."); - return false; - } - return true; -} - -static bool GetTempFolderPath(char* tempPath) -{ - if (!GetTempPathA(MAX_PATH, tempPath)) - { - LogError("Failed to get path to temp folder."); - return false; - } - return true; -} - -static int GetDefaultWorkerCount() -{ - SYSTEM_INFO sysinfo; - GetSystemInfo(&sysinfo); - - int count = (int)sysinfo.dwNumberOfProcessors; - - // If we ever execute on a machine which has more than MAXIMUM_WAIT_OBJECTS(64) CPU cores - // we still can't spawn more than the max supported by WaitForMultipleObjects() - if (count > MAXIMUM_WAIT_OBJECTS) - count = MAXIMUM_WAIT_OBJECTS; - - return count; -} - -static bool GetCurrentExePath(char* path) -{ - if (!GetModuleFileName(NULL, path, MAX_PATH)) - { - LogError("Failed to get current exe path."); - return false; - } - return true; -} - -static bool OpenWorkerOutputFiles(PerWorkerData& wd, int workerIndex) -{ - SECURITY_ATTRIBUTES sa; - sa.nLength = sizeof(sa); - sa.lpSecurityDescriptor = NULL; - sa.bInheritHandle = TRUE; // Let newly created stdout/stderr handles be inherited. - - LogDebug("stdout %i=%s", workerIndex, wd.stdOutputPath); - wd.hStdOutput = CreateFileA(wd.stdOutputPath, GENERIC_WRITE, FILE_SHARE_READ, &sa, CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, NULL); - if (wd.hStdOutput == INVALID_HANDLE_VALUE) - { - LogError("Unable to open '%s'. GetLastError()=%u", wd.stdOutputPath, GetLastError()); - return false; - } - - LogDebug("stderr %i=%s", workerIndex, wd.stdErrorPath); - wd.hStdError = CreateFileA(wd.stdErrorPath, GENERIC_WRITE, FILE_SHARE_READ, &sa, CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, NULL); - if (wd.hStdError == INVALID_HANDLE_VALUE) - { - LogError("Unable to open '%s'. GetLastError()=%u", wd.stdErrorPath, GetLastError()); - CloseHandle(wd.hStdOutput); - wd.hStdOutput = INVALID_HANDLE_VALUE; - return false; - } - return true; -} - -static void CloseWorkerOutputFiles(PerWorkerData& wd) -{ - CloseHandle(wd.hStdOutput); - CloseHandle(wd.hStdError); -} - -// Returns nullptr; exit codes are retrieved lazily via GetWorkerExitCode / GetExitCodeProcess. -static int* WaitForWorkerProcesses(SpmiProcessHandle* handles, int count) -{ - DWORD waitResult = WaitForMultipleObjects((DWORD)count, handles, TRUE, INFINITE); - if (waitResult == WAIT_FAILED) - { - LogError("WaitForMultipleObjects failed. GetLastError()=%u", GetLastError()); - return nullptr; - } - return nullptr; -} - -static bool GetWorkerExitCode(SpmiProcessHandle* handles, int* exitCodes, int workerIndex, unsigned& exitCode) -{ - DWORD code; - if (!GetExitCodeProcess(handles[workerIndex], &code)) - return false; - exitCode = (unsigned)code; - return true; -} - -static void FreeWorkerExitCodes(int* exitCodes) -{ - // No-op on Windows; exit codes are retrieved via GetExitCodeProcess. -} - -#endif // TARGET_UNIX - -int doParallelSuperPMI(CommandLine::Options& o) -{ - HRESULT hr = E_FAIL; - SimpleTimer st; - st.Start(); - - if (!RegisterCtrlHandler()) - return 1; - - char tempPath[MAX_PATH]; - if (!GetTempFolderPath(tempPath)) - return 1; - - if (o.workerCount <= 0) - o.workerCount = GetDefaultWorkerCount(); - - // Obtain the path of the current executable, which we will use to spawn ourself. - char* spmiFilename = new char[MAX_PATH]; - if (!GetCurrentExePath(spmiFilename)) - return 1; - - char* spmiArgs = ConstructChildProcessArgs(o); - - // TODO: merge all this output to a single call to LogVerbose to avoid all the newlines. - LogVerbose("Using child (%s) with args (%s)", spmiFilename, spmiArgs); - if (o.mclFilename != nullptr) - LogVerbose(" failingMCList=%s", o.mclFilename); - if (o.details != nullptr) - LogVerbose(" details=%s", o.details); - LogVerbose(" workerCount=%d, skipCleanup=%d.", o.workerCount, o.skipCleanup); - - PerWorkerData* perWorkerData = new PerWorkerData[o.workerCount]; - - // Add a random number to the temporary file names to allow multiple parallel SuperPMI to happen at once. - unsigned int randNumber = 0; - minipal_get_non_cryptographically_secure_random_bytes((uint8_t*)&randNumber, sizeof(randNumber)); - - for (int i = 0; i < o.workerCount; i++) - { - PerWorkerData& wd = perWorkerData[i]; - if (o.mclFilename != nullptr) - { - wd.failingMCListPath = new char[MAX_PATH]; - sprintf_s(wd.failingMCListPath, MAX_PATH, "%sParallelSuperPMI-%u-%d.mcl", tempPath, randNumber, i); - } - - if (o.details != nullptr) - { - wd.detailsPath = new char[MAX_PATH]; - sprintf_s(wd.detailsPath, MAX_PATH, "%sParallelSuperPMI-Details-%u-%d.csv", tempPath, randNumber, i); - } - - wd.stdOutputPath = new char[MAX_PATH]; - wd.stdErrorPath = new char[MAX_PATH]; - - sprintf_s(wd.stdOutputPath, MAX_PATH, "%sParallelSuperPMI-stdout-%u-%d.txt", tempPath, randNumber, i); - sprintf_s(wd.stdErrorPath, MAX_PATH, "%sParallelSuperPMI-stderr-%u-%d.txt", tempPath, randNumber, i); - } - - char cmdLine[MAX_CMDLINE_SIZE]; - cmdLine[0] = '\0'; - int bytesWritten; - - SpmiProcessHandle* hProcesses = new SpmiProcessHandle[o.workerCount]; - for (int i = 0; i < o.workerCount; i++) - { - bytesWritten = sprintf_s(cmdLine, MAX_CMDLINE_SIZE, "%s -stride %d %d", spmiFilename, i + 1, o.workerCount); - - PerWorkerData& wd = perWorkerData[i]; - - if (wd.failingMCListPath != nullptr) - { - bytesWritten += sprintf_s(cmdLine + bytesWritten, MAX_CMDLINE_SIZE - bytesWritten, " -failingMCList %s", - wd.failingMCListPath); - } - - if (wd.detailsPath != nullptr) - { - bytesWritten += sprintf_s(cmdLine + bytesWritten, MAX_CMDLINE_SIZE - bytesWritten, " -details %s", - wd.detailsPath); - } - - bytesWritten += sprintf_s(cmdLine + bytesWritten, MAX_CMDLINE_SIZE - bytesWritten, " -v ewmin %s", spmiArgs); - - if (!OpenWorkerOutputFiles(wd, i)) - return -1; - - // Create a SuperPMI worker process and redirect its output to file - if (!StartProcess(cmdLine, wd.hStdOutput, wd.hStdError, &hProcesses[i])) - return -1; - } - - int* exitCodes = WaitForWorkerProcesses(hProcesses, o.workerCount); - - // Close stdout/stderr - for (int i = 0; i < o.workerCount; i++) - CloseWorkerOutputFiles(perWorkerData[i]); - - SpmiResult result = SpmiResult::Success; - - if (!closeRequested) - { - // Figure out the error code to use. - // Mainly, if any child returns non-zero, we want to return non-zero, to indicate failure. - for (int i = 0; i < o.workerCount; i++) - { - unsigned exitCodeTmp; - bool ok = GetWorkerExitCode(hProcesses, exitCodes, i, exitCodeTmp); - if (ok) - { - SpmiResult childResult = (SpmiResult)exitCodeTmp; - - switch (childResult) - { - case SpmiResult::Success: - case SpmiResult::Diffs: - case SpmiResult::Misses: - case SpmiResult::Error: - case SpmiResult::JitFailedToInit: - break; - - default: - // We may get here for OOM-killed, for example. - LogError("Child process %d exited with code %u", i, exitCodeTmp); - childResult = SpmiResult::GeneralFailure; - break; - } - - perWorkerData[i].resultCode = childResult; - - if (childResult != result) - { - // In priority: first failures are more important to propagate - if (result == SpmiResult::GeneralFailure || childResult == SpmiResult::GeneralFailure) - { - result = SpmiResult::GeneralFailure; - } - else if (result == SpmiResult::JitFailedToInit || childResult == SpmiResult::JitFailedToInit) - { - result = SpmiResult::JitFailedToInit; - } - else if (result == SpmiResult::Error || childResult == SpmiResult::Error) - { - result = SpmiResult::Error; - } - else if (result == SpmiResult::Diffs || childResult == SpmiResult::Diffs) - { - result = SpmiResult::Diffs; - } - else if (result == SpmiResult::Misses || childResult == SpmiResult::Misses) - { - result = SpmiResult::Misses; - } - // Keep success result - } - } - else - { - LogError("Could not get exit code for child process %d\n", i); - result = SpmiResult::GeneralFailure; - } - } - - bool usageError = false; // variable to flag if we hit a usage error in SuperPMI - - int loaded = 0, jitted = 0, failed = 0, excluded = 0, missing = 0, diffs = 0; - - // Read the stderr files and log them as errors - // Read the stdout files and parse them for counts and log any MISSING or ISSUE errors - for (int i = 0; i < o.workerCount; i++) - { - PerWorkerData& wd = perWorkerData[i]; - ProcessChildStdErr(wd.stdErrorPath); - ProcessChildStdOut(o, wd.stdOutputPath, &loaded, &jitted, &failed, &excluded, &missing, &diffs, &usageError); - - if (usageError) - break; - } - - if (o.mclFilename != nullptr && !usageError) - { - // Concat the resulting .mcl files - MergeWorkerMCLs(o.mclFilename, perWorkerData, o.workerCount, &PerWorkerData::failingMCListPath); - } - - if (o.details != nullptr && !usageError) - { - // Concat the resulting diff .mcl files - MergeWorkerCsvs(o.details, perWorkerData, o.workerCount, &PerWorkerData::detailsPath); - } - - if (!usageError) - { - if (o.applyDiff) - { - LogInfo(g_AsmDiffsSummaryFormatString, loaded, jitted, failed, excluded, missing, diffs); - } - else - { - LogInfo(g_SummaryFormatString, loaded, jitted, failed, excluded, missing); - } - } - - st.Stop(); - LogVerbose("Total time: %fms", st.GetMilliseconds()); - } - - FreeWorkerExitCodes(exitCodes); - - if (!o.skipCleanup) - { - // Delete all temporary files generated - for (int i = 0; i < o.workerCount; i++) - { - PerWorkerData& wd = perWorkerData[i]; - if (wd.failingMCListPath != nullptr) - { - remove(wd.failingMCListPath); - } - if (wd.detailsPath != nullptr) - { - remove(wd.detailsPath); - } - remove(wd.stdOutputPath); - remove(wd.stdErrorPath); - } - } - - return (int)result; -} diff --git a/src/coreclr/tools/superpmi/superpmi/streamingsuperpmi.cpp b/src/coreclr/tools/superpmi/superpmi/streamingsuperpmi.cpp deleted file mode 100644 index 89ee2f2eaaf216..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi/streamingsuperpmi.cpp +++ /dev/null @@ -1,317 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "standardpch.h" -#include "superpmi.h" -#include "jitinstance.h" -#include "simpletimer.h" -#include "mclist.h" -#include "lightweightmap.h" -#include "commandline.h" -#include "errorhandling.h" -#include "methodcontext.h" -#include "methodcontextreader.h" -#include "spmiutil.h" -#include "fileio.h" - -#if defined(_WIN32) -#define strtok_r strtok_s -#endif - -static bool AddJitOption(LightWeightMap* map, char* newOption) -{ - char* key; - char* value; - - if (!CommandLine::ParseJitOption(newOption, &key, &value)) - { - return false; - } - - DWORD keyIndex = - (DWORD)map->AddBuffer((unsigned char*)key, sizeof(char) * ((unsigned int)strlen(key) + 1)); - DWORD valueIndex = - (DWORD)map->AddBuffer((unsigned char*)value, sizeof(char) * ((unsigned int)strlen(value) + 1)); - map->Add(keyIndex, valueIndex); - - delete[] key; - delete[] value; - - return true; -} - -struct CacheEntry -{ - MethodContext* mc; - int age; -}; - -static MethodContext* getMethodContext(int index, MethodContextReader* reader) -{ - enum { CACHE_SIZE = 100 }; - static CacheEntry cache[CACHE_SIZE] = {}; - static int count = 0; - static int age = 0; - int i = 0; - - // Search the cache - // - for (; i < count; i++) - { - if (cache[i].mc->index == index) - { - break; - } - } - - if (i == count) - { - // Method not found in cache - // - LogDebug("[streaming] loading MC %i from file", index); - if (i == CACHE_SIZE) - { - // Cache is full, evict oldest entry - // - int oldestAge = age; - int oldestEntry = -1; - for (int j = 0; j < CACHE_SIZE; j++) - { - if (cache[j].age < oldestAge) - { - oldestEntry = j; - oldestAge = cache[j].age; - } - } - - LogDebug("[streaming] evicting MC %i from cache", cache[oldestEntry].mc->index); - delete cache[oldestEntry].mc; - cache[oldestEntry].mc = nullptr; - i = oldestEntry; - } - else - { - count++; - } - - reader->Reset(&index, 1); - MethodContextBuffer mcb = reader->GetNextMethodContext(); - - if (mcb.Error()) - { - return nullptr; - } - - MethodContext* mc = nullptr; - if (!MethodContext::Initialize(index, mcb.buff, mcb.size, /* readCompileResults */ false, &mc)) - { - return nullptr; - } - - cache[i].mc = mc; - } - else - { - LogDebug("[streaming] found MC %i in cache", index); - } - - // Move to front... - // - if (i != 0) - { - CacheEntry temp = cache[0]; - cache[0] = cache[i]; - cache[i] = temp; - } - - cache[0].age = age++; - return cache[0].mc; -} - -int doStreamingSuperPMI(CommandLine::Options& o) -{ - HRESULT hr = E_FAIL; - SimpleTimer st; - st.Start(); - - FILE* streamFile = nullptr; - if (_stricmp(o.streamFile, "stdin") == 0) - { - streamFile = stdin; - } - else - { - streamFile = fopen(o.streamFile, "r"); - } - - if (streamFile == nullptr) - { - LogError("Failed to open file '%s'. GetLastError()=%u", o.streamFile, GetLastError()); - return 1; - } - - // Just one worker for now... all method selection done via stream file - // - o.workerCount = 1; - o.indexes = nullptr; - o.indexCount = -1; - o.hash = nullptr; - o.offset = -1; - o.increment = -1; - - // The method context reader handles skipping any unrequested method contexts - // Used in conjunction with an MCI file, it does a lot less work... - MethodContextReader* reader = - new MethodContextReader(o.nameOfInputMethodContextFile, o.indexes, o.indexCount, o.hash, o.offset, o.increment); - if (!reader->isValid()) - { - return (int)SpmiResult::GeneralFailure; - } - - JitInstance* jit = nullptr; - - enum { BUFFER_SIZE = 2048 }; - - char line[BUFFER_SIZE]; - const char* const seps = "!"; - char *next = nullptr; - - // Syntax is dddd { ! =value }* - // Likes starting with '#' are ignored - // - while (fgets(line, BUFFER_SIZE, streamFile) != nullptr) - { - for (int i = 0; i < BUFFER_SIZE; i++) - { - if (line[i] == '\n' || line[i] == '\r') - { - line[i]= 0; - break; - } - } - line[BUFFER_SIZE - 1] = '0'; - - LogDebug("[streaming] Request: '%s'", line); - - if (line[0] == '#') - { - continue; - } - - if (strncmp(line, "quit", 4) == 0) - { - LogDebug("[streaming] Quitting"); - break; - } - - char* tok = strtok_r(line, seps, &next); - const int index = atoi(tok); - - if (index == 0) - { - LogDebug("[streaming] Stopping"); - break; - } - - LogDebug("[streaming] Method %d", index); - - LightWeightMap* baseForceJitOptions = o.forceJitOptions; - LightWeightMap* forceJitOptions = nullptr; - bool skip = false; - - while ((tok = strtok_r(nullptr, seps, &next))) - { - if (forceJitOptions == nullptr) - { - if (baseForceJitOptions == nullptr) - { - forceJitOptions = new LightWeightMap(); - } - else - { - forceJitOptions = new LightWeightMap(*baseForceJitOptions); - } - } - - bool added = AddJitOption(forceJitOptions, tok); - - if (!added) - { - LogInfo("[streaming] unable to parse option '%s'", tok); - skip = true; - break; - } - } - - if (skip) - { - continue; - } - - LogDebug("[streaming] Launching..."); - MethodContext* const mc = getMethodContext(index, reader); - - if (mc == nullptr) - { - return (int)SpmiResult::GeneralFailure; - } - - if (mc->index != index) - { - LogDebug("MC cache lookup failure, wanted index %d, got index %d\n", index, mc->index); - return (int)SpmiResult::GeneralFailure; - } - - if (jit == nullptr) - { - LogDebug("[streaming] loading jit %s", o.nameOfJit); - SimpleTimer stInitJit; - jit = JitInstance::InitJit(o.nameOfJit, o.breakOnAssert, &stInitJit, mc, forceJitOptions, o.jitOptions); - - if (jit == nullptr) - { - // InitJit already printed a failure message - return (int)SpmiResult::JitFailedToInit; - } - } - else - { - jit->updateForceOptions(forceJitOptions); - jit->resetConfig(mc); - } - - LogDebug("[streaming] invoking jit"); - fflush(stdout); - - bool collectThroughput = false; - ReplayResults res = jit->CompileMethod(mc, reader->GetMethodContextIndex(), collectThroughput); - - if (res.Result == ReplayResult::Success) - { - if (Logger::IsLogLevelEnabled(LOGLEVEL_DEBUG)) - { - mc->cr->dumpToConsole(); // Dump the compile results if doing debug logging - } - } - else if (res.Result == ReplayResult::Error) - { - LogDebug("[streaming] jit compilation failed"); - - LogError("Method %d of size %d failed to load and compile correctly%s (%s).", - reader->GetMethodContextIndex(), mc->methodSize, - (o.nameOfJit2 == nullptr) ? "" : " by JIT1", o.nameOfJit); - } - - // Protocol with clients is for them to read stdout. Let them know we're done. - // - printf("[streaming] Done. Status=%d\n", (int) res.Result); - fflush(stdout); - - // Cleanup - // - delete forceJitOptions; - mc->Reset(); - } - - return (int)SpmiResult::Success; -} diff --git a/src/coreclr/tools/superpmi/superpmi/superpmi.cpp b/src/coreclr/tools/superpmi/superpmi/superpmi.cpp deleted file mode 100644 index b906f243703612..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi/superpmi.cpp +++ /dev/null @@ -1,844 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "standardpch.h" - -#ifdef USE_COREDISTOOLS -#include "coredistools.h" -#endif // USE_COREDISTOOLS - -#include "lightweightmap.h" -#include "commandline.h" -#include "superpmi.h" -#include "jitinstance.h" -#include "neardiffer.h" -#include "simpletimer.h" -#include "methodcontext.h" -#include "methodcontextreader.h" -#include "mclist.h" -#include "methodstatsemitter.h" -#include "spmiutil.h" -#include "fileio.h" - -extern int doParallelSuperPMI(CommandLine::Options& o); -extern int doStreamingSuperPMI(CommandLine::Options& o); - -// NOTE: these output status strings are parsed by parallelsuperpmi.cpp::ProcessChildStdOut(). -// There must be a single, fixed prefix common to all strings, to ease the determination of when -// to parse the string fully. -const char* const g_AllFormatStringFixedPrefix = "Loaded "; -const char* const g_SummaryFormatString = "Loaded %d Jitted %d FailedCompile %d Excluded %d Missing %d"; -const char* const g_AsmDiffsSummaryFormatString = "Loaded %d Jitted %d FailedCompile %d Excluded %d Missing %d Diffs %d"; - -//#define SuperPMI_ChewMemory 0x7FFFFFFF //Amount of address space to consume on startup - -void SetSuperPmiTargetArchitecture(const char* targetArchitecture) -{ - // Allow overriding the default. - - if (targetArchitecture != nullptr) - { - if ((0 == _stricmp(targetArchitecture, "x64")) || (0 == _stricmp(targetArchitecture, "amd64"))) - { - SetSpmiTargetArchitecture(SPMI_TARGET_ARCHITECTURE_AMD64); - } - else if (0 == _stricmp(targetArchitecture, "x86")) - { - SetSpmiTargetArchitecture(SPMI_TARGET_ARCHITECTURE_X86); - } - else if ((0 == _stricmp(targetArchitecture, "arm")) || (0 == _stricmp(targetArchitecture, "arm32"))) - { - SetSpmiTargetArchitecture(SPMI_TARGET_ARCHITECTURE_ARM); - } - else if (0 == _stricmp(targetArchitecture, "arm64")) - { - SetSpmiTargetArchitecture(SPMI_TARGET_ARCHITECTURE_ARM64); - } - else if (0 == _stricmp(targetArchitecture, "loongarch64")) - { - SetSpmiTargetArchitecture(SPMI_TARGET_ARCHITECTURE_LOONGARCH64); - } - else if (0 == _stricmp(targetArchitecture, "riscv64")) - { - SetSpmiTargetArchitecture(SPMI_TARGET_ARCHITECTURE_RISCV64); - } - else if (0 == _stricmp(targetArchitecture, "wasm") || (0 == _stricmp(targetArchitecture, "wasm32"))) - { - SetSpmiTargetArchitecture(SPMI_TARGET_ARCHITECTURE_WASM32); - } - else - { - LogError("Illegal target architecture '%s'", targetArchitecture); - } - } -} - -enum class NearDifferResult -{ - SuccessWithoutDiff, - SuccessWithDiff, - Failure, -}; - -// This function uses PAL_TRY, so it can't be in the a function that requires object unwinding. Extracting it out here -// avoids compiler error. -// -static NearDifferResult InvokeNearDiffer(NearDiffer* nearDiffer, - MethodContext** mc, - CompileResult** crl, - MethodContextReader** reader) -{ - - struct Param : FilterSuperPMIExceptionsParam_CaptureException - { - NearDiffer* nearDiffer; - MethodContext** mc; - CompileResult** crl; - MethodContextReader** reader; - NearDifferResult result; - } param; - param.nearDiffer = nearDiffer; - param.mc = mc; - param.crl = crl; - param.reader = reader; - param.result = NearDifferResult::Failure; - - PAL_TRY(Param*, pParam, ¶m) - { - if (!pParam->nearDiffer->compare(*pParam->mc, *pParam->crl, (*pParam->mc)->cr)) - { - pParam->result = NearDifferResult::SuccessWithDiff; - LogIssue(ISSUE_ASM_DIFF, "main method %d of size %d differs", (*pParam->reader)->GetMethodContextIndex(), - (*pParam->mc)->methodSize); - } - else - { - pParam->result = NearDifferResult::SuccessWithoutDiff; - } - } - PAL_EXCEPT_FILTER(FilterSuperPMIExceptions_CaptureExceptionAndStop) - { - SpmiException e(¶m); - - LogError("main method %d of size %d failed to load and compile correctly.", (*reader)->GetMethodContextIndex(), - (*mc)->methodSize); - e.ShowAndDeleteMessage(); - param.result = NearDifferResult::Failure; - } - PAL_ENDTRY - - return param.result; -} - -static const char* ResultToString(ReplayResult result) -{ - switch (result) - { - case ReplayResult::Success: - return "Success"; - case ReplayResult::Error: - return "Error"; - case ReplayResult::Miss: - return "Miss"; - default: - return "Unknown"; - } -} - -static void PrintDiffsCsvHeader(FileWriter& fw) -{ - fw.Print("Context,Context size,Method full name,Tier name,Base result,Diff result,MinOpts,Has diff,Base instructions,Diff instructions"); - -#define JITMETADATAINFO(name, type, flags) -#define JITMETADATAMETRIC(name, type, flags) fw.Print(",Base " #name ",Diff " #name); - -#include "jitmetadatalist.h" - - fw.Print("\n"); -} - -static void PrintDiffsCsvRow( - FileWriter& fw, - int context, uint32_t contextSize, - const ReplayResults& baseRes, - const ReplayResults& diffRes, - bool hasDiff) -{ - fw.Printf("%d,%u,", context, contextSize); - fw.PrintQuotedCsvField(diffRes.CompileResults->MethodFullName == nullptr ? "" : diffRes.CompileResults->MethodFullName); - fw.Printf( - ",%s,%s,%s,%s,%s,%lld,%lld", - diffRes.CompileResults->TieringName == nullptr ? "" : diffRes.CompileResults->TieringName, - ResultToString(baseRes.Result), ResultToString(diffRes.Result), - diffRes.IsMinOpts ? "True" : "False", - hasDiff ? "True" : "False", - baseRes.NumExecutedInstructions, diffRes.NumExecutedInstructions); - -#define JITMETADATAINFO(name, type, flags) -#define JITMETADATAMETRIC(name, type, flags) \ - fw.Print(","); \ - fw.Print(baseRes.CompileResults->name); \ - fw.Print(","); \ - fw.Print(diffRes.CompileResults->name); - -#include "jitmetadatalist.h" - - fw.Print("\n"); -} - -static void PrintReplayCsvHeader(FileWriter& fw) -{ - fw.Printf("Context,Context size,Method full name,Tier name,Result,MinOpts,Instructions"); - -#define JITMETADATAINFO(name, type, flags) -#define JITMETADATAMETRIC(name, type, flags) fw.Print("," #name); - -#include "jitmetadatalist.h" - - fw.Print("\n"); -} - -static void PrintReplayCsvRow( - FileWriter& fw, - int context, uint32_t contextSize, - const ReplayResults& res) -{ - fw.Printf("%d,%u,", context, contextSize); - fw.PrintQuotedCsvField(res.CompileResults->MethodFullName == nullptr ? "" : res.CompileResults->MethodFullName); - fw.Printf(",%s,%s,%s,%lld", - res.CompileResults->TieringName == nullptr ? "" : res.CompileResults->TieringName, - ResultToString(res.Result), - res.IsMinOpts ? "True" : "False", - res.NumExecutedInstructions); - -#define JITMETADATAINFO(name, type, flags) -#define JITMETADATAMETRIC(name, type, flags) \ - fw.Print(","); \ - fw.Print(res.CompileResults->name); - -#include "jitmetadatalist.h" - - fw.Print("\n"); -} - -// Run superpmi. The return value is as follows: -// 0 : success -// -1 : general fatal error (e.g., failed to initialize, failed to read files) -// -2 : JIT failed to initialize -// 1 : there were compilation failures -// 2 : there were asm diffs -// 3 : there were missing values in method context -int __cdecl main(int argc, char* argv[]) -{ -#ifdef TARGET_UNIX - if (0 != PAL_Initialize(argc, argv)) - { - fprintf(stderr, "Error: Fail to PAL_Initialize\n"); - return (int)SpmiResult::GeneralFailure; - } -#endif // TARGET_UNIX - - Logger::Initialize(); - - SimpleTimer st1; - SimpleTimer st2; - SimpleTimer st3; - SimpleTimer st4; - st2.Start(); - JitInstance* jit = nullptr; - JitInstance* jit2 = nullptr; - MethodStatsEmitter* methodStatsEmitter = nullptr; - -#ifdef SuperPMI_ChewMemory - // Chew up the base 2gb of memory on x86... helpful in finding any places where classhandles etc are de-ref'd - SYSTEM_INFO sSysInfo; - GetSystemInfo(&sSysInfo); - - LPVOID lpvAddr; -#undef VirtualAlloc - do - { - lpvAddr = VirtualAlloc(NULL, sSysInfo.dwPageSize, MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS); - } while ((size_t)lpvAddr < SuperPMI_ChewMemory); -#endif - - bool collectThroughput = false; - MCList failingToReplayMCL; - FileWriter detailsCsv; - - CommandLine::Options o; - if (!CommandLine::Parse(argc, argv, &o)) - { - return (int)SpmiResult::GeneralFailure; - } - - if (o.parallel) - { - return doParallelSuperPMI(o); - } - - if (o.streamFile != nullptr) - { - return doStreamingSuperPMI(o); - } - - SetBreakOnException(o.breakOnException); - - if (o.methodStatsTypes != NULL && - (strchr(o.methodStatsTypes, '*') != NULL || strchr(o.methodStatsTypes, 't') != NULL || - strchr(o.methodStatsTypes, 'T') != NULL)) - { - collectThroughput = true; - } - - LogVerbose("Using jit(%s) with input (%s)", o.nameOfJit, o.nameOfInputMethodContextFile); - std::string indexesStr = " indexCount="; - indexesStr += std::to_string(o.indexCount); - indexesStr += " ("; - for (int i = 0; i < o.indexCount; i++) - { - indexesStr += std::to_string(o.indexes[i]); - if (i < (o.indexCount - 1)) - indexesStr += ","; - } - indexesStr += ")"; - LogVerbose(indexesStr.c_str()); - - if (o.methodStatsTypes != nullptr) - LogVerbose(" EmitMethodStats-Types=%s", o.methodStatsTypes); - - if (o.hash != nullptr) - LogVerbose(" MD5Hash=%s", o.hash); - - if (o.mclFilename != nullptr) - LogVerbose(" failingMCList=%s", o.mclFilename); - - if (o.offset > 0 && o.increment > 0) - LogVerbose(" offset=%d increment=%d", o.offset, o.increment); - - if (o.methodStatsTypes != nullptr) - { - methodStatsEmitter = new MethodStatsEmitter(o.nameOfInputMethodContextFile); - methodStatsEmitter->SetStatsTypes(o.methodStatsTypes); - } - - if (o.mclFilename != nullptr) - { - failingToReplayMCL.InitializeMCL(o.mclFilename); - } - if (o.details != nullptr) - { - if (!FileWriter::CreateNew(o.details, &detailsCsv)) - { - LogError("Could not create file %s", o.details); - return (int)SpmiResult::GeneralFailure; - } - } - - SetDebugDumpVariables(); - - // The method context reader handles skipping any unrequested method contexts - // Used in conjunction with an MCI file, it does a lot less work... - MethodContextReader* reader = - new MethodContextReader(o.nameOfInputMethodContextFile, o.indexes, o.indexCount, o.hash, o.offset, o.increment); - if (!reader->isValid()) - { - return (int)SpmiResult::GeneralFailure; - } - - int loadedCount = 0; - int jittedCount = 0; - int failToReplayCount = 0; - int errorCount = 0; - int errorCount2 = 0; - int diffsCount = 0; - int missingCount = 0; - int index = 0; - int excludedCount = 0; - - st1.Start(); - NearDiffer nearDiffer(o.targetArchitecture, o.useCoreDisTools); - - if (o.applyDiff) - { - if (!nearDiffer.InitAsmDiff()) - { - return (int)SpmiResult::GeneralFailure; - } - } - - if (o.details != nullptr) - { - if (o.applyDiff) - { - PrintDiffsCsvHeader(detailsCsv); - } - else - { - PrintReplayCsvHeader(detailsCsv); - } - } - - // This doesn't change in the work loop below, so compute it once. - double totalWork = reader->TotalWork() * o.repeatCount; - - while (true) - { - // Read the progress before doing the method context read. This is because when we output progress below, - // we output a sum of this plus the per-repeatCount progress for the currently read MC. - double progressBeforeCurrentMC = reader->Progress() * o.repeatCount; - - // Read the Method Context data from the file. - - MethodContextBuffer mcb = reader->GetNextMethodContext(); - if (mcb.Error()) - { - return (int)SpmiResult::GeneralFailure; - } - else if (mcb.allDone()) - { - LogDebug("Done processing method contexts"); - break; - } - - // Now read the data into a MethodContext. This could throw if the method context data is corrupt. - - loadedCount++; - const int mcIndex = reader->GetMethodContextIndex(); - MethodContext* mc = nullptr; - if (!MethodContext::Initialize(mcIndex, mcb.buff, mcb.size, /* readCompileResults */ false, &mc)) - { - return (int)SpmiResult::GeneralFailure; - } - - if (o.ignoreStoredConfig) - { - mc->setIgnoreStoredConfig(); - } - - if (reader->IsMethodExcluded(mc)) - { - excludedCount++; - LogInfo("main method %d of size %d with was excluded from the compilation.", - reader->GetMethodContextIndex(), mc->methodSize); - continue; - } - - // Compile this method context as many times as we have been asked to (default is once). - for (int iter = 0; iter < o.repeatCount; iter++) - { - if (jit == nullptr) - { - SimpleTimer stInitJit; - - jit = JitInstance::InitJit(o.nameOfJit, o.breakOnAssert, &stInitJit, mc, o.forceJitOptions, o.jitOptions); - if (jit == nullptr) - { - // InitJit already printed a failure message - return (int)SpmiResult::JitFailedToInit; - } - - if (o.nameOfJit2 != nullptr) - { - jit2 = JitInstance::InitJit(o.nameOfJit2, o.breakOnAssert, &stInitJit, mc, o.forceJit2Options, - o.jit2Options); - if (jit2 == nullptr) - { - // InitJit already printed a failure message - return (int)SpmiResult::JitFailedToInit; - } - - if (jit2->getModule() == jit->getModule()) - { - // The baseline and diff JITs resolved to the same loaded module. Because the JIT keeps - // global state (e.g. g_jitHost, JitConfig), sharing a single module between the two - // JitInstances corrupts that state and produces spurious diffs and intermittent crashes. - // Require the two JITs to be distinct files (copy one to a different path if needed). - LogError("The baseline JIT ('%s') and diff JIT ('%s') resolve to the same loaded module. " - "They must be distinct files; copy one JIT to a different path.", - o.nameOfJit, o.nameOfJit2); - return (int)SpmiResult::JitFailedToInit; - } - } - } - - // For asm diffs, we need to store away the CompileResult generated by the first JIT when compiling - // with the 2nd JIT. - CompileResult* crl = nullptr; - - if (mc->WasEnvironmentChanged(jit->getEnvironment())) - { - if (!jit->resetConfig(mc)) - { - LogError("JIT can't reset environment"); - } - if (o.nameOfJit2 != nullptr) - { - if (!jit2->resetConfig(mc)) - { - LogError("JIT2 can't reset environment"); - } - } - } - - jittedCount++; - st3.Start(); - ReplayResults res = jit->CompileMethod(mc, reader->GetMethodContextIndex(), collectThroughput); - st3.Stop(); - LogDebug("Method %d compiled%s in %fms, result %d", - reader->GetMethodContextIndex(), (o.nameOfJit2 == nullptr) ? "" : " by JIT1", st3.GetMilliseconds(), res); - - if (res.Result == ReplayResult::Success) - { - if (Logger::IsLogLevelEnabled(LOGLEVEL_DEBUG)) - { - mc->cr->dumpToConsole(); // Dump the compile results if doing debug logging - } - } - else if (res.Result == ReplayResult::Error) - { - errorCount++; - LogError("Method %d of size %d failed to load and compile correctly%s (%s).", - reader->GetMethodContextIndex(), mc->methodSize, - (o.nameOfJit2 == nullptr) ? "" : " by JIT1", o.nameOfJit); - if (errorCount == o.failureLimit) - { - LogError("More than %d methods failed%s. Skip compiling remaining methods.", - o.failureLimit, (o.nameOfJit2 == nullptr) ? "" : " by JIT1"); - goto doneRepeatCount; - } - if ((o.reproName != nullptr) && (o.indexCount == -1)) - { - char buff[500]; - sprintf_s(buff, 500, "%s-%d.mc", o.reproName, reader->GetMethodContextIndex()); - HANDLE hFileOut = CreateFileA(buff, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); - if (hFileOut == INVALID_HANDLE_VALUE) - { - LogError("Failed to open output '%s'. GetLastError()=%u", buff, GetLastError()); - return (int)SpmiResult::GeneralFailure; - } - mc->saveToFile(hFileOut); - if (CloseHandle(hFileOut) == 0) - { - LogError("CloseHandle for output file failed. GetLastError()=%u", GetLastError()); - return (int)SpmiResult::GeneralFailure; - } - LogInfo("Wrote out repro to '%s'", buff); - } - if (o.breakOnError) - { - if (o.indexCount == -1) - LogInfo("HINT: to repro add '-c %d' to cmdline", reader->GetMethodContextIndex()); - DEBUG_BREAK; - } - } - - ReplayResults res2; - res2.Result = ReplayResult::Success; - if (o.nameOfJit2 != nullptr) - { - // Lets get the results for the 2nd JIT. - // We will save the first JIT's CR to save space for the 2nd JIT CR - crl = mc->cr; - mc->cr = new CompileResult(); - - st4.Start(); - res2 = jit2->CompileMethod(mc, reader->GetMethodContextIndex(), collectThroughput); - st4.Stop(); - LogDebug("Method %d compiled by JIT2 in %fms, result %d", reader->GetMethodContextIndex(), - st4.GetMilliseconds(), res2); - - if (res2.Result == ReplayResult::Success) - { - if (Logger::IsLogLevelEnabled(LOGLEVEL_DEBUG)) - { - mc->cr->dumpToConsole(); // Dump the compile results if doing debug logging - } - } - else if (res2.Result == ReplayResult::Error) - { - errorCount2++; - LogError("Method %d of size %d failed to load and compile correctly by JIT2 (%s).", - reader->GetMethodContextIndex(), mc->methodSize, o.nameOfJit2); - if (errorCount2 == o.failureLimit) - { - LogError("More than %d methods compilation failed by JIT2. Skip compiling remaining methods.", o.failureLimit); - goto doneRepeatCount; - } - } - } - - if ((res.Result == ReplayResult::Success) && (res2.Result == ReplayResult::Success)) - { - if (collectThroughput) - { - if ((o.nameOfJit2 != nullptr) && (res2.Result == ReplayResult::Success)) - { - // TODO-Bug?: bug in getting the lowest cycle time?? - ULONGLONG dif1, dif2, dif3, dif4; - dif1 = (jit->times[0] - jit2->times[0]) * (jit->times[0] - jit2->times[0]); - dif2 = (jit->times[0] - jit2->times[1]) * (jit->times[0] - jit2->times[1]); - dif3 = (jit->times[1] - jit2->times[0]) * (jit->times[1] - jit2->times[0]); - dif4 = (jit->times[1] - jit2->times[1]) * (jit->times[1] - jit2->times[1]); - - if (dif1 < dif2) - { - if (dif3 < dif4) - { - if (dif1 < dif3) - { - crl->clockCyclesToCompile = jit->times[0]; - mc->cr->clockCyclesToCompile = jit2->times[0]; - } - else - { - crl->clockCyclesToCompile = jit->times[1]; - mc->cr->clockCyclesToCompile = jit2->times[0]; - } - } - else - { - if (dif1 < dif4) - { - crl->clockCyclesToCompile = jit->times[0]; - mc->cr->clockCyclesToCompile = jit2->times[0]; - } - else - { - crl->clockCyclesToCompile = jit->times[1]; - mc->cr->clockCyclesToCompile = jit2->times[1]; - } - } - } - else - { - if (dif3 < dif4) - { - if (dif2 < dif3) - { - crl->clockCyclesToCompile = jit->times[0]; - mc->cr->clockCyclesToCompile = jit2->times[1]; - } - else - { - crl->clockCyclesToCompile = jit->times[1]; - mc->cr->clockCyclesToCompile = jit2->times[0]; - } - } - else - { - if (dif2 < dif4) - { - crl->clockCyclesToCompile = jit->times[0]; - mc->cr->clockCyclesToCompile = jit2->times[1]; - } - else - { - crl->clockCyclesToCompile = jit->times[1]; - mc->cr->clockCyclesToCompile = jit2->times[1]; - } - } - } - - if (methodStatsEmitter != nullptr) - { - methodStatsEmitter->Emit(reader->GetMethodContextIndex(), mc, crl->clockCyclesToCompile, - mc->cr->clockCyclesToCompile); - } - } - else - { - if (jit->times[0] > jit->times[1]) - mc->cr->clockCyclesToCompile = jit->times[1]; - else - mc->cr->clockCyclesToCompile = jit->times[0]; - if (methodStatsEmitter != nullptr) - { - methodStatsEmitter->Emit(reader->GetMethodContextIndex(), mc, mc->cr->clockCyclesToCompile, 0); - } - } - } - - if (!collectThroughput && methodStatsEmitter != nullptr) - { - // We have a separate call to Emit for collectThroughput - methodStatsEmitter->Emit(reader->GetMethodContextIndex(), mc, -1, -1); - } - - if (o.applyDiff) - { - NearDifferResult diffResult = NearDifferResult::Failure; - // We need at least two compile results to diff: they can either both come from JIT - // invocations, or one can be loaded from the method context file. - - // We need to check both CompileResults to ensure we have a valid CR - if (crl->AllocMem == nullptr || mc->cr->AllocMem == nullptr) - { - LogError("method %d is missing a compileResult, cannot do diffing", - reader->GetMethodContextIndex()); - } - else - { - diffResult = InvokeNearDiffer(&nearDiffer, &mc, &crl, &reader); - - switch (diffResult) - { - case NearDifferResult::SuccessWithDiff: - diffsCount++; - // This is a difference in ASM outputs from Jit1 & Jit2 and not a playback failure - // We will add this MC to the details if there is one below. - // Otherwise add it in the failingMCList here. - if (o.details == nullptr) - { - failingToReplayMCL.AddMethodToMCL(reader->GetMethodContextIndex()); - } - - break; - case NearDifferResult::SuccessWithoutDiff: - break; - case NearDifferResult::Failure: - if (o.mclFilename != nullptr) - failingToReplayMCL.AddMethodToMCL(reader->GetMethodContextIndex()); - - break; - } - } - - if (o.details != nullptr) - { - PrintDiffsCsvRow( - detailsCsv, - reader->GetMethodContextIndex(), - mcb.size, - res, res2, - /* hasDiff */ diffResult != NearDifferResult::SuccessWithoutDiff); - } - } - else - { - if (o.details != nullptr) - { - PrintReplayCsvRow( - detailsCsv, - reader->GetMethodContextIndex(), - mcb.size, - res); - } - } - } - else - { - failToReplayCount++; - - // Methods that don't compile due to missing JIT-EE information - // should still be added to the failing MC list but we don't create MC repro for them. - if (o.mclFilename != nullptr) - { - failingToReplayMCL.AddMethodToMCL(reader->GetMethodContextIndex()); - } - - if ((res.Result == ReplayResult::Miss) || (res2.Result == ReplayResult::Miss)) - { - missingCount++; - } - - if (o.details != nullptr) - { - if (o.applyDiff) - { - PrintDiffsCsvRow( - detailsCsv, - reader->GetMethodContextIndex(), mcb.size, - res, res2, - /* hasDiff */ false); - } - else - { - PrintReplayCsvRow(detailsCsv, reader->GetMethodContextIndex(), mcb.size, res); - } - } - } - - // Write a progress message if necessary. - const int progressInterval = 500; - if ((jittedCount > 0) && (jittedCount % progressInterval == 0)) - { - // Note that if progress is measured in terms of bytes of method contexts, instead of a method - // context count, then adding `iter` here will be wildly inaccurate. However, in that case -- - // when we don't have a TOC or index list -- we have no idea how many method contexts are in - // the file nor the "average size" of any single method context. - double currentProgress = progressBeforeCurrentMC + iter; - double percentComplete = 100.0 * currentProgress / totalWork; - - st1.Stop(); - if (o.applyDiff) - { - LogVerbose(" %2.1f%% - Loaded %d Jitted %d Diffs %d FailedCompile %d at %d per second", - percentComplete, loadedCount, jittedCount, diffsCount, - failToReplayCount, (int)((double)progressInterval / st1.GetSeconds())); - } - else - { - LogVerbose(" %2.1f%% - Loaded %d Jitted %d FailedCompile %d at %d per second", - percentComplete, loadedCount, jittedCount, failToReplayCount, - (int)((double)progressInterval / st1.GetSeconds())); - } - st1.Start(); - } - - delete crl; - - if (iter + 1 < o.repeatCount) - { - mc->Reset(); - } - } - - delete mc; - } -doneRepeatCount: - delete reader; - - // NOTE: these output status strings are parsed by parallelsuperpmi.cpp::ProcessChildStdOut(). - if (o.applyDiff) - { - LogInfo(g_AsmDiffsSummaryFormatString, loadedCount, jittedCount, failToReplayCount, excludedCount, - missingCount, diffsCount); - } - else - { - LogInfo(g_SummaryFormatString, loadedCount, jittedCount, failToReplayCount, excludedCount, missingCount); - } - - st2.Stop(); - LogVerbose("Total time: %fms", st2.GetMilliseconds()); - - if (methodStatsEmitter != nullptr) - { - delete methodStatsEmitter; - } - - if (o.mclFilename != nullptr) - { - failingToReplayMCL.CloseMCL(); - } - Logger::Shutdown(); - - SpmiResult result = SpmiResult::Success; - - if ((errorCount > 0) || (errorCount2 > 0)) - { - result = SpmiResult::Error; - } - else if (o.applyDiff && (diffsCount > 0)) - { - result = SpmiResult::Diffs; - } - else if (missingCount > 0) - { - result = SpmiResult::Misses; - } - - return (int)result; -} diff --git a/src/coreclr/tools/superpmi/superpmi/superpmi.h b/src/coreclr/tools/superpmi/superpmi/superpmi.h deleted file mode 100644 index 190b8d5d9ec091..00000000000000 --- a/src/coreclr/tools/superpmi/superpmi/superpmi.h +++ /dev/null @@ -1,27 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#ifndef _SuperPMI -#define _SuperPMI - -#include "errorhandling.h" - -extern const char* const g_SuperPMIUsageFirstLine; - -extern const char* const g_AllFormatStringFixedPrefix; -extern const char* const g_SummaryFormatString; -extern const char* const g_AsmDiffsSummaryFormatString; - -enum class SpmiResult -{ - JitFailedToInit = -2, - GeneralFailure = -1, - Success = 0, - Error = 1, - Diffs = 2, - Misses = 3 -}; - -extern void SetSuperPmiTargetArchitecture(const char* targetArchitecture); - -#endif diff --git a/src/tests/Common/CoreRootArtifacts.targets b/src/tests/Common/CoreRootArtifacts.targets index f4ae0e322d8015..28bacf4ef1048e 100644 --- a/src/tests/Common/CoreRootArtifacts.targets +++ b/src/tests/Common/CoreRootArtifacts.targets @@ -29,7 +29,6 @@ - From 42bac13f3d397d4539622396a483b1cee1ae1819 Mon Sep 17 00:00:00 2001 From: am11 <3840695+am11@users.noreply.github.com> Date: Thu, 5 Nov 2026 01:24:54 +0200 Subject: [PATCH 02/10] CI fixes --- eng/Subsets.props | 3 +- .../superpmi/jitinterface/CMakeLists.txt | 30 +++---------------- .../superpmi/jitinterface/jitinterface.cpp | 2 +- .../tools/superpmi/jitinterface/shim.cpp | 21 ++----------- .../tools/superpmi/managed/mcs/mcs.csproj | 5 ++-- .../superpmi/managed/superpmi-tools.proj | 4 --- .../superpmi/managed/superpmi/superpmi.csproj | 21 +++++++------ src/coreclr/tools/superpmi/readme.md | 11 ++++--- 8 files changed, 25 insertions(+), 72 deletions(-) diff --git a/eng/Subsets.props b/eng/Subsets.props index 097407e7fa6db7..fb8c0de8817ac5 100644 --- a/eng/Subsets.props +++ b/eng/Subsets.props @@ -383,8 +383,7 @@ Category="clr" /> - - + diff --git a/src/coreclr/tools/superpmi/jitinterface/CMakeLists.txt b/src/coreclr/tools/superpmi/jitinterface/CMakeLists.txt index 3d661abf1b98ae..84a81b5ef08ca1 100644 --- a/src/coreclr/tools/superpmi/jitinterface/CMakeLists.txt +++ b/src/coreclr/tools/superpmi/jitinterface/CMakeLists.txt @@ -3,36 +3,14 @@ project(superpmi-jitinterface) # The JIT-EE interface wrapper and the JIT host are shared with crossgen2's jitinterface library. include_directories(../../aot/jitinterface) -set(SUPERPMI_JITINTERFACE_SOURCES +# Linked into superpmi (a NativeAOT executable). +add_library_clr(superpmi-jitinterface + STATIC jitinterface.cpp threadtime.cpp ../../aot/jitinterface/jithost.cpp ) -# Loaded by superpmi when it is published as a single-file app, which gets a copy of it next to it. -add_library_clr(superpmi-jitinterface - SHARED - ${SUPERPMI_JITINTERFACE_SOURCES} -) - -if (CLR_CMAKE_HOST_WIN32) - target_link_libraries(superpmi-jitinterface - PRIVATE - ${STATIC_MT_CRT_LIB} - ${STATIC_MT_VCRT_LIB} - ${STATIC_MT_CPP_LIB} - kernel32.lib - ) -endif() - -install_clr(TARGETS superpmi-jitinterface DESTINATIONS superpmi-lib COMPONENT spmi) - -# Linked into superpmi when it is published with NativeAOT. -add_library_clr(superpmi-jitinterface-static - STATIC - ${SUPERPMI_JITINTERFACE_SOURCES} -) - # Linked into the managed shims (NativeAOT shared libraries), which the runtime loads as its JIT. add_library_clr(superpmi-shim-jitinterface STATIC @@ -44,7 +22,7 @@ if (MSVC) target_compile_options(superpmi-shim-jitinterface PRIVATE /EHa) endif() -foreach(target superpmi-jitinterface-static superpmi-shim-jitinterface) +foreach(target superpmi-jitinterface superpmi-shim-jitinterface) set_target_properties(${target} PROPERTIES POSITION_INDEPENDENT_CODE ON) if (MSVC) diff --git a/src/coreclr/tools/superpmi/jitinterface/jitinterface.cpp b/src/coreclr/tools/superpmi/jitinterface/jitinterface.cpp index 021e75e3ebe13e..94cd3a887f9372 100644 --- a/src/coreclr/tools/superpmi/jitinterface/jitinterface.cpp +++ b/src/coreclr/tools/superpmi/jitinterface/jitinterface.cpp @@ -209,7 +209,7 @@ DLL_EXPORT const PrintControl* GetCoreDisToolsPrinters(LogCallback callback) return &s_printControl; } -DLL_EXPORT volatile uint64_t s_globalZero = 0; +static volatile uint64_t s_globalZero = 0; // A dynamic instrumentor can rewrite this function to provide the precise instruction counts that SuperPMI // reports in its metrics. The volatile read tells the compiler that something might actually happen here. diff --git a/src/coreclr/tools/superpmi/jitinterface/shim.cpp b/src/coreclr/tools/superpmi/jitinterface/shim.cpp index a1fc88e8f77115..92803f5a0adf59 100644 --- a/src/coreclr/tools/superpmi/jitinterface/shim.cpp +++ b/src/coreclr/tools/superpmi/jitinterface/shim.cpp @@ -14,8 +14,6 @@ #ifdef _MSC_VER #include -#else -#include #endif #include "jitinterface_generated.h" @@ -53,22 +51,10 @@ static void RunWithCodeFilter(F& function, uint32_t* code) { } } -#else -// The code of the current exception if the PAL threw it (PAL_SEHException, whose first field points to the -// EXCEPTION_RECORD), and otherwise 1, the code that is recorded for the other exceptions. -static uint32_t GetCurrentExceptionCode() -{ - const std::type_info* type = abi::__cxa_current_exception_type(); - if (type == nullptr || strcmp(type->name(), "16PAL_SEHException") != 0) - return 1; - - std::exception_ptr exception = std::current_exception(); - void* object = *reinterpret_cast(&exception); - return **reinterpret_cast(object); -} #endif -// Runs the function, and returns what it throws in *ppException instead. +// Runs the function, and returns what it throws in *ppException instead. Elsewhere than on Windows, the code of a C++ +// exception isn't known, so it is recorded as 1. template static void RunCapturingException(CorInfoExceptionClass** ppException, F function) { @@ -88,9 +74,6 @@ static void RunCapturingException(CorInfoExceptionClass** ppException, F functio } catch (...) { -#ifndef _MSC_VER - code = GetCurrentExceptionCode(); -#endif *ppException = new CapturedException(std::current_exception(), code); } } diff --git a/src/coreclr/tools/superpmi/managed/mcs/mcs.csproj b/src/coreclr/tools/superpmi/managed/mcs/mcs.csproj index ec94a19efc130b..638c023ea6d0cd 100644 --- a/src/coreclr/tools/superpmi/managed/mcs/mcs.csproj +++ b/src/coreclr/tools/superpmi/managed/mcs/mcs.csproj @@ -4,10 +4,9 @@ Exe true - - true + + true true - true $(PortableOS)-$(TargetArchitecture) $(RuntimeBinDir) diff --git a/src/coreclr/tools/superpmi/managed/superpmi-tools.proj b/src/coreclr/tools/superpmi/managed/superpmi-tools.proj index eff903025add18..4e533f1f969070 100644 --- a/src/coreclr/tools/superpmi/managed/superpmi-tools.proj +++ b/src/coreclr/tools/superpmi/managed/superpmi-tools.proj @@ -3,10 +3,6 @@ - - - - diff --git a/src/coreclr/tools/superpmi/managed/superpmi/superpmi.csproj b/src/coreclr/tools/superpmi/managed/superpmi/superpmi.csproj index 017fed9cb18769..57b69cebef4c87 100644 --- a/src/coreclr/tools/superpmi/managed/superpmi/superpmi.csproj +++ b/src/coreclr/tools/superpmi/managed/superpmi/superpmi.csproj @@ -4,14 +4,15 @@ Exe true - - true + + true true - true $(PortableOS)-$(TargetArchitecture) $(RuntimeBinDir) true + + false @@ -20,16 +21,14 @@ - - + - + - - + + + diff --git a/src/coreclr/tools/superpmi/readme.md b/src/coreclr/tools/superpmi/readme.md index b1b20c6edafc3a..263e55f0f6fa38 100644 --- a/src/coreclr/tools/superpmi/readme.md +++ b/src/coreclr/tools/superpmi/readme.md @@ -54,17 +54,16 @@ library (`.dll` or `.so` or `.dylib`), which the runtime loads as its JIT; the ` and `superpmi-shim-simple` libraries work the same way, to count the JIT-EE interface calls and to measure the cost of the shims. -All of them are written in C# (in `managed`), and published with NativeAOT next to the JIT: +All of them are written in C# (in `managed`), and published with NativeAOT next to the JIT, on the +platforms that NativeAOT supports: * `managed/SuperPmi.Shared`: the method context format, and the recording (`rec*`), replaying (`rep*`) and dumping (`dmp*`) of the JIT-EE interface calls. -* `managed/superpmi`, `managed/mcs`: the executable tools. Without NativeAOT for the platform, they are - single-file apps. -* `managed/superpmi-shim-*`, with the code they share in `managed/shim`: the shims, which need NativeAOT. +* `managed/superpmi`, `managed/mcs`: the executable tools. +* `managed/superpmi-shim-*`, with the code they share in `managed/shim`: the shims. * `jitinterface`: the native code they need, to call the JIT and the runtime through their C++ interfaces. Most of it is generated with the JIT interface (`src/coreclr/tools/Common/JitInterface/ThunkGenerator`). - It is built as static libraries in `superpmi-lib`, which NativeAOT links into the tools; a single-file - `superpmi` gets a copy of the `superpmi-jitinterface` shared library next to it instead. + It is built as static libraries in `superpmi-lib`, which NativeAOT links into the tools. To harness collection, there is a .NET Core C# program that is built as part of the coreclr tests build called superpmicollect.exe From cad5aacee3329b2fd2a3b9888545d56aa142ec41 Mon Sep 17 00:00:00 2001 From: Adeel Mujahid <3840695+am11@users.noreply.github.com> Date: Thu, 5 Nov 2026 03:38:50 +0200 Subject: [PATCH 03/10] Add dummy comment in compiler.h for CI testing --- src/coreclr/jit/compiler.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 212d10c3ab2e72..3e861ab50788f5 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.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. +// Dummy change to excercise in CI + /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XX XX From 4db2623c4d1a2e75a3e4796bbe0ce92813ee6636 Mon Sep 17 00:00:00 2001 From: am11 <3840695+am11@users.noreply.github.com> Date: Thu, 5 Nov 2026 12:26:05 +0200 Subject: [PATCH 04/10] . --- eng/Subsets.props | 8 ++++---- src/coreclr/tools/superpmi/managed/Directory.Build.props | 1 + .../tools/superpmi/managed/Directory.Build.targets | 4 ++++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/eng/Subsets.props b/eng/Subsets.props index fb8c0de8817ac5..5611dcb06ee624 100644 --- a/eng/Subsets.props +++ b/eng/Subsets.props @@ -383,10 +383,6 @@ Category="clr" /> - - - - false + true diff --git a/src/coreclr/tools/superpmi/managed/Directory.Build.targets b/src/coreclr/tools/superpmi/managed/Directory.Build.targets index 78778798a937f9..75f920c42b0b88 100644 --- a/src/coreclr/tools/superpmi/managed/Directory.Build.targets +++ b/src/coreclr/tools/superpmi/managed/Directory.Build.targets @@ -1,5 +1,9 @@ + + true + + Date: Thu, 5 Nov 2026 17:35:58 +0200 Subject: [PATCH 05/10] Disable concurrent GC in superpmi for PIN runs --- src/coreclr/tools/superpmi/managed/superpmi/superpmi.csproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/coreclr/tools/superpmi/managed/superpmi/superpmi.csproj b/src/coreclr/tools/superpmi/managed/superpmi/superpmi.csproj index 57b69cebef4c87..4e13970eece479 100644 --- a/src/coreclr/tools/superpmi/managed/superpmi/superpmi.csproj +++ b/src/coreclr/tools/superpmi/managed/superpmi/superpmi.csproj @@ -13,6 +13,8 @@ true false + + false From d5e6cb11f644d4be6d380697cd93a22773d498b8 Mon Sep 17 00:00:00 2001 From: am11 <3840695+am11@users.noreply.github.com> Date: Mon, 9 Nov 2026 11:48:49 +0200 Subject: [PATCH 06/10] Get the JIT metrics from the native side of superpmi instead of parsing jitmetadatalist.h Co-authored-by: Cursor --- .../superpmi/jitinterface/jitinterface.cpp | 37 +++++++++++++++++++ .../managed/SuperPmi.Shared/JitMetrics.cs | 37 +++---------------- .../SuperPmi.Shared/SuperPmi.Shared.csproj | 1 - .../superpmi/managed/superpmi/Program.cs | 2 + .../managed/superpmi/SpmiJitInterface.cs | 19 ++++++++++ 5 files changed, 64 insertions(+), 32 deletions(-) diff --git a/src/coreclr/tools/superpmi/jitinterface/jitinterface.cpp b/src/coreclr/tools/superpmi/jitinterface/jitinterface.cpp index 94cd3a887f9372..898cf2c5e40e23 100644 --- a/src/coreclr/tools/superpmi/jitinterface/jitinterface.cpp +++ b/src/coreclr/tools/superpmi/jitinterface/jitinterface.cpp @@ -209,6 +209,43 @@ DLL_EXPORT const PrintControl* GetCoreDisToolsPrinters(LogCallback callback) return &s_printControl; } +// The types of the metrics that the JIT reports through reportMetadata. Matches JitMetrics.MetricType. +enum JitMetricType +{ + JitMetricInt, + JitMetricInt64, + JitMetricDouble, +}; + +template struct JitMetricTypeOf; +template <> struct JitMetricTypeOf { static const JitMetricType value = JitMetricInt; }; +template <> struct JitMetricTypeOf { static const JitMetricType value = JitMetricInt64; }; +template <> struct JitMetricTypeOf { static const JitMetricType value = JitMetricDouble; }; + +struct JitMetricInfo +{ + const char* name; + JitMetricType type; +}; + +static const JitMetricInfo s_jitMetrics[] = { +#define JITMETADATAINFO(name, type, flags) +#define JITMETADATAMETRIC(name, type, flags) {#name, JitMetricTypeOf::value}, +#include "../../../jit/jitmetadatalist.h" +}; + +DLL_EXPORT int GetJitMetricCount() +{ + return sizeof(s_jitMetrics) / sizeof(s_jitMetrics[0]); +} + +// The metrics are in the order that the JIT reports them. +DLL_EXPORT const char* GetJitMetric(int index, JitMetricType* type) +{ + *type = s_jitMetrics[index].type; + return s_jitMetrics[index].name; +} + static volatile uint64_t s_globalZero = 0; // A dynamic instrumentor can rewrite this function to provide the precise instruction counts that SuperPMI diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/JitMetrics.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/JitMetrics.cs index 3aa379dc2b0ec5..3490a9621b1e4f 100644 --- a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/JitMetrics.cs +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/JitMetrics.cs @@ -2,17 +2,15 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections.Generic; using System.Globalization; -using System.IO; -using System.Text; namespace SuperPmi; -// The metrics that the JIT reports through reportMetadata, as listed by src/coreclr/jit/jitmetadatalist.h -// (embedded as a resource, so new metrics don't need changes here). +// The metrics that the JIT reports through reportMetadata, as listed by src/coreclr/jit/jitmetadatalist.h. The +// replay host gets them from its native side, which is compiled with that list; the other tools have none. public sealed unsafe class JitMetrics { + // Matches JitMetricType in src/coreclr/tools/superpmi/jitinterface/jitinterface.cpp. public enum MetricType { Int, @@ -22,36 +20,13 @@ public enum MetricType public readonly record struct Metric(string Name, byte[] Utf8Name, MetricType Type); - public static readonly Metric[] All = Load(); + public static Metric[] All { get; private set; } = []; // Doubles are stored as their bits. private readonly long[] _values = new long[All.Length]; - private static Metric[] Load() - { - using Stream stream = typeof(JitMetrics).Assembly.GetManifestResourceStream("jitmetadatalist.h"); - using var reader = new StreamReader(stream); - - const string Prefix = "JITMETADATAMETRIC("; - var metrics = new List(); - while (reader.ReadLine() is string line) - { - if (!line.StartsWith(Prefix, StringComparison.Ordinal)) - continue; - - string[] parts = line.Substring(Prefix.Length).Split(','); - string name = parts[0].Trim(); - MetricType type = parts[1].Trim() switch - { - "int" => MetricType.Int, - "int64_t" => MetricType.Int64, - "double" => MetricType.Double, - string other => throw new InvalidDataException($"Unknown JIT metric type '{other}' for {name}"), - }; - metrics.Add(new Metric(name, Encoding.UTF8.GetBytes(name), type)); - } - return metrics.ToArray(); - } + // Called before any compile results are created. + public static void Initialize(Metric[] metrics) => All = metrics; // The JIT reports metrics in the order they're listed, so the search resumes where the previous one // matched; in practice this matches on the first comparison. diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/SuperPmi.Shared.csproj b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/SuperPmi.Shared.csproj index e38c98e9a204d3..6a26b6e8391bd8 100644 --- a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/SuperPmi.Shared.csproj +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/SuperPmi.Shared.csproj @@ -10,7 +10,6 @@ - diff --git a/src/coreclr/tools/superpmi/managed/superpmi/Program.cs b/src/coreclr/tools/superpmi/managed/superpmi/Program.cs index e63bf77ebdb869..a38ea982305403 100644 --- a/src/coreclr/tools/superpmi/managed/superpmi/Program.cs +++ b/src/coreclr/tools/superpmi/managed/superpmi/Program.cs @@ -21,6 +21,8 @@ private static int Main(string[] args) { try { + JitMetrics.Initialize(SpmiJitInterface.GetJitMetrics()); + // As in C's argv, the first argument is the program as invoked. return Replay.Run([Environment.GetCommandLineArgs()[0], .. args]); } diff --git a/src/coreclr/tools/superpmi/managed/superpmi/SpmiJitInterface.cs b/src/coreclr/tools/superpmi/managed/superpmi/SpmiJitInterface.cs index 929791c7b1e876..be9406abbc77e3 100644 --- a/src/coreclr/tools/superpmi/managed/superpmi/SpmiJitInterface.cs +++ b/src/coreclr/tools/superpmi/managed/superpmi/SpmiJitInterface.cs @@ -3,6 +3,7 @@ using System; using System.Runtime.InteropServices; +using System.Text; using Internal.JitInterface; namespace SuperPmi.Replay; @@ -48,6 +49,24 @@ public static partial CorJitResult JitCompileMethod(IntPtr* ppException, uint* p // The level is 0 for errors, 1 for warnings, and 2 for everything else. [LibraryImport(Library)] public static partial IntPtr GetCoreDisToolsPrinters(delegate* unmanaged callback); + + [LibraryImport(Library)] + private static partial int GetJitMetricCount(); + + [LibraryImport(Library)] + private static partial byte* GetJitMetric(int index, JitMetrics.MetricType* type); + + public static JitMetrics.Metric[] GetJitMetrics() + { + var metrics = new JitMetrics.Metric[GetJitMetricCount()]; + for (int i = 0; i < metrics.Length; i++) + { + JitMetrics.MetricType type; + ReadOnlySpan name = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(GetJitMetric(i, &type)); + metrics[i] = new JitMetrics.Metric(Encoding.UTF8.GetString(name), name.ToArray(), type); + } + return metrics; + } } // Measures the CPU time of the current thread, less the overhead of measuring it. From e7713de10bd1ce9a7914fe59dcb6cd17ec5cada8 Mon Sep 17 00:00:00 2001 From: am11 <3840695+am11@users.noreply.github.com> Date: Mon, 9 Nov 2026 12:04:55 +0200 Subject: [PATCH 07/10] Replace the printf emulation in the SuperPMI tools with C# formatting Co-authored-by: Cursor --- .../managed/SuperPmi.Shared/CFormat.cs | 306 -------- .../SuperPmi.Shared/CompileResult.Dump.cs | 80 +-- .../SuperPmi.Shared/CompileResult.Replay.cs | 26 +- .../SuperPmi.Shared/MethodContext.Dump.cs | 673 ++++++++---------- .../SuperPmi.Shared/MethodContext.Replay.cs | 113 +-- .../managed/SuperPmi.Shared/SpmiDumpHelper.cs | 34 +- .../tools/superpmi/managed/mcs/ILDumper.cs | 10 +- .../tools/superpmi/managed/mcs/VerbDump.cs | 5 +- .../tools/superpmi/managed/mcs/VerbILDump.cs | 9 +- .../superpmi/managed/superpmi/JitInstance.cs | 2 +- .../superpmi/managed/superpmi/NearDiffer.cs | 12 +- .../tools/superpmi/managed/superpmi/Output.cs | 2 - .../managed/superpmi/ParallelReplay.cs | 6 +- .../tools/superpmi/managed/superpmi/Replay.cs | 38 +- 14 files changed, 474 insertions(+), 842 deletions(-) delete mode 100644 src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CFormat.cs diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CFormat.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CFormat.cs deleted file mode 100644 index dbc7fb8e79d819..00000000000000 --- a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CFormat.cs +++ /dev/null @@ -1,306 +0,0 @@ -// 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.Globalization; -using System.IO; -using System.Text; - -namespace SuperPmi; - -// C printf-style formatting, in which the output formats of the tools are defined. -// Integer arguments are converted to the width given by the length modifier, as a C variadic call would. -public static class CFormat -{ - public static void Printf(TextWriter writer, string format, params object[] args) => writer.Write(Sprintf(format, args)); - - public static string Sprintf(string format, params object[] args) - { - var sb = new StringBuilder(format.Length + 16); - int argIndex = 0; - int i = 0; - while (i < format.Length) - { - char c = format[i++]; - if (c != '%') - { - sb.Append(c); - continue; - } - - if (i < format.Length && format[i] == '%') - { - sb.Append('%'); - i++; - continue; - } - - bool leftAlign = false, zeroPad = false, plus = false, space = false, alternate = false; - for (; i < format.Length; i++) - { - switch (format[i]) - { - case '-': leftAlign = true; continue; - case '0': zeroPad = true; continue; - case '+': plus = true; continue; - case ' ': space = true; continue; - case '#': alternate = true; continue; - } - break; - } - - int width = -1; - if (i < format.Length && format[i] == '*') - { - width = Convert.ToInt32(args[argIndex++], CultureInfo.InvariantCulture); - if (width < 0) - { - leftAlign = true; - width = -width; - } - i++; - } - else - { - width = ParseNumber(format, ref i, -1); - } - - int precision = -1; - if (i < format.Length && format[i] == '.') - { - i++; - if (i < format.Length && format[i] == '*') - { - precision = Convert.ToInt32(args[argIndex++], CultureInfo.InvariantCulture); - i++; - } - else - { - precision = ParseNumber(format, ref i, 0); - } - } - - int bits = 32; - if (Match(format, ref i, "hh")) bits = 8; - else if (Match(format, ref i, "h")) bits = 16; - else if (Match(format, ref i, "ll") || Match(format, ref i, "I64") || Match(format, ref i, "l") || - Match(format, ref i, "j") || Match(format, ref i, "z") || Match(format, ref i, "t") || Match(format, ref i, "q")) bits = 64; - else if (Match(format, ref i, "I32")) bits = 32; - else if (Match(format, ref i, "L")) bits = 64; - - char conversion = format[i++]; - object arg = conversion == 'n' ? null : args[argIndex++]; - - string body; - string prefix = ""; - bool numeric = true; - switch (conversion) - { - case 'd': - case 'i': - { - long value = ToSigned(arg, bits); - body = FormatDigits((ulong)Math.Abs((decimal)value), 10, false, precision); - prefix = value < 0 ? "-" : plus ? "+" : space ? " " : ""; - break; - } - case 'u': - body = FormatDigits(ToUnsigned(arg, bits), 10, false, precision); - break; - case 'x': - case 'X': - { - ulong value = ToUnsigned(arg, bits); - body = FormatDigits(value, 16, conversion == 'X', precision); - if (alternate && value != 0) - prefix = conversion == 'X' ? "0X" : "0x"; - break; - } - case 'o': - { - ulong value = ToUnsigned(arg, bits); - body = FormatDigits(value, 8, false, precision); - if (alternate && !body.StartsWith('0')) - body = "0" + body; - break; - } - case 'c': - body = ((char)(byte)ToUnsigned(arg, 8)).ToString(); - numeric = false; - break; - case 's': - body = arg switch - { - null => "(null)", - byte[] bytes => Encoding.UTF8.GetString(bytes), - _ => arg.ToString(), - }; - if (precision >= 0 && body.Length > precision) - body = body.Substring(0, precision); - numeric = false; - break; - case 'p': - body = "0x" + ToUnsigned(arg, 64).ToString("x", CultureInfo.InvariantCulture); - numeric = false; - break; - case 'f': - case 'F': - case 'e': - case 'E': - case 'g': - case 'G': - { - double value = Convert.ToDouble(arg, CultureInfo.InvariantCulture); - body = FormatDouble(Math.Abs(value), conversion, precision < 0 ? 6 : precision, alternate); - prefix = (value < 0 || (value == 0 && double.IsNegative(value))) ? "-" : plus ? "+" : space ? " " : ""; - if (double.IsNaN(value) || double.IsInfinity(value)) - zeroPad = false; - break; - } - default: - throw new FormatException($"Unsupported printf conversion '%{conversion}' in \"{format}\""); - } - - // With a precision, '0' padding doesn't apply to integers. - if (precision >= 0 && conversion is 'd' or 'i' or 'u' or 'x' or 'X' or 'o') - zeroPad = false; - - int length = prefix.Length + body.Length; - if (width <= length) - { - sb.Append(prefix).Append(body); - } - else if (leftAlign) - { - sb.Append(prefix).Append(body).Append(' ', width - length); - } - else if (zeroPad && numeric) - { - sb.Append(prefix).Append('0', width - length).Append(body); - } - else - { - sb.Append(' ', width - length).Append(prefix).Append(body); - } - } - - return sb.ToString(); - } - - private static int ParseNumber(string format, ref int i, int defaultValue) - { - int start = i; - int value = 0; - while (i < format.Length && char.IsAsciiDigit(format[i])) - value = value * 10 + (format[i++] - '0'); - return i == start ? defaultValue : value; - } - - private static bool Match(string format, ref int i, string text) - { - if (string.CompareOrdinal(format, i, text, 0, text.Length) != 0) - return false; - i += text.Length; - return true; - } - - private static ulong RawBits(object arg) => arg switch - { - sbyte v => (ulong)(long)v, - short v => (ulong)(long)v, - int v => (ulong)(long)v, - long v => (ulong)v, - nint v => (ulong)(long)v, - byte v => v, - ushort v => v, - char v => v, - uint v => v, - ulong v => v, - nuint v => (ulong)v, - bool v => v ? 1UL : 0UL, - Enum e => RawBits(Convert.ChangeType(e, Enum.GetUnderlyingType(e.GetType()), CultureInfo.InvariantCulture)), - _ => throw new FormatException($"Unsupported printf integer argument type {arg?.GetType()}"), - }; - - private static ulong ToUnsigned(object arg, int bits) - { - ulong raw = RawBits(arg); - return bits == 64 ? raw : raw & ((1UL << bits) - 1); - } - - private static long ToSigned(object arg, int bits) - { - ulong raw = RawBits(arg); - return bits switch - { - 8 => (sbyte)raw, - 16 => (short)raw, - 32 => (int)raw, - _ => (long)raw, - }; - } - - private static string FormatDigits(ulong value, int radix, bool upper, int precision) - { - string digits = radix switch - { - 10 => value.ToString(CultureInfo.InvariantCulture), - 16 => value.ToString(upper ? "X" : "x", CultureInfo.InvariantCulture), - _ => Convert.ToString((long)value, 8), - }; - if (precision == 0 && value == 0) - return ""; - return precision > digits.Length ? new string('0', precision - digits.Length) + digits : digits; - } - - private static string FormatDouble(double value, char conversion, int precision, bool alternate) - { - bool upper = char.IsUpper(conversion); - if (double.IsNaN(value)) - return upper ? "NAN" : "nan"; - if (double.IsInfinity(value)) - return upper ? "INF" : "inf"; - - switch (char.ToLowerInvariant(conversion)) - { - case 'f': - return value.ToString("F" + precision, CultureInfo.InvariantCulture); - case 'e': - return FormatExponent(value, precision, upper); - default: - { - // %g: %e if the exponent is < -4 or >= the precision, else %f; trailing zeros removed. - int p = precision == 0 ? 1 : precision; - int exponent = value == 0 ? 0 : (int)Math.Floor(Math.Log10(value)); - string rounded = value.ToString("E" + (p - 1), CultureInfo.InvariantCulture); - exponent = int.Parse(rounded.Substring(rounded.IndexOf('E') + 1), CultureInfo.InvariantCulture); - string result = (exponent < -4 || exponent >= p) - ? FormatExponent(value, p - 1, upper) - : value.ToString("F" + (p - 1 - exponent), CultureInfo.InvariantCulture); - if (!alternate) - result = StripTrailingZeros(result); - return result; - } - } - } - - // C uses at least two exponent digits; .NET uses three. - private static string FormatExponent(double value, int precision, bool upper) - { - string s = value.ToString((upper ? "E" : "e") + precision, CultureInfo.InvariantCulture); - int e = s.IndexOfAny(['e', 'E']); - string mantissa = s.Substring(0, e); - int exponent = int.Parse(s.Substring(e + 1), CultureInfo.InvariantCulture); - return $"{mantissa}{s[e]}{(exponent < 0 ? '-' : '+')}{Math.Abs(exponent):00}"; - } - - private static string StripTrailingZeros(string s) - { - int e = s.IndexOfAny(['e', 'E']); - string mantissa = e >= 0 ? s.Substring(0, e) : s; - string exponent = e >= 0 ? s.Substring(e) : ""; - if (mantissa.Contains('.')) - mantissa = mantissa.TrimEnd('0').TrimEnd('.'); - return mantissa + exponent; - } -} diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CompileResult.Dump.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CompileResult.Dump.cs index 72ee1d75412720..dd4511fee3fde4 100644 --- a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CompileResult.Dump.cs +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CompileResult.Dump.cs @@ -18,13 +18,13 @@ public sealed partial class CompileResult public void dmpAssertLog(uint key, uint value) { - CFormat.Printf(Out, "AssertLog key %u, value '%s'", key, AssertLog.GetString(value)); + Out.Write($"AssertLog key {key}, value '{AssertLog.GetString(value) ?? "(null)"}'"); AssertLog.Unlock(); } public void dmpCallLog(uint key, uint value) { - CFormat.Printf(Out, "CallLog %u '%s'", key, CallLog.GetString(value)); + Out.Write($"CallLog {key} '{CallLog.GetString(value) ?? "(null)"}'"); CallLog.Unlock(); } @@ -32,13 +32,13 @@ public void dmpSetBoundaries(uint key, in Agnostic_SetBoundaries value) { const int OffsetMappingSize = 12; // ICorDebugInfo::OffsetMapping: nativeOffset, ilOffset, source ReadOnlySpan om = SetBoundaries.GetBuffer(value.pMap_offset); - CFormat.Printf(Out, "SetBoundaries key 0, value ftn-%016llX cMap-%u %u{", value.ftn, value.cMap, value.pMap_offset); + Out.Write($"SetBoundaries key 0, value ftn-{value.ftn:X16} cMap-{value.cMap} {value.pMap_offset}{{"); for (uint i = 0; i < value.cMap; i++) { if (i != 0) Out.Write(", "); int at = (int)i * OffsetMappingSize; - CFormat.Printf(Out, "%u %u %u", U32(om, at + 4), U32(om, at), U32(om, at + 8)); + Out.Write($"{U32(om, at + 4)} {U32(om, at)} {U32(om, at + 8)}"); } Out.Write("}"); SetBoundaries.Unlock(); @@ -49,13 +49,13 @@ public void dmpSetVars(uint key, in Agnostic_SetVars value) // ICorDebugInfo::NativeVarInfo: startOffset, endOffset, callReturnValueILOffset, varNumber, then a 16-byte VarLoc. const int NativeVarInfoSize = 32; ReadOnlySpan om = SetVars.GetBuffer(value.vars_offset); - CFormat.Printf(Out, "SetVars key %u, value ftn-%016llX cVars-%u %u{", key, value.ftn, value.cVars, value.vars_offset); + Out.Write($"SetVars key {key}, value ftn-{value.ftn:X16} cVars-{value.cVars} {value.vars_offset}{{"); for (uint i = 0; i < value.cVars; i++) { if (i != 0) Out.Write(", "); int at = (int)i * NativeVarInfoSize; - CFormat.Printf(Out, "so-%u eo-%u var-%u", U32(om, at), U32(om, at + 4), U32(om, at + 12)); + Out.Write($"so-{U32(om, at)} eo-{U32(om, at + 4)} var-{U32(om, at + 12)}"); } Out.Write("}"); SetVars.Unlock(); @@ -64,7 +64,7 @@ public void dmpSetVars(uint key, in Agnostic_SetVars value) public void dmpSetPatchpointInfo(uint key, in Agnostic_SetPatchpointInfo value) { SetPatchpointInfo.GetBuffer(value.index); - CFormat.Printf(Out, "SetPatchpointInfo key %u, index %u{", key, value.index); + Out.Write($"SetPatchpointInfo key {key}, index {value.index}{{"); Out.Write("}"); SetPatchpointInfo.Unlock(); } @@ -74,95 +74,91 @@ public void dmpAllocGCInfo(uint key, in Agnostic_AllocGCInfo value) { ReadOnlySpan buff = AllocGCInfo.GetBuffer(value.retval_offset); Out.Write("AllocGCInfo key 0, "); - CFormat.Printf(Out, "sz-%llu %s{ ", value.size, value.retval_offset == uint.MaxValue ? "(nil)" : CFormat.Sprintf("0x%x", value.retval_offset)); + Out.Write($"sz-{value.size} {(value.retval_offset == uint.MaxValue ? "(nil)" : $"0x{value.retval_offset:x}")}{{ "); for (ulong i = 0; i < value.size; i++) - CFormat.Printf(Out, "%02X ", buff[(int)i]); + Out.Write($"{buff[(int)i]:X2} "); Out.Write("}"); AllocGCInfo.Unlock(); } public void dmpReportInliningDecision(uint key, in Agnostic_ReportInliningDecision value) { - CFormat.Printf(Out, "ReportInliningDecision key %u, value inliner-%016llX inlinee-%016llX res-%u reason-'%s'", key, - value.inlinerHnd, value.inlineeHnd, value.inlineResult, ReportInliningDecision.GetString(value.reason_offset)); + Out.Write($"ReportInliningDecision key {key}, value inliner-{value.inlinerHnd:X16} inlinee-{value.inlineeHnd:X16} " + + $"res-{value.inlineResult} reason-'{ReportInliningDecision.GetString(value.reason_offset) ?? "(null)"}'"); ReportInliningDecision.Unlock(); } public void dmpReportTailCallDecision(uint key, in Agnostic_ReportTailCallDecision value) { - CFormat.Printf(Out, "ReportTailCallDecision key-%u, value cr-%016llX ce-%016llX tail-%u call-%u -%s", key, value.callerHnd, - value.calleeHnd, value.tailCallResult, value.tailCallResult, ReportTailCallDecision.GetString(value.reason_index)); + Out.Write($"ReportTailCallDecision key-{key}, value cr-{value.callerHnd:X16} ce-{value.calleeHnd:X16} tail-{value.tailCallResult} " + + $"call-{value.tailCallResult} -{ReportTailCallDecision.GetString(value.reason_index) ?? "(null)"}"); ReportTailCallDecision.Unlock(); } public void dmpProcessName(uint key, uint value) { - CFormat.Printf(Out, "ProcessName key %u, value '%s'", key, ProcessName.GetString(value)); + Out.Write($"ProcessName key {key}, value '{ProcessName.GetString(value) ?? "(null)"}'"); ProcessName.Unlock(); } public void dmpAllocMem(uint key, in Agnostic_AllocMemDetails value) - => CFormat.Printf(Out, "AllocMem key 0, value hotCodeSize-%u coldCodeSize-%u roDataSize-%u xcptnsCount-%u hotCodeBlock_offset-%u coldCodeBlock_offset-%u roDataBlock_offset-%u hotCodeBlock-%016llX coldCodeBlock-%016llX roDataBlock-%016llX", - value.hotCodeSize, value.coldCodeSize, value.roDataSize, value.xcptnsCount, - value.hotCodeBlock_offset, value.coldCodeBlock_offset, value.roDataBlock_offset, value.hotCodeBlock, - value.coldCodeBlock, value.roDataBlock); + => Out.Write($"AllocMem key 0, value hotCodeSize-{value.hotCodeSize} coldCodeSize-{value.coldCodeSize} roDataSize-{value.roDataSize} " + + $"xcptnsCount-{value.xcptnsCount} hotCodeBlock_offset-{value.hotCodeBlock_offset} coldCodeBlock_offset-{value.coldCodeBlock_offset} " + + $"roDataBlock_offset-{value.roDataBlock_offset} hotCodeBlock-{value.hotCodeBlock:X16} coldCodeBlock-{value.coldCodeBlock:X16} " + + $"roDataBlock-{value.roDataBlock:X16}"); public void dmpCompileMethod(uint key, in Agnostic_CompileMethodResults value) - => CFormat.Printf(Out, "CompileMethod key %u, value nativeEntry-%016llX nativeSizeOfCode-%u CorJitResult-%u", key, - value.nativeEntry, value.nativeSizeOfCode, value.CorJitResult); + => Out.Write($"CompileMethod key {key}, value nativeEntry-{value.nativeEntry:X16} nativeSizeOfCode-{value.nativeSizeOfCode} " + + $"CorJitResult-{value.CorJitResult}"); public void dmpMessageLog(uint key, uint value) - => CFormat.Printf(Out, "MessageLog NYI"); + => Out.Write("MessageLog NYI"); public void dmpSetEHcount(uint key, uint value) - => CFormat.Printf(Out, "SetEHcount key %u, value %u", key, value); + => Out.Write($"SetEHcount key {key}, value {value}"); public void dmpSetEHinfo(uint key, in Agnostic_CORINFO_EH_CLAUSE value) { - CFormat.Printf(Out, "SetEHinfo key %u, value flg-%u to-%u tl-%u ho-%u hl-%u", key, value.Flags, value.TryOffset, value.TryLength, - value.HandlerOffset, value.HandlerLength); + Out.Write($"SetEHinfo key {key}, value flg-{value.Flags} to-{value.TryOffset} tl-{value.TryLength} ho-{value.HandlerOffset} " + + $"hl-{value.HandlerLength}"); if (value.Flags == CORINFO_EH_CLAUSE_FILTER) { - CFormat.Printf(Out, " fo-%u", value.ClassToken); // FilterOffset + Out.Write($" fo-{value.ClassToken}"); // FilterOffset } else if (value.Flags == CORINFO_EH_CLAUSE_NONE) { - CFormat.Printf(Out, " cls-%08X", value.ClassToken); + Out.Write($" cls-{value.ClassToken:X8}"); } // else, no need to print for finally/fault handlers } public void dmpSetMethodAttribs(ulong key, uint value) { - CFormat.Printf(Out, "SetMethodAttribs key ftn-%016llX, value attr-%08X", key, value); + Out.Write($"SetMethodAttribs key ftn-{key:X16}, value attr-{value:X8}"); } public void dmpReportFatalError(uint key, uint value) - => CFormat.Printf(Out, "ReportFatalError key Count-%u, value result-%08X", key, value); + => Out.Write($"ReportFatalError key Count-{key}, value result-{value:X8}"); public void dmpRecordRelocation(uint key, in Agnostic_RecordRelocation value) - => CFormat.Printf(Out, "RecordRelocation key %u, value loc-%016llX tgt-%016llX fRelocType-%u(%s) addlDelta:%d", key, - value.location, value.target, value.fRelocType, relocationTypeToString(value.fRelocType), - (int)value.addlDelta); + => Out.Write($"RecordRelocation key {key}, value loc-{value.location:X16} tgt-{value.target:X16} " + + $"fRelocType-{value.fRelocType}({relocationTypeToString(value.fRelocType)}) addlDelta:{(int)value.addlDelta}"); public void dmpReserveUnwindInfo(uint key, in Agnostic_ReserveUnwindInfo value) - => CFormat.Printf(Out, "ReserveUnwindInfo key %u, value isFun-%u isCold-%u usz-%u", key, value.isFunclet, value.isColdCode, - value.unwindSize); + => Out.Write($"ReserveUnwindInfo key {key}, value isFun-{value.isFunclet} isCold-{value.isColdCode} usz-{value.unwindSize}"); public void dmpAllocUnwindInfo(uint key, in Agnostic_AllocUnwindInfo value) - => CFormat.Printf(Out, "AllocUnwindInfo key %u, value pHot-%016llX pCold-%016llX startOff-%u endOff-%u unwindSz-%u blki-%u funcKind-%u", - key, value.pHotCode, value.pColdCode, value.startOffset, value.endOffset, value.unwindSize, - value.pUnwindBlock_index, value.funcKind); + => Out.Write($"AllocUnwindInfo key {key}, value pHot-{value.pHotCode:X16} pCold-{value.pColdCode:X16} startOff-{value.startOffset} " + + $"endOff-{value.endOffset} unwindSz-{value.unwindSize} blki-{value.pUnwindBlock_index} funcKind-{value.funcKind}"); public void dmpRecordCallSiteWithSignature(uint key, in Agnostic_RecordCallSite value) - => CFormat.Printf(Out, "RecordCallSite key %u, callSig-%s ftn-%016llX", - key, - SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INFO(value.callSig, RecordCallSiteWithSignature, CrSigInstHandleMap), - value.methodHandle); + => Out.Write($"RecordCallSite key {key}, " + + $"callSig-{SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INFO(value.callSig, RecordCallSiteWithSignature, CrSigInstHandleMap)} " + + $"ftn-{value.methodHandle:X16}"); public void dmpRecordCallSiteWithoutSignature(uint key, ulong methodHandle) - => CFormat.Printf(Out, "RecordCallSite without call signature key %u, ftn-%016llX", key, methodHandle); + => Out.Write($"RecordCallSite without call signature key {key}, ftn-{methodHandle:X16}"); public void dmpCrSigInstHandleMap(uint key, ulong value) - => CFormat.Printf(Out, "CrSigInstHandleMap key %u, value %016llX", key, value); + => Out.Write($"CrSigInstHandleMap key {key}, value {value:X16}"); } diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CompileResult.Replay.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CompileResult.Replay.cs index b7072c43e9f9f1..354b48e87f7214 100644 --- a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CompileResult.Replay.cs +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CompileResult.Replay.cs @@ -379,7 +379,8 @@ public void applyRelocs(ref RelocContext rc, byte* block1, uint blocksize1, void nuint section_begin = (nuint)block1; nuint section_end = (nuint)block1 + blocksize1; // address is exclusive - Logger.LogDebug(CFormat.Sprintf("applyRelocs block [%p,%p) block size %u, orig addr %p", (ulong)block1, (ulong)(block1 + blocksize1), blocksize1, CastHandle(originalAddr))); + Logger.LogDebug($"applyRelocs block [0x{(ulong)block1:x},0x{(ulong)(block1 + blocksize1):x}) block size {blocksize1}, orig addr " + + $"0x{CastHandle(originalAddr):x}"); ReadOnlySpan relocations = RecordRelocation.GetRawItems(); for (int i = 0; i < relocations.Length; i++) @@ -406,7 +407,7 @@ public void applyRelocs(ref RelocContext rc, byte* block1, uint blocksize1, void { if (inSection) { - Logger.LogDebug(CFormat.Sprintf(" fixupLoc-%016llX (@%p) : %08X => %08X", fixupLocation, (ulong)address, *(uint*)address, (uint)tmp.target)); + Logger.LogDebug($" fixupLoc-{fixupLocation:X16} (@0x{(ulong)address:x}) : {*(uint*)address:X8} => {(uint)tmp.target:X8}"); *(uint*)address = (uint)tmp.target; } wasRelocHandled = true; @@ -530,7 +531,7 @@ public void applyRelocs(ref RelocContext rc, byte* block1, uint blocksize1, void // Write 64 bits into the location. if (inSection) { - Logger.LogDebug(CFormat.Sprintf(" fixupLoc-%016llX (@%p) %016llX => %016llX", fixupLocation, (ulong)address, *(ulong*)address, tmp.target)); + Logger.LogDebug($" fixupLoc-{fixupLocation:X16} (@0x{(ulong)address:x}) {*(ulong*)address:X16} => {tmp.target:X16}"); *(ulong*)address = tmp.target; } wasRelocHandled = true; @@ -582,7 +583,8 @@ private static void ApplyRelative32(ref RelocContext rc, in Agnostic_RecordReloc int index = mc.GetRelocTypeHint.GetIndex(tmp.target); if (index != -1 && (CorInfoReloc)mc.GetRelocTypeHint.GetItem(index) == CorInfoReloc.RELATIVE32) { - Logger.LogDebug(CFormat.Sprintf(" RELATIVE32 target used as argument to getRelocTypeHint: setting delta=%d (0x%X)", (ulong)(long)(int)tmp.target, (uint)tmp.target)); + Logger.LogDebug($" RELATIVE32 target used as argument to getRelocTypeHint: setting delta={(int)tmp.target} " + + $"(0x{(uint)tmp.target:X})"); delta = (int)tmp.target; deltaIsFinal = true; } @@ -597,7 +599,8 @@ private static void ApplyRelative32(ref RelocContext rc, in Agnostic_RecordReloc { if (value.helperLookup.handle == tmp.target) { - Logger.LogDebug(CFormat.Sprintf(" RELATIVE32 target is result of getHelperFtn(): setting delta=%d (0x%X)", (ulong)(long)(int)tmp.target, (uint)tmp.target)); + Logger.LogDebug($" RELATIVE32 target is result of getHelperFtn(): setting delta={(int)tmp.target} " + + $"(0x{(uint)tmp.target:X})"); delta = (int)tmp.target; deltaIsFinal = true; break; @@ -612,7 +615,8 @@ private static void ApplyRelative32(ref RelocContext rc, in Agnostic_RecordReloc { if (value.A == tmp.target) { - Logger.LogDebug(CFormat.Sprintf(" RELATIVE32 target is result of getFunctionEntryPoint(): setting delta=%d (0x%X)", (ulong)(long)(int)tmp.target, (uint)tmp.target)); + Logger.LogDebug($" RELATIVE32 target is result of getFunctionEntryPoint(): setting delta={(int)tmp.target} " + + $"(0x{(uint)tmp.target:X})"); delta = (int)tmp.target; deltaIsFinal = true; break; @@ -629,13 +633,13 @@ private static void ApplyRelative32(ref RelocContext rc, in Agnostic_RecordReloc { delta = (long)(rc.originalHotCodeAddress + rc.hotCodeSize + ro_section_offset - baseAddr); deltaIsFinal = true; - Logger.LogDebug(CFormat.Sprintf(" RELATIVE32 hot code target is in RO data section: setting delta=%d (0x%X)", (ulong)delta, (ulong)delta)); + Logger.LogDebug($" RELATIVE32 hot code target is in RO data section: setting delta={(int)delta} (0x{(uint)delta:X})"); } else if (rc.originalColdCodeAddress <= (nuint)fixupLocation && (nuint)fixupLocation < rc.originalColdCodeAddress + rc.coldCodeSize) { delta = (long)(rc.originalColdCodeAddress + rc.coldCodeSize + ro_section_offset - baseAddr); deltaIsFinal = true; - Logger.LogDebug(CFormat.Sprintf(" RELATIVE32 cold code target is in RO data section: setting delta=%d (0x%X)", (ulong)delta, (ulong)delta)); + Logger.LogDebug($" RELATIVE32 cold code target is in RO data section: setting delta={(int)delta} (0x{(uint)delta:X})"); } } @@ -645,7 +649,7 @@ private static void ApplyRelative32(ref RelocContext rc, in Agnostic_RecordReloc // compilation fit fine. This is only an issue for 32-bit offsets on 64-bit targets. target = CastHandle(originalAddr) + blocksize1; long newdelta = (long)(target - baseAddr); - Logger.LogDebug(CFormat.Sprintf(" RELATIVE32 overflow. Mapping target to %016llX. Mapping delta: %016llX => %016llX", target, (ulong)delta, (ulong)newdelta)); + Logger.LogDebug($" RELATIVE32 overflow. Mapping target to {target:X16}. Mapping delta: {delta:X16} => {newdelta:X16}"); delta = newdelta; } } @@ -658,7 +662,7 @@ private static void ApplyRelative32(ref RelocContext rc, in Agnostic_RecordReloc } else if (delta != (int)delta) { - Logger.LogError(CFormat.Sprintf("RELATIVE32 relocation overflows field! delta=0x%016llX", (ulong)delta)); + Logger.LogError($"RELATIVE32 relocation overflows field! delta=0x{delta:X16}"); } if (GetSpmiTargetArchitecture() == TargetArchitecture.X64 && !deltaIsFinal) @@ -672,7 +676,7 @@ private static void ApplyRelative32(ref RelocContext rc, in Agnostic_RecordReloc } // Write 32 bits into the location. - Logger.LogDebug(CFormat.Sprintf(" fixupLoc-%016llX (@%p) : %08X => %08X", fixupLocation, (ulong)address, *(uint*)address, (ulong)delta)); + Logger.LogDebug($" fixupLoc-{fixupLocation:X16} (@0x{(ulong)address:x}) : {*(uint*)address:X8} => {(uint)delta:X8}"); *(uint*)address = (uint)delta; } diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Dump.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Dump.cs index 76d696c41451b1..c5ed1d081b1511 100644 --- a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Dump.cs +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Dump.cs @@ -22,7 +22,7 @@ public sealed partial class MethodContext public void dmpGetClassAssemblyName(ulong key, uint value) { string assemblyName = GetClassAssemblyName.GetString(value); - CFormat.Printf(Out, "GetClassAssemblyName cls-%016llX, value-%u '%s'", key, value, assemblyName); + Out.Write($"GetClassAssemblyName cls-{key:X16}, value-{value} '{assemblyName ?? "(null)"}'"); GetClassAssemblyName.Unlock(); } @@ -30,11 +30,11 @@ public void dmpGetVars(ulong key, in Agnostic_GetVars value) { const int ILVarInfoSize = 12; // ICorDebugInfo::ILVarInfo: startOffset, endOffset, varNumber ReadOnlySpan vars = GetVars.GetBuffer(value.vars_offset); - CFormat.Printf(Out, "GetVars key ftn-%016llX, value cVars-%u extendOthers-%u (", key, value.cVars, value.extendOthers); + Out.Write($"GetVars key ftn-{key:X16}, value cVars-{value.cVars} extendOthers-{value.extendOthers} ("); for (uint i = 0; i < value.cVars; i++) { int at = (int)i * ILVarInfoSize; - CFormat.Printf(Out, "(%u %u %u %u)", i, U32(vars, at), U32(vars, at + 4), U32(vars, at + 8)); + Out.Write($"({i} {U32(vars, at)} {U32(vars, at + 4)} {U32(vars, at + 8)})"); } Out.Write(")"); GetVars.Unlock(); @@ -42,11 +42,11 @@ public void dmpGetVars(ulong key, in Agnostic_GetVars value) public void dmpGetBoundaries(ulong key, in Agnostic_GetBoundaries value) { - CFormat.Printf(Out, "GetBoundaries key ftn-%016llX, value cnt-%u imp-%u{", key, value.cILOffsets, value.implicitBoundaries); + Out.Write($"GetBoundaries key ftn-{key:X16}, value cnt-{value.cILOffsets} imp-{value.implicitBoundaries}{{"); ReadOnlySpan bnd = GetBoundaries.GetBuffer(value.pILOffset_offset); for (uint i = 0; i < value.cILOffsets; i++) { - CFormat.Printf(Out, "%u", U32(bnd, (int)i * 4)); + Out.Write($"{U32(bnd, (int)i * 4)}"); // Every element is followed by a comma. Out.Write(","); } @@ -60,14 +60,15 @@ public void dmpGetMethodNameFromMetadata(Agnostic_CORINFO_METHODNAME_TOKENin key string className = GetMethodNameFromMetadata.GetString(value.className); string namespaceName = GetMethodNameFromMetadata.GetString(value.namespaceName); ReadOnlySpan enclosingClassNameIndices = GetMethodNameFromMetadata.GetBuffer(value.enclosingClassNames); - CFormat.Printf(Out, "GetMethodNameFromMetadata key - ftn-%016llX classNonNull-%u namespaceNonNull-%u maxEnclosingClassNames-%u, value meth-'%s', class-'%s', namespace-'%s'", - key.ftn, key.className, key.namespaceName, key.maxEnclosingClassNames, methodName, className, namespaceName); + Out.Write($"GetMethodNameFromMetadata key - ftn-{key.ftn:X16} classNonNull-{key.className} namespaceNonNull-{key.namespaceName} " + + $"maxEnclosingClassNames-{key.maxEnclosingClassNames}, value meth-'{methodName ?? "(null)"}', class-'{className ?? "(null)"}', " + + $"namespace-'{namespaceName ?? "(null)"}'"); for (uint i = 0; i < key.maxEnclosingClassNames; i++) { string enclosingClassName = GetMethodNameFromMetadata.GetString(U32(enclosingClassNameIndices, (int)i * 4)); if (enclosingClassName != null) - CFormat.Printf(Out, " enclosingClass%u-'%s'", i, enclosingClassName); + Out.Write($" enclosingClass{i}-'{enclosingClassName}'"); } GetMethodNameFromMetadata.Unlock(); @@ -77,24 +78,24 @@ public void dmpGetJitFlags(uint key, DD value) { ReadOnlySpan jitflags = GetJitFlags.GetBuffer(value.A); ulong flags = U64(jitflags, 0); - CFormat.Printf(Out, "GetJitFlags key %u sizeInBytes-%u jitFlags-%016llX instructionSetFlags-", key, value.B, flags); + Out.Write($"GetJitFlags key {key} sizeInBytes-{value.B} jitFlags-{flags:X16} instructionSetFlags-"); var isaFlags = new ulong[InstructionFlagsFieldCount]; for (int i = 0; i < isaFlags.Length; i++) isaFlags[i] = U64(jitflags, 8 * (i + 1)); for (int i = isaFlags.Length - 1; i >= 0; i--) - CFormat.Printf(Out, "%016llX", isaFlags[i]); + Out.Write($"{isaFlags[i]:X16}"); Out.Write(" ("); for (uint flag = 0; flag < 64; flag++) { if ((flags & (1UL << (int)flag)) != 0) - CFormat.Printf(Out, " %s", JitFlagNames.CorJitFlagToString(flag)); + Out.Write($" {JitFlagNames.CorJitFlagToString(flag)}"); } for (uint isa = 0; isa < 64 * isaFlags.Length; isa++) { if ((isaFlags[isa / 64] & (1UL << (int)(isa % 64))) != 0) - CFormat.Printf(Out, " %s", JitFlagNames.InstructionSetToString(isa)); + Out.Write($" {JitFlagNames.InstructionSetToString(isa)}"); } Out.Write(" )"); GetJitFlags.Unlock(); @@ -102,42 +103,42 @@ public void dmpGetJitFlags(uint key, DD value) public void dmpGetFieldInfo(in Agnostic_GetFieldInfo key, in Agnostic_CORINFO_FIELD_INFO value) { - CFormat.Printf(Out, "GetFieldInfo key ch-%016llX flg-%08X rt{%s}", key.callerHandle, key.flags, - SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.ResolvedToken)); + Out.Write($"GetFieldInfo key ch-{key.callerHandle:X16} flg-{key.flags:X8} " + + $"rt{{{SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.ResolvedToken)}}}"); - CFormat.Printf(Out, ", value fa-%u fflg-%08X hlp-%u off-%u fT-%u(%s) sT-%016llX aa-%u hnum-%u na-%u {", value.fieldAccessor, - value.fieldFlags, value.helper, value.offset, value.fieldType, toString_CorInfoType(value.fieldType), - value.structType, value.accessAllowed, value.accessCalloutHelper.helperNum, value.accessCalloutHelper.numArgs); + Out.Write($", value fa-{value.fieldAccessor} fflg-{value.fieldFlags:X8} hlp-{value.helper} off-{value.offset} " + + $"fT-{value.fieldType}({toString_CorInfoType(value.fieldType)}) sT-{value.structType:X16} aa-{value.accessAllowed} " + + $"hnum-{value.accessCalloutHelper.helperNum} na-{value.accessCalloutHelper.numArgs} {{"); for (int i = 0; i < 4; i++) { Agnostic_CORINFO_HELPER_ARG arg = value.accessCalloutHelper.args[i]; - string format = arg.argType switch + string kind = arg.argType switch { - 1 => "{%u: fld-%016llX}", - 2 => "{%u: mth-%016llX}", - 3 => "{%u: cls-%016llX}", - 4 => "{%u: mod-%016llX}", - 5 => "{%u: const-%016llX}", + 1 => "fld", + 2 => "mth", + 3 => "cls", + 4 => "mod", + 5 => "const", _ => null, }; - if (format == null) - CFormat.Printf(Out, "{%u: illegal}", i); + if (kind == null) + Out.Write($"{{{i}: illegal}}"); else - CFormat.Printf(Out, format, i, arg.constant); + Out.Write($"{{{i}: {kind}-{arg.constant:X16}}}"); } - CFormat.Printf(Out, " fl %s}", SpmiDumpHelper.DumpAgnostic_CORINFO_CONST_LOOKUP(value.fieldLookup)); + Out.Write($" fl {SpmiDumpHelper.DumpAgnostic_CORINFO_CONST_LOOKUP(value.fieldLookup)}}}"); } public void dmpGetClassGClayout(ulong key, in Agnostic_GetClassGClayout value) { - CFormat.Printf(Out, "GetClassGCLayout key %016llX, value len %u cnt %u {", key, value.len, value.valCount); + Out.Write($"GetClassGCLayout key {key:X16}, value len {value.len} cnt {value.valCount} {{"); if (value.gcPtrs_Index != uint.MaxValue) { ReadOnlySpan ptr = GetClassGClayout.GetBuffer(value.gcPtrs_Index); for (uint i = 0; i < value.len; i++) { - CFormat.Printf(Out, "0x%02x", ptr[(int)i]); + Out.Write($"0x{ptr[(int)i]:x2}"); if (i + 1 < value.len) Out.Write(","); } @@ -148,17 +149,17 @@ public void dmpGetClassGClayout(ulong key, in Agnostic_GetClassGClayout value) public void dmpCanAccessClass(in Agnostic_CanAccessClassIn key, in Agnostic_CanAccessClassOut value) { - CFormat.Printf(Out, "CanAccessClass key rt{%s}, callerHandle %016llX\n", - SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.ResolvedToken), key.callerHandle); - CFormat.Printf(Out, ", value hnum-%u na-%u {", value.AccessHelper.helperNum, value.AccessHelper.numArgs); + Out.Write($"CanAccessClass key rt{{{SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.ResolvedToken)}}}, callerHandle " + + $"{key.callerHandle:X16}\n"); + Out.Write($", value hnum-{value.AccessHelper.helperNum} na-{value.AccessHelper.numArgs} {{"); for (int i = 0; i < 4; i++) - CFormat.Printf(Out, "{%016llX %u}", value.AccessHelper.args[i].constant, value.AccessHelper.args[i].argType); - CFormat.Printf(Out, "} res-%u", value.result); + Out.Write($"{{{value.AccessHelper.args[i].constant:X16} {value.AccessHelper.args[i].argType}}}"); + Out.Write($"}} res-{value.result}"); } public void dmpGetTypeLayout(ulong key, in Agnostic_GetTypeLayoutResult value) { - CFormat.Printf(Out, "GetTypeLayout key type-%016llX value result=%d numNodes=%d", key, value.result, value.numNodes); + Out.Write($"GetTypeLayout key type-{key:X16} value result={(int)value.result} numNodes={(int)value.numNodes}"); if (value.numNodes > 0) { ReadOnlySpan nodes = @@ -179,9 +180,9 @@ public void dmpTypeLayoutTree(ReadOnlySpan no Out.Write(" "); Agnostic_CORINFO_TYPE_LAYOUT_NODE node = nodes[(int)index]; - CFormat.Printf(Out, "%zu: parent %u offset %u size %u type %s numFields %u hasSignificantPadding %s simdTypeHnd %016llX diagFieldHnd %016llX", - index, node.parent, node.offset, node.size, toString_CorInfoType(node.type), node.numFields, - node.hasSignificantPadding != 0 ? "yes" : "no", node.simdTypeHnd, node.diagFieldHnd); + Out.Write($"{index}: parent {node.parent} offset {node.offset} size {node.size} type {toString_CorInfoType(node.type)} numFields " + + $"{node.numFields} hasSignificantPadding {(node.hasSignificantPadding != 0 ? "yes" : "no")} simdTypeHnd {node.simdTypeHnd:X16} " + + $"diagFieldHnd {node.diagFieldHnd:X16}"); index++; for (ulong i = 0; i < node.numFields; i++) @@ -199,8 +200,8 @@ private static Agnostic_PgoInstrumentationSchema PgoSchemaAt(ReadOnlySpan public void dmpAllocPgoInstrumentationBySchema(ulong key, in Agnostic_AllocPgoInstrumentationBySchema value) { - CFormat.Printf(Out, "AllocPgoInstrumentationBySchema key ftn-%016llX, value res-%08X addr-%016llX cnt-%u schema{\n", - key, value.result, value.instrumentationDataAddress, value.countSchemaItems); + Out.Write($"AllocPgoInstrumentationBySchema key ftn-{key:X16}, value res-{value.result:X8} addr-{value.instrumentationDataAddress:X16} " + + $"cnt-{value.countSchemaItems} schema{{\n"); if (value.countSchemaItems > 0) { @@ -209,8 +210,8 @@ public void dmpAllocPgoInstrumentationBySchema(ulong key, in Agnostic_AllocPgoIn for (uint i = 0; i < value.countSchemaItems; i++) { Agnostic_PgoInstrumentationSchema s = PgoSchemaAt(pBuf, i); - CFormat.Printf(Out, " %u-{Offset %016llX ILOffset %u Kind %u(0x%x) Count %u Other %u}\n", - i, s.Offset, s.ILOffset, s.InstrumentationKind, s.InstrumentationKind, s.Count, s.Other); + Out.Write($" {i}-{{Offset {s.Offset:X16} ILOffset {s.ILOffset} Kind {s.InstrumentationKind}(0x{s.InstrumentationKind:x}) Count " + + $"{s.Count} Other {s.Other}}}\n"); } AllocPgoInstrumentationBySchema.Unlock(); } @@ -219,8 +220,8 @@ public void dmpAllocPgoInstrumentationBySchema(ulong key, in Agnostic_AllocPgoIn public void dmpGetPgoInstrumentationResults(ulong key, in Agnostic_GetPgoInstrumentationResults value) { - CFormat.Printf(Out, "GetPgoInstrumentationResults key ftn-%016llX, value res-%08X schemaCnt-%u profileBufSize-%u source-%u dynamic-%u schema{", - key, value.result, value.countSchemaItems, value.dataByteCount, value.pgoSource, value.dynamicPgo); + Out.Write($"GetPgoInstrumentationResults key ftn-{key:X16}, value res-{value.result:X8} schemaCnt-{value.countSchemaItems} " + + $"profileBufSize-{value.dataByteCount} source-{value.pgoSource} dynamic-{value.dynamicPgo} schema{{"); if (value.countSchemaItems > 0) { @@ -231,49 +232,49 @@ public void dmpGetPgoInstrumentationResults(ulong key, in Agnostic_GetPgoInstrum for (uint i = 0; i < value.countSchemaItems; i++) { Agnostic_PgoInstrumentationSchema s = PgoSchemaAt(pBuf, i); - CFormat.Printf(Out, " %u-{Offset %016llX ILOffset %u Kind %u(0x%x) Count %u Other %u Data ", - i, s.Offset, s.ILOffset, s.InstrumentationKind, s.InstrumentationKind, s.Count, s.Other); + Out.Write($" {i}-{{Offset {s.Offset:X16} ILOffset {s.ILOffset} Kind {s.InstrumentationKind}(0x{s.InstrumentationKind:x}) Count " + + $"{s.Count} Other {s.Other} Data "); int at = (int)s.Offset; switch ((PgoInstrumentationKind)s.InstrumentationKind) { case PgoInstrumentationKind.BasicBlockIntCount: - CFormat.Printf(Out, "B %u", U32(data, at)); + Out.Write($"B {U32(data, at)}"); break; case PgoInstrumentationKind.BasicBlockLongCount: - CFormat.Printf(Out, "B %llu", U64(data, at)); + Out.Write($"B {U64(data, at)}"); break; case PgoInstrumentationKind.EdgeIntCount: - CFormat.Printf(Out, "E %u", U32(data, at)); + Out.Write($"E {U32(data, at)}"); break; case PgoInstrumentationKind.EdgeLongCount: - CFormat.Printf(Out, "E %llu", U64(data, at)); + Out.Write($"E {U64(data, at)}"); break; case PgoInstrumentationKind.HandleHistogramIntCount: - CFormat.Printf(Out, "T %u", U32(data, at)); + Out.Write($"T {U32(data, at)}"); break; case PgoInstrumentationKind.HandleHistogramLongCount: - CFormat.Printf(Out, "T %llu", U64(data, at)); + Out.Write($"T {U64(data, at)}"); break; case PgoInstrumentationKind.HandleHistogramTypes: case PgoInstrumentationKind.HandleHistogramMethods: for (uint j = 0; j < s.Count; j++) - CFormat.Printf(Out, "[%u] %016llX ", j, ReadPointer(data, at + (int)j * IntPtr.Size)); + Out.Write($"[{j}] {ReadPointer(data, at + (int)j * IntPtr.Size):X16} "); break; case PgoInstrumentationKind.ValueHistogramIntCount: - CFormat.Printf(Out, "V %u", U32(data, at)); + Out.Write($"V {U32(data, at)}"); break; case PgoInstrumentationKind.ValueHistogramLongCount: - CFormat.Printf(Out, "V %llu", U64(data, at)); + Out.Write($"V {U64(data, at)}"); break; case PgoInstrumentationKind.ValueHistogram: for (uint j = 0; j < s.Count; j++) - CFormat.Printf(Out, "[%u] %08X ", j, U32(data, at + (int)j * sizeof(uint))); + Out.Write($"[{j}] {U32(data, at + (int)j * sizeof(uint)):X8} "); break; case PgoInstrumentationKind.GetLikelyClass: case PgoInstrumentationKind.GetLikelyMethod: // (N)umber, (L)ikelihood, (H)andle - CFormat.Printf(Out, "N %u L %u H %016llX", s.Other >> 8, s.Other & 0xFF, ReadPointer(data, at)); + Out.Write($"N {s.Other >> 8} L {s.Other & 0xFF} H {ReadPointer(data, at):X16}"); break; default: Out.Write("?"); @@ -284,7 +285,7 @@ public void dmpGetPgoInstrumentationResults(ulong key, in Agnostic_GetPgoInstrum } GetPgoInstrumentationResults.Unlock(); } - CFormat.Printf(Out, "} data_index-%u", value.data_index); + Out.Write($"}} data_index-{value.data_index}"); } // Instrumentation data holds handles in the collecting host's pointer size. @@ -293,35 +294,34 @@ private static ulong ReadPointer(ReadOnlySpan data, int offset) public void dmpGetSystemVAmd64PassStructInRegisterDescriptor(ulong key, in Agnostic_GetSystemVAmd64PassStructInRegisterDescriptor value) { - CFormat.Printf(Out, "GetSystemVAmd64PassStructInRegisterDescriptor key structHnd-%016llX, value passInReg-%u 8bCount-%u", key, - value.passedInRegisters, value.eightByteCount); + Out.Write($"GetSystemVAmd64PassStructInRegisterDescriptor key structHnd-{key:X16}, value passInReg-{value.passedInRegisters} " + + $"8bCount-{value.eightByteCount}"); for (int i = 0; i < 2; i++) { - CFormat.Printf(Out, " 8bClass[%u]-%u 8bSz[%u]-%u 8bOff[%u]-%u", i, value.eightByteClassifications[i], i, - value.eightByteSizes[i], i, value.eightByteOffsets[i]); + Out.Write($" 8bClass[{i}]-{value.eightByteClassifications[i]} 8bSz[{i}]-{value.eightByteSizes[i]} " + + $"8bOff[{i}]-{value.eightByteOffsets[i]}"); } - CFormat.Printf(Out, " result %u", value.result); + Out.Write($" result {value.result}"); } public void dmpGetSwiftLowering(ulong key, in Agnostic_GetSwiftLowering value) { - CFormat.Printf(Out, "GetSwiftLowering key structHnd-%016llX, value byReference-%u numLoweredElements-%u", key, - value.byReference, value.numLoweredElements); + Out.Write($"GetSwiftLowering key structHnd-{key:X16}, value byReference-{value.byReference} numLoweredElements-{value.numLoweredElements}"); if (value.byReference == 0) { for (int i = 0; i < value.numLoweredElements; i++) - CFormat.Printf(Out, " [%zu] %u", i, value.loweredElements[i]); + Out.Write($" [{i}] {value.loweredElements[i]}"); } } public void dmpGetFpStructLowering(ulong key, in Agnostic_GetFpStructLowering value) { - CFormat.Printf(Out, "GetFpStructLowering key structHnd-%016llX, value byIntegerCallConv-%u numLoweredElements-%u", key, - value.byIntegerCallConv, value.numLoweredElements); + Out.Write($"GetFpStructLowering key structHnd-{key:X16}, value byIntegerCallConv-{value.byIntegerCallConv} " + + $"numLoweredElements-{value.numLoweredElements}"); if (value.byIntegerCallConv == 0) { for (int i = 0; i < value.numLoweredElements; i++) - CFormat.Printf(Out, " [%zu] %u", i, value.loweredElements[i]); + Out.Write($" [{i}] {value.loweredElements[i]}"); } } @@ -329,28 +329,28 @@ public void dmpGetClassNameFromMetadata(DLD key, DD value) { string className = GetClassNameFromMetadata.GetString(value.A); string namespaceName = GetClassNameFromMetadata.GetString(value.B); - CFormat.Printf(Out, "GetClassNameFromMetadata key - classNonNull-%llu namespaceNonNull-%u, value class-'%s', namespace-'%s'", - key.A, key.B, className, namespaceName); + Out.Write($"GetClassNameFromMetadata key - classNonNull-{key.A} namespaceNonNull-{key.B}, value class-'{className ?? "(null)"}', " + + $"namespace-'{namespaceName ?? "(null)"}'"); GetClassNameFromMetadata.Unlock(); } public void dmpPrint(string name, LightWeightMapBuffer buffer, ulong key, in Agnostic_PrintResult value) { - CFormat.Printf(Out, "%s key hnd-%016llX, stringBufferSize-%u, requiredBufferSize-%u", name, key, value.stringBufferSize, value.requiredBufferSize); + Out.Write($"{name} key hnd-{key:X16}, stringBufferSize-{value.stringBufferSize}, requiredBufferSize-{value.requiredBufferSize}"); buffer.Unlock(); } public void dmpCheckMethodModifier(in Agnostic_CheckMethodModifier key, uint value) { - CFormat.Printf(Out, "CheckMethodModifier key, ftn-%016llX mod-'%s' opt-%u, value res-%u", key.hMethod, - CheckMethodModifier.GetString(key.modifier), key.fOptional, value); + Out.Write($"CheckMethodModifier key, ftn-{key.hMethod:X16} mod-'{CheckMethodModifier.GetString(key.modifier) ?? "(null)"}' " + + $"opt-{key.fOptional}, value res-{value}"); CheckMethodModifier.Unlock(); } public void dmpGetIntConfigValue(in Agnostic_ConfigIntInfo key, uint value) { string name = GetIntConfigValue.GetString(key.nameIndex); - CFormat.Printf(Out, "GetIntConfigValue name %s, default value %d, value %d", name, key.defaultValue, value); + Out.Write($"GetIntConfigValue name {name ?? "(null)"}, default value {(int)key.defaultValue}, value {(int)value}"); GetIntConfigValue.Unlock(); } @@ -358,574 +358,511 @@ public void dmpGetStringConfigValue(uint nameIndex, uint resultIndex) { string name = GetStringConfigValue.GetString(nameIndex); string result = GetStringConfigValue.GetString(resultIndex); - CFormat.Printf(Out, "GetStringConfigValue name %s, result %s", name, result); + Out.Write($"GetStringConfigValue name {name ?? "(null)"}, result {result ?? "(null)"}"); GetStringConfigValue.Unlock(); } public void dmpCompileMethod(uint key, in Agnostic_CompileMethod value) - => CFormat.Printf(Out, "CompileMethod key %u, value ftn-%016llX scp-%016llX ilo-%u ils-%u ms-%u ehc-%u opt-%u rk-%u args-%s locals-%s flg-%08X os-%u", - key, value.info.ftn, value.info.scope, value.info.ILCode_offset, value.info.ILCodeSize, value.info.maxStack, - value.info.EHcount, value.info.options, value.info.regionKind, - SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INFO(value.info.args, CompileMethod, SigInstHandleMap), - SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INFO(value.info.locals, CompileMethod, SigInstHandleMap), - value.flags, value.os); + => Out.Write($"CompileMethod key {key}, value ftn-{value.info.ftn:X16} scp-{value.info.scope:X16} ilo-{value.info.ILCode_offset} " + + $"ils-{value.info.ILCodeSize} ms-{value.info.maxStack} ehc-{value.info.EHcount} opt-{value.info.options} rk-{value.info.regionKind} " + + $"args-{SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INFO(value.info.args, CompileMethod, SigInstHandleMap)} " + + $"locals-{SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INFO(value.info.locals, CompileMethod, SigInstHandleMap)} flg-{value.flags:X8} " + + $"os-{value.os}"); public void dmpGetMethodClass(ulong key, ulong value) - => CFormat.Printf(Out, "GetMethodClass key %016llX, value %016llX", key, value); + => Out.Write($"GetMethodClass key {key:X16}, value {value:X16}"); public void dmpGetClassAttribs(ulong key, uint value) - => CFormat.Printf(Out, "GetClassAttribs key %016llX, value %08X (%s)", key, value, SpmiDumpHelper.DumpCorInfoFlag(value)); + => Out.Write($"GetClassAttribs key {key:X16}, value {value:X8} ({SpmiDumpHelper.DumpCorInfoFlag(value)})"); public void dmpIsIntrinsic(ulong key, uint value) - => CFormat.Printf(Out, "IsIntrinsic key ftn-%016llX, value res-%u", key, value); + => Out.Write($"IsIntrinsic key ftn-{key:X16}, value res-{value}"); public void dmpNotifyMethodInfoUsage(ulong key, uint value) - => CFormat.Printf(Out, "NotifyMethodInfoUsage key ftn-%016llX, value res-%u", key, value); + => Out.Write($"NotifyMethodInfoUsage key ftn-{key:X16}, value res-{value}"); public void dmpNotifyInstructionSetUsage(DD key, uint value) - => CFormat.Printf(Out, "NotifyInstructionSetUsage key isa-%u, supported-%u, preserve-negative-dependency-%u, res-%u", - key.A, key.B & 1, (key.B >> 1) & 1, value); + => Out.Write($"NotifyInstructionSetUsage key isa-{key.A}, supported-{key.B & 1}, preserve-negative-dependency-{(key.B >> 1) & 1}, " + + $"res-{value}"); public void dmpGetMethodAttribs(ulong key, uint value) - => CFormat.Printf(Out, "GetMethodAttribs key %016llX, value %08X (%s)", key, value, SpmiDumpHelper.DumpCorInfoFlag(value)); + => Out.Write($"GetMethodAttribs key {key:X16}, value {value:X8} ({SpmiDumpHelper.DumpCorInfoFlag(value)})"); public void dmpInitClass(in Agnostic_InitClass key, uint value) - => CFormat.Printf(Out, "InitClass key fld-%016llX meth-%016llX con-%016llX, value res-%u", key.field, key.method, - key.context, value); + => Out.Write($"InitClass key fld-{key.field:X16} meth-{key.method:X16} con-{key.context:X16}, value res-{value}"); public void dmpCanInline(DLDL key, in Agnostic_CanInline value) - => CFormat.Printf(Out, "CanInline key - callerHnd-%016llX calleeHnd-%016llX, value result-%u exceptionCode-%08X", - key.A, key.B, value.result, value.exceptionCode); + => Out.Write($"CanInline key - callerHnd-{key.A:X16} calleeHnd-{key.B:X16}, value result-{value.result} " + + $"exceptionCode-{value.exceptionCode:X8}"); public void dmpResolveToken(in Agnostic_CORINFO_RESOLVED_TOKENin key, in ResolveTokenValue value) - => CFormat.Printf(Out, "ResolveToken key: %s, value: %s excp-%08X", - SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKENin(key), - SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKENout(value.tokenOut), - value.exceptionCode); + => Out.Write($"ResolveToken key: {SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKENin(key)}, value: " + + $"{SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKENout(value.tokenOut)} excp-{value.exceptionCode:X8}"); public void dmpGetCallInfo(in Agnostic_GetCallInfo key, in Agnostic_CORINFO_CALL_INFO value) - => CFormat.Printf(Out, "GetCallInfo key rt{%s} crt{%s} ch-%016llX flg-%08X, value mth-%016llX, mf-%08X (%s) cf-%08X (%s) sig-%s aa-%u cch{hn-%u na-%u (TODO: dump callsiteCalloutHelper.args)} tt-%u k-%u (%s) nic-%u (%s) ch-%016llX ecnrl-%u (%s) stubLookup{%s} ipl{at-%08X (%s) hnd-%016llX} excp-%08X", - // input - SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.ResolvedToken), - SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.ConstrainedResolvedToken), - key.callerHandle, - key.flags, - // output - value.hMethod, - value.methodFlags, - SpmiDumpHelper.DumpCorInfoFlag(value.methodFlags), - value.classFlags, - SpmiDumpHelper.DumpCorInfoFlag(value.classFlags), - SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INFO(value.sig, GetCallInfo, SigInstHandleMap), - value.accessAllowed, - value.callsiteCalloutHelper.helperNum, - value.callsiteCalloutHelper.numArgs, - value.thisTransform, - value.kind, - toString_CORINFO_CALL_KIND(value.kind), - value.nullInstanceCheck, - (value.nullInstanceCheck != 0) ? "true" : "false", - value.contextHandle, - value.exactContextNeedsRuntimeLookup, - (value.exactContextNeedsRuntimeLookup != 0) ? "true" : "false", - SpmiDumpHelper.DumpAgnostic_CORINFO_LOOKUP(value.stubLookup), - value.instParamLookup.accessType, - toString_InfoAccessType(value.instParamLookup.accessType), - value.instParamLookup.handle, - value.exceptionCode); + => Out.Write($"GetCallInfo key rt{{{SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.ResolvedToken)}}} " + + $"crt{{{SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.ConstrainedResolvedToken)}}} ch-{key.callerHandle:X16} " + + $"flg-{key.flags:X8}, value mth-{value.hMethod:X16}, mf-{value.methodFlags:X8} ({SpmiDumpHelper.DumpCorInfoFlag(value.methodFlags)}) " + + $"cf-{value.classFlags:X8} ({SpmiDumpHelper.DumpCorInfoFlag(value.classFlags)}) " + + $"sig-{SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INFO(value.sig, GetCallInfo, SigInstHandleMap)} aa-{value.accessAllowed} " + + $"cch{{hn-{value.callsiteCalloutHelper.helperNum} na-{value.callsiteCalloutHelper.numArgs} (TODO: dump callsiteCalloutHelper.args)}} " + + $"tt-{value.thisTransform} k-{value.kind} ({toString_CORINFO_CALL_KIND(value.kind)}) nic-{value.nullInstanceCheck} " + + $"({((value.nullInstanceCheck != 0) ? "true" : "false")}) ch-{value.contextHandle:X16} ecnrl-{value.exactContextNeedsRuntimeLookup} " + + $"({((value.exactContextNeedsRuntimeLookup != 0) ? "true" : "false")}) " + + $"stubLookup{{{SpmiDumpHelper.DumpAgnostic_CORINFO_LOOKUP(value.stubLookup)}}} ipl{{at-{value.instParamLookup.accessType:X8} " + + $"({toString_InfoAccessType(value.instParamLookup.accessType)}) hnd-{value.instParamLookup.handle:X16}}} excp-{value.exceptionCode:X8}"); public void dmpExpandRawHandleIntrinsic(in Agnostic_ExpandRawHandleIntrinsic key, in Agnostic_CORINFO_GENERICHANDLE_RESULT result) - => CFormat.Printf(Out, "ExpandRawHandleIntrinsic key: %s, value %s cth-%016llx ht-%u", - SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKENin(key.ResolvedToken), - SpmiDumpHelper.DumpAgnostic_CORINFO_LOOKUP(result.lookup), - result.compileTimeHandle, - result.handleType); + => Out.Write($"ExpandRawHandleIntrinsic key: {SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKENin(key.ResolvedToken)}, value " + + $"{SpmiDumpHelper.DumpAgnostic_CORINFO_LOOKUP(result.lookup)} cth-{result.compileTimeHandle:x16} ht-{result.handleType}"); public void dmpIsIntrinsicType(ulong key, uint value) - => CFormat.Printf(Out, "IsIntrinsicType key mth-%016llX, value intr-%u", key, value); + => Out.Write($"IsIntrinsicType key mth-{key:X16}, value intr-{value}"); public void dmpAsCorInfoType(ulong key, uint value) - => CFormat.Printf(Out, "AsCorInfoType key cls-%016llX, value cit-%u(%s)", key, value, toString_CorInfoType(value)); + => Out.Write($"AsCorInfoType key cls-{key:X16}, value cit-{value}({toString_CorInfoType(value)})"); public void dmpIsValueClass(ulong key, uint value) - => CFormat.Printf(Out, "IsValueClass key cls-%016llX, value res-%u", key, value); + => Out.Write($"IsValueClass key cls-{key:X16}, value res-{value}"); public void dmpIsByRefLike(ulong key, uint value) - => CFormat.Printf(Out, "IsByRefLike key cls-%016llX, value res-%u", key, value); + => Out.Write($"IsByRefLike key cls-{key:X16}, value res-{value}"); public void dmpIsSharedInst(ulong key, uint value) - => CFormat.Printf(Out, "IsSharedInst key cls-%016llX, value res-%u", key, value); + => Out.Write($"IsSharedInst key cls-{key:X16}, value res-{value}"); public void dmpGetClassSize(ulong key, uint val) - => CFormat.Printf(Out, "GetClassSize key %016llX, value %u", key, val); + => Out.Write($"GetClassSize key {key:X16}, value {val}"); public void dmpGetHeapClassSize(ulong key, uint val) - => CFormat.Printf(Out, "GetHeapClassSize key %016llX, value %u", key, val); + => Out.Write($"GetHeapClassSize key {key:X16}, value {val}"); public void dmpCanAllocateOnStack(ulong key, uint val) - => CFormat.Printf(Out, "CanAllocateOnStack key %016llX, value %u", key, val); + => Out.Write($"CanAllocateOnStack key {key:X16}, value {val}"); public void dmpGetClassNumInstanceFields(ulong key, uint value) - => CFormat.Printf(Out, "GetClassNumInstanceFields key cls-%016llX, value res-%u", key, value); + => Out.Write($"GetClassNumInstanceFields key cls-{key:X16}, value res-{value}"); public void dmpGetNewArrHelper(ulong key, uint value) - => CFormat.Printf(Out, "GetNewArrHelper key cls-%016llX, value res-%u", key, value); + => Out.Write($"GetNewArrHelper key cls-{key:X16}, value res-{value}"); public void dmpGetSharedCCtorHelper(ulong key, uint value) - => CFormat.Printf(Out, "GetSharedCCtorHelper key cls-%016llX, value res-%u", key, value); + => Out.Write($"GetSharedCCtorHelper key cls-{key:X16}, value res-{value}"); public void dmpGetTypeForBox(ulong key, ulong value) - => CFormat.Printf(Out, "GetTypeForBox key cls-%016llX, value res-%016llX", key, value); + => Out.Write($"GetTypeForBox key cls-{key:X16}, value res-{value:X16}"); public void dmpGetBoxHelper(ulong key, uint value) - => CFormat.Printf(Out, "GetBoxHelper key cls-%016llX, value res-%u", key, value); + => Out.Write($"GetBoxHelper key cls-{key:X16}, value res-{value}"); public void dmpGetBuiltinClass(uint key, ulong value) - => CFormat.Printf(Out, "GetBuiltinClass key cls-%08X, value cls-%016llX", key, value); + => Out.Write($"GetBuiltinClass key cls-{key:X8}, value cls-{value:X16}"); public void dmpGetTypeForPrimitiveValueClass(ulong key, uint value) - => CFormat.Printf(Out, "GetTypeForPrimitiveValueClass key cls-%016llX, value cit-%u(%s)", key, value, toString_CorInfoType(value)); + => Out.Write($"GetTypeForPrimitiveValueClass key cls-{key:X16}, value cit-{value}({toString_CorInfoType(value)})"); public void dmpGetTypeForPrimitiveNumericClass(ulong key, uint value) - => CFormat.Printf(Out, "GetTypeForPrimitiveNumericClass key cls-%016llX, value cit-%u(%s)", key, value, - toString_CorInfoType(value)); + => Out.Write($"GetTypeForPrimitiveNumericClass key cls-{key:X16}, value cit-{value}({toString_CorInfoType(value)})"); public void dmpGetParentType(ulong key, ulong value) - => CFormat.Printf(Out, "GetParentType key cls-%016llX, value cls-%016llX", key, value); + => Out.Write($"GetParentType key cls-{key:X16}, value cls-{value:X16}"); public void dmpIsSDArray(ulong key, uint value) - => CFormat.Printf(Out, "IsSDArray key cls-%016llX, value res-%u", key, value); + => Out.Write($"IsSDArray key cls-{key:X16}, value res-{value}"); public void dmpGetFieldClass(ulong key, ulong value) - => CFormat.Printf(Out, "GetFieldClass key %016llX, value %016llX", key, value); + => Out.Write($"GetFieldClass key {key:X16}, value {value:X16}"); public void dmpGetFieldOffset(ulong key, uint value) - => CFormat.Printf(Out, "GetFieldOffset key FLD-%016llX, value %08X", key, value); + => Out.Write($"GetFieldOffset key FLD-{key:X16}, value {value:X8}"); public void dmpGetUnBoxHelper(ulong key, uint value) - => CFormat.Printf(Out, "GetUnBoxHelper key cls-%016llX, value res-%u", key, value); + => Out.Write($"GetUnBoxHelper key cls-{key:X16}, value res-{value}"); public void dmpGetRuntimeTypePointer(ulong key, ulong value) - => CFormat.Printf(Out, "GetRuntimeTypePointer key cls-%016llX, value res-%016llX", key, value); + => Out.Write($"GetRuntimeTypePointer key cls-{key:X16}, value res-{value:X16}"); public void dmpIsObjectImmutable(ulong key, uint value) - => CFormat.Printf(Out, "IsObjectImmutable key obj-%016llX, value res-%u", key, value); + => Out.Write($"IsObjectImmutable key obj-{key:X16}, value res-{value}"); public void dmpGetStringChar(DLD key, DD value) - => CFormat.Printf(Out, "IsObjectImmutable key obj-%016llX, index-%u, value res-%u, val-%u", key.A, key.B, value.A, value.B); + => Out.Write($"IsObjectImmutable key obj-{key.A:X16}, index-{key.B}, value res-{value.A}, val-{value.B}"); public void dmpGetObjectType(ulong key, ulong value) - => CFormat.Printf(Out, "GetObjectType key obj-%016llX, value res-%016llX", key, value); + => Out.Write($"GetObjectType key obj-{key:X16}, value res-{value:X16}"); public void dmpGetReadyToRunHelper(GetReadyToRunHelper_TOKENin key, GetReadyToRunHelper_TOKENout value) { - CFormat.Printf(Out, "GetReadyToRunHelper key: tk{%s} id-%u", - SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.ResolvedToken), key.id); - CFormat.Printf(Out, ", value: lk{ %s } %u", SpmiDumpHelper.DumpAgnostic_CORINFO_CONST_LOOKUP(value.Lookup), - value.result); + Out.Write($"GetReadyToRunHelper key: tk{{{SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.ResolvedToken)}}} id-{key.id}"); + Out.Write($", value: lk{{ {SpmiDumpHelper.DumpAgnostic_CORINFO_CONST_LOOKUP(value.Lookup)} }} {value.result}"); } public void dmpGetReadyToRunDelegateCtorHelper(GetReadyToRunDelegateCtorHelper_TOKENIn key, Agnostic_CORINFO_LOOKUP value) { - CFormat.Printf(Out, "GetReadyToRunDelegateCtorHelper key: method tk{%s} type-%016llX constraint-%08X", - SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.TargetMethod), key.delegateType, key.targetConstraint); - CFormat.Printf(Out, ", value: %s", SpmiDumpHelper.DumpAgnostic_CORINFO_LOOKUP(value)); + Out.Write($"GetReadyToRunDelegateCtorHelper key: method tk{{{SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.TargetMethod)}}} " + + $"type-{key.delegateType:X16} constraint-{key.targetConstraint:X8}"); + Out.Write($", value: {SpmiDumpHelper.DumpAgnostic_CORINFO_LOOKUP(value)}"); } public void dmpGetHelperFtn(uint key, Agnostic_GetHelperFtn value) - => CFormat.Printf(Out, "GetHelperFtn key ftn-%u nativeEntrypoint {%s}, helperMethod-%016llX", key, - SpmiDumpHelper.DumpAgnostic_CORINFO_CONST_LOOKUP(value.helperLookup), - value.helperMethod); + => Out.Write($"GetHelperFtn key ftn-{key} nativeEntrypoint {{{SpmiDumpHelper.DumpAgnostic_CORINFO_CONST_LOOKUP(value.helperLookup)}}}, " + + $"helperMethod-{value.helperMethod:X16}"); public void dmpGetJustMyCodeHandle(ulong key, DLDL value) - => CFormat.Printf(Out, "GetJustMyCodeHandle key ftn-%016llX, value pp-%016llX, res-%016llX", key, value.A, value.B); + => Out.Write($"GetJustMyCodeHandle key ftn-{key:X16}, value pp-{value.A:X16}, res-{value.B:X16}"); public void dmpGetFunctionEntryPoint(DLD key, DLD value) - => CFormat.Printf(Out, "GetFunctionEntryPoint key ftn-%016llX af-%08X, value add-%016llX at-%u", key.A, key.B, value.A, value.B); + => Out.Write($"GetFunctionEntryPoint key ftn-{key.A:X16} af-{key.B:X8}, value add-{value.A:X16} at-{value.B}"); public void dmpConstructStringLiteral(DLD key, DLD value) - => CFormat.Printf(Out, "ConstructStringLiteral key mod-%016llX tok-%08X, value pp-%016llX iat-%u", key.A, key.B, value.A, value.B); + => Out.Write($"ConstructStringLiteral key mod-{key.A:X16} tok-{key.B:X8}, value pp-{value.A:X16} iat-{value.B}"); public void dmpConvertPInvokeCalliToCall(DLD key, DLDL value) - => CFormat.Printf(Out, "ConvertPInvokeCalliToCall key mod-%016llX tok-%08X, value cls-%016llX meth-%016llX", - key.A, key.B, value.A, value.B); + => Out.Write($"ConvertPInvokeCalliToCall key mod-{key.A:X16} tok-{key.B:X8}, value cls-{value.A:X16} meth-{value.B:X16}"); public void dmpEmptyStringLiteral(uint key, DLD value) - => CFormat.Printf(Out, "EmptyStringLiteral key %u, value pVal-%016llX res-%u", key, value.A, value.B); + => Out.Write($"EmptyStringLiteral key {key}, value pVal-{value.A:X16} res-{value.B}"); public void dmpGetArgType(in Agnostic_GetArgType_Key key, in Agnostic_GetArgType_Value value) { - CFormat.Printf(Out, "GetArgType key flg-%08X na-%u %s %s msig-%016llX scp-%016llX arg-%016llX", - key.flags, key.numArgs, - SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INST_Element("", "cc", "ci", key.sigInst_classInstCount, key.sigInst_classInst_Index, SigInstHandleMap), - SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INST_Element("", "mc", "mi", key.sigInst_methInstCount, key.sigInst_methInst_Index, SigInstHandleMap), - key.methodSignature, key.scope, key.args); - CFormat.Printf(Out, ", value result(cit)-%u(%s) vcType-%016llX excp-%08X", value.result, toString_CorInfoTypeWithMod(value.result), value.vcTypeRet, value.exceptionCode); + Out.Write($"GetArgType key flg-{key.flags:X8} na-{key.numArgs} " + + $"{SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INST_Element("", "cc", "ci", key.sigInst_classInstCount, key.sigInst_classInst_Index, SigInstHandleMap)} " + + $"{SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INST_Element("", "mc", "mi", key.sigInst_methInstCount, key.sigInst_methInst_Index, SigInstHandleMap)} " + + $"msig-{key.methodSignature:X16} scp-{key.scope:X16} arg-{key.args:X16}"); + Out.Write($", value result(cit)-{value.result}({toString_CorInfoTypeWithMod(value.result)}) vcType-{value.vcTypeRet:X16} " + + $"excp-{value.exceptionCode:X8}"); } public void dmpGetExactClasses(DLD key, in Agnostic_GetExactClassesResult value) - => CFormat.Printf(Out, "GetExactClasses key baseType-%016llX, maxExactCls-%u, value numClasses-%d", - key.A, key.B, value.numClasses); + => Out.Write($"GetExactClasses key baseType-{key.A:X16}, maxExactCls-{key.B}, value numClasses-{value.numClasses}"); public void dmpGetArgNext(ulong key, ulong value) - => CFormat.Printf(Out, "GetArgNext key %016llX, value %016llX", key, value); + => Out.Write($"GetArgNext key {key:X16}, value {value:X16}"); public void dmpGetMethodSig(DLDL key, in Agnostic_CORINFO_SIG_INFO value) - => CFormat.Printf(Out, "GetMethodSig key ftn-%016llX prt-%016llX, value-%s", key.A, key.B, - SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INFO(value, GetMethodSig, SigInstHandleMap)); + => Out.Write($"GetMethodSig key ftn-{key.A:X16} prt-{key.B:X16}, " + + $"value-{SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INFO(value, GetMethodSig, SigInstHandleMap)}"); public void dmpGetArgClass(in Agnostic_GetArgClass_Key key, in Agnostic_GetArgClass_Value value) { - CFormat.Printf(Out, "GetArgClass key %s %s msig-%016llX scp-%016llX args-%016llX", - SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INST_Element("", "cc", "ci", key.sigInst_classInstCount, key.sigInst_classInst_Index, SigInstHandleMap), - SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INST_Element("", "mc", "mi", key.sigInst_methInstCount, key.sigInst_methInst_Index, SigInstHandleMap), - key.methodSignature, key.scope, key.args); - CFormat.Printf(Out, ", value %016llX excp-%08X", value.result, value.exceptionCode); + Out.Write("GetArgClass key " + + $"{SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INST_Element("", "cc", "ci", key.sigInst_classInstCount, key.sigInst_classInst_Index, SigInstHandleMap)} " + + $"{SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INST_Element("", "mc", "mi", key.sigInst_methInstCount, key.sigInst_methInst_Index, SigInstHandleMap)} " + + $"msig-{key.methodSignature:X16} scp-{key.scope:X16} args-{key.args:X16}"); + Out.Write($", value {value.result:X16} excp-{value.exceptionCode:X8}"); } public void dmpGetHFAType(ulong key, uint value) - => CFormat.Printf(Out, "GetHFAType key %016llX, value %u ", key, value); + => Out.Write($"GetHFAType key {key:X16}, value {value} "); public void dmpGetMethodInfo(DLDL key, in Agnostic_GetMethodInfo value) { if (value.result != 0) { - CFormat.Printf(Out, "GetMethodInfo key ftn-%016llX ctx-%016llX, value res-%u ftn-%016llX scp-%016llX ilo-%u ils-%u ms-%u ehc-%u opt-%08X rk-%u args-%s locals-%s excp-%08X", - key.A, key.B, value.result, value.info.ftn, value.info.scope, value.info.ILCode_offset, value.info.ILCodeSize, - value.info.maxStack, value.info.EHcount, value.info.options, value.info.regionKind, - SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INFO(value.info.args, GetMethodInfo, SigInstHandleMap), - SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INFO(value.info.locals, GetMethodInfo, SigInstHandleMap), - value.exceptionCode); + Out.Write($"GetMethodInfo key ftn-{key.A:X16} ctx-{key.B:X16}, value res-{value.result} ftn-{value.info.ftn:X16} " + + $"scp-{value.info.scope:X16} ilo-{value.info.ILCode_offset} ils-{value.info.ILCodeSize} ms-{value.info.maxStack} " + + $"ehc-{value.info.EHcount} opt-{value.info.options:X8} rk-{value.info.regionKind} " + + $"args-{SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INFO(value.info.args, GetMethodInfo, SigInstHandleMap)} " + + $"locals-{SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INFO(value.info.locals, GetMethodInfo, SigInstHandleMap)} " + + $"excp-{value.exceptionCode:X8}"); } else { - CFormat.Printf(Out, "GetMethodInfo key ftn-%016llX ctx-%016llX, value res-%u excp-%08X", - key.A, key.B, value.result, value.exceptionCode); + Out.Write($"GetMethodInfo key ftn-{key.A:X16} ctx-{key.B:X16}, value res-{value.result} excp-{value.exceptionCode:X8}"); } } public void dmpHaveSameMethodDefinition(in DLDL key, uint value) - => CFormat.Printf(Out, "HaveSameMethodDefinition key methHnd1-%016llX, methHnd2-%016llX, value %u", key.A, key.B, value); + => Out.Write($"HaveSameMethodDefinition key methHnd1-{key.A:X16}, methHnd2-{key.B:X16}, value {value}"); public void dmpGetTypeDefinition(ulong key, ulong value) - => CFormat.Printf(Out, "GetTypeDefinition key cls-%016llX, value cls-%016llX", key, value); + => Out.Write($"GetTypeDefinition key cls-{key:X16}, value cls-{value:X16}"); public void dmpGetNewHelper(ulong key, in DDD value) - => CFormat.Printf(Out, "GetNewHelper key %016llX, hasSideEffects-%u, value res-%u, exceptionCode-%08X", key, value.A, value.B, value.C); + => Out.Write($"GetNewHelper key {key:X16}, hasSideEffects-{value.A}, value res-{value.B}, exceptionCode-{value.C:X8}"); public void dmpEmbedGenericHandle(in Agnostic_EmbedGenericHandle key, in Agnostic_CORINFO_GENERICHANDLE_RESULT value) - => CFormat.Printf(Out, "EmbedGenericHandle key rt{%s} emb-%u, value %s cth-%016llX ht-%u", - SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.ResolvedToken), - key.fEmbedParent, - SpmiDumpHelper.DumpAgnostic_CORINFO_LOOKUP(value.lookup), - value.compileTimeHandle, - value.handleType); + => Out.Write($"EmbedGenericHandle key rt{{{SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.ResolvedToken)}}} " + + $"emb-{key.fEmbedParent}, value {SpmiDumpHelper.DumpAgnostic_CORINFO_LOOKUP(value.lookup)} cth-{value.compileTimeHandle:X16} " + + $"ht-{value.handleType}"); public void dmpGetEHinfo(DLD key, in Agnostic_CORINFO_EH_CLAUSE value) - => CFormat.Printf(Out, "GetEHinfo key ftn-%016llX ehn-%u, value flg-%u to-%u tl-%u ho-%u hl-%u ct-%u", key.A, key.B, value.Flags, - value.TryOffset, value.TryLength, value.HandlerOffset, value.HandlerLength, value.ClassToken); + => Out.Write($"GetEHinfo key ftn-{key.A:X16} ehn-{key.B}, value flg-{value.Flags} to-{value.TryOffset} tl-{value.TryLength} " + + $"ho-{value.HandlerOffset} hl-{value.HandlerLength} ct-{value.ClassToken}"); public void dmpGetMethodVTableOffset(ulong key, DDD value) - => CFormat.Printf(Out, "GetMethodVTableOffset key ftn-%016llX, value offi-%u, offa-%u. offr-%d", key, value.A, value.B, value.C); + => Out.Write($"GetMethodVTableOffset key ftn-{key:X16}, value offi-{value.A}, offa-{value.B}. offr-{(int)value.C}"); public void dmpResolveVirtualMethod(in Agnostic_ResolveVirtualMethodKey key, in Agnostic_ResolveVirtualMethodResult result) { - CFormat.Printf(Out, "ResolveVirtualMethod key virtMethod-%016llX, objClass-%016llX, context-%016llX pResolvedTokenVirtualMethodNonNull-%08X pResolvedTokenVirtualMethod{%s}", - key.virtualMethod, - key.objClass, - key.context, - key.pResolvedTokenVirtualMethodNonNull, - (key.pResolvedTokenVirtualMethodNonNull != 0) ? SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.pResolvedTokenVirtualMethod) : "???"); - CFormat.Printf(Out, ", value returnValue-%s, devirtMethod-%016llX, tokenLookupContext-%016llX, detail-%d, tokDvMeth{%s}, tokDvUnboxMeth{%s}, instParamLookup{%s}", - (result.returnValue != 0) ? "true" : "false", - result.devirtualizedMethod, - result.tokenLookupContext, - result.detail, - (result.returnValue != 0) ? SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKEN(result.resolvedTokenDevirtualizedMethod) : "???", - (result.returnValue != 0) ? SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKEN(result.resolvedTokenDevirtualizedUnboxedMethod) : "???", - SpmiDumpHelper.DumpAgnostic_CORINFO_LOOKUP(result.instParamLookup)); + Out.Write($"ResolveVirtualMethod key virtMethod-{key.virtualMethod:X16}, objClass-{key.objClass:X16}, context-{key.context:X16} " + + $"pResolvedTokenVirtualMethodNonNull-{key.pResolvedTokenVirtualMethodNonNull:X8} " + + $"pResolvedTokenVirtualMethod{{{((key.pResolvedTokenVirtualMethodNonNull != 0) ? SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.pResolvedTokenVirtualMethod) : "???")}}}"); + Out.Write($", value returnValue-{((result.returnValue != 0) ? "true" : "false")}, devirtMethod-{result.devirtualizedMethod:X16}, " + + $"tokenLookupContext-{result.tokenLookupContext:X16}, detail-{(int)result.detail}, " + + $"tokDvMeth{{{((result.returnValue != 0) ? SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKEN(result.resolvedTokenDevirtualizedMethod) : "???")}}}, " + + $"tokDvUnboxMeth{{{((result.returnValue != 0) ? SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKEN(result.resolvedTokenDevirtualizedUnboxedMethod) : "???")}}}, " + + $"instParamLookup{{{SpmiDumpHelper.DumpAgnostic_CORINFO_LOOKUP(result.instParamLookup)}}}"); } public void dmpGetAsyncOtherVariant(ulong key, DLD value) - => CFormat.Printf(Out, "GetAsyncOtherVariant ftn-%016llX, result-%016llX, variantIsThunk-%u", key, value.A, value.B); + => Out.Write($"GetAsyncOtherVariant ftn-{key:X16}, result-{value.A:X16}, variantIsThunk-{value.B}"); public void dmpGetDefaultComparerClass(ulong key, ulong value) - => CFormat.Printf(Out, "GetDefaultComparerClass key cls-%016llX, value cls-%016llX", key, value); + => Out.Write($"GetDefaultComparerClass key cls-{key:X16}, value cls-{value:X16}"); public void dmpGetDefaultEqualityComparerClass(ulong key, ulong value) - => CFormat.Printf(Out, "GetDefaultEqualityComparerClass key cls-%016llX, value cls-%016llX", key, value); + => Out.Write($"GetDefaultEqualityComparerClass key cls-{key:X16}, value cls-{value:X16}"); public void dmpGetSZArrayHelperEnumeratorClass(ulong key, ulong value) - => CFormat.Printf(Out, "GetSZArrayHelperEnumeratorClass key cls-%016llX, value cls-%016llX", key, value); + => Out.Write($"GetSZArrayHelperEnumeratorClass key cls-{key:X16}, value cls-{value:X16}"); public void dmpGetTokenTypeAsHandle(in GetTokenTypeAsHandleValue key, ulong value) - => CFormat.Printf(Out, "GetTokenTypeAsHandle key ftn-%016llX fld-%016llX, value cls-%016llX", key.hMethod, key.hField, value); + => Out.Write($"GetTokenTypeAsHandle key ftn-{key.hMethod:X16} fld-{key.hField:X16}, value cls-{value:X16}"); public void dmpGetThreadLocalFieldInfo(DLD key, uint value) - => CFormat.Printf(Out, "GetThreadLocalFieldInfo key hnd-%016llX,gctype-%d result-%u", key.A, key.B, value); + => Out.Write($"GetThreadLocalFieldInfo key hnd-{key.A:X16},gctype-{(int)key.B} result-{value}"); public void dmpGetThreadLocalStaticBlocksInfo(uint key, in Agnostic_GetThreadLocalStaticBlocksInfo value) - => CFormat.Printf(Out, "GetThreadLocalStaticBlocksInfo key %u, tlsIndex-%s, , tlsGetAddrFtnPtr-%016llX, tlsIndexObject - %016llX, threadVarsSection - %016llX, offsetOfThreadLocalStoragePointer-%u, offsetOfMaxThreadStaticBlocks-%u, offsetOfThreadStaticBlocks-%u, offsetOfBaseOfThreadLocalData-%u", - key, SpmiDumpHelper.DumpAgnostic_CORINFO_CONST_LOOKUP(value.tlsIndex), value.tlsGetAddrFtnPtr, - value.tlsIndexObject, value.threadVarsSection, value.offsetOfThreadLocalStoragePointer, - value.offsetOfMaxThreadStaticBlocks, value.offsetOfThreadStaticBlocks, value.offsetOfBaseOfThreadLocalData); + => Out.Write($"GetThreadLocalStaticBlocksInfo key {key}, tlsIndex-{SpmiDumpHelper.DumpAgnostic_CORINFO_CONST_LOOKUP(value.tlsIndex)}, , " + + $"tlsGetAddrFtnPtr-{value.tlsGetAddrFtnPtr:X16}, tlsIndexObject - {value.tlsIndexObject:X16}, threadVarsSection - " + + $"{value.threadVarsSection:X16}, offsetOfThreadLocalStoragePointer-{value.offsetOfThreadLocalStoragePointer}, " + + $"offsetOfMaxThreadStaticBlocks-{value.offsetOfMaxThreadStaticBlocks}, offsetOfThreadStaticBlocks-{value.offsetOfThreadStaticBlocks}, " + + $"offsetOfBaseOfThreadLocalData-{value.offsetOfBaseOfThreadLocalData}"); public void dmpGetThreadLocalStaticInfo_NativeAOT(ulong key, in Agnostic_GetThreadStaticInfo_NativeAOT value) - => CFormat.Printf(Out, "GetThreadLocalStaticInfo_NativeAOT key %016llX, tlsRootObject-%s, tlsIndexObject-%s, offsetOfThreadLocalStoragePointer-%u, threadStaticBaseSlow-%s, tlsGetAddrFtnPtr-%s", - key, SpmiDumpHelper.DumpAgnostic_CORINFO_CONST_LOOKUP(value.tlsRootObject), - SpmiDumpHelper.DumpAgnostic_CORINFO_CONST_LOOKUP(value.tlsIndexObject), - value.offsetOfThreadLocalStoragePointer, - SpmiDumpHelper.DumpAgnostic_CORINFO_CONST_LOOKUP(value.threadStaticBaseSlow), - SpmiDumpHelper.DumpAgnostic_CORINFO_CONST_LOOKUP(value.tlsGetAddrFtnPtr)); + => Out.Write($"GetThreadLocalStaticInfo_NativeAOT key {key:X16}, " + + $"tlsRootObject-{SpmiDumpHelper.DumpAgnostic_CORINFO_CONST_LOOKUP(value.tlsRootObject)}, " + + $"tlsIndexObject-{SpmiDumpHelper.DumpAgnostic_CORINFO_CONST_LOOKUP(value.tlsIndexObject)}, " + + $"offsetOfThreadLocalStoragePointer-{value.offsetOfThreadLocalStoragePointer}, " + + $"threadStaticBaseSlow-{SpmiDumpHelper.DumpAgnostic_CORINFO_CONST_LOOKUP(value.threadStaticBaseSlow)}, " + + $"tlsGetAddrFtnPtr-{SpmiDumpHelper.DumpAgnostic_CORINFO_CONST_LOOKUP(value.tlsGetAddrFtnPtr)}"); public void dmpEmbedMethodHandle(ulong key, DLDL value) - => CFormat.Printf(Out, "EmbedMethodHandle key ftn-%016llX, value pp-%016llX res-%016llX", key, value.A, value.B); + => Out.Write($"EmbedMethodHandle key ftn-{key:X16}, value pp-{value.A:X16} res-{value.B:X16}"); public void dmpGetStaticFieldContent(DLDDD key, DD value) { - CFormat.Printf(Out, "GetStaticFieldContent key fld-%016llX bufSize-%u, ignoremovable-%u, valOffset-%u result-%u", key.A, key.B, key.C, key.D, value.A); + Out.Write($"GetStaticFieldContent key fld-{key.A:X16} bufSize-{key.B}, ignoremovable-{key.C}, valOffset-{key.D} result-{value.A}"); GetStaticFieldContent.Unlock(); } public void dmpGetObjectContent(DLDD key, DD value) { - CFormat.Printf(Out, "GetObjectContent key fld-%016llX bufSize-%u, valOffset-%u result-%u", key.A, key.B, key.C, value.A); + Out.Write($"GetObjectContent key fld-{key.A:X16} bufSize-{key.B}, valOffset-{key.C} result-{value.A}"); GetObjectContent.Unlock(); } public void dmpGetStaticFieldCurrentClass(DLD key, in Agnostic_GetStaticFieldCurrentClass value) - => CFormat.Printf(Out, "GetStaticFieldCurrentClass key fld-%016llX, value clsHnd-%016llX isSpeculative-%u", key.A, value.classHandle, - value.isSpeculative); + => Out.Write($"GetStaticFieldCurrentClass key fld-{key.A:X16}, value clsHnd-{value.classHandle:X16} isSpeculative-{value.isSpeculative}"); public void dmpGetClassAlignmentRequirement(DLD key, uint value) - => CFormat.Printf(Out, "GetClassAlignmentRequirement key %016llX %u, value %u", key.A, key.B, value); + => Out.Write($"GetClassAlignmentRequirement key {key.A:X16} {key.B}, value {value}"); public void dmpGetCastingHelper(in Agnostic_GetCastingHelper key, uint value) - => CFormat.Printf(Out, "GetCastingHelper key cls-%016llX, thw-%u, value res-%u", key.hClass, key.fThrowing, value); + => Out.Write($"GetCastingHelper key cls-{key.hClass:X16}, thw-{key.fThrowing}, value res-{value}"); public void dmpEmbedModuleHandle(ulong key, DLDL value) - => CFormat.Printf(Out, "EmbedModuleHandle key mod-%016llX, value pp-%016llX res-%016llX", key, value.A, value.B); + => Out.Write($"EmbedModuleHandle key mod-{key:X16}, value pp-{value.A:X16} res-{value.B:X16}"); public void dmpEmbedClassHandle(ulong key, DLDL value) - => CFormat.Printf(Out, "EmbedClassHandle key cls-%016llX, value pp-%016llX res-%016llX", key, value.A, value.B); + => Out.Write($"EmbedClassHandle key cls-{key:X16}, value pp-{value.A:X16} res-{value.B:X16}"); public void dmpPInvokeMarshalingRequired(in MethodOrSigInfoValue key, uint value) - => CFormat.Printf(Out, "PInvokeMarshalingRequired key mth-%016llX scp-%016llX sig-%s, value res-%u", - key.method, key.scope, - SpmiDumpHelper.DumpPSig(key.pSig_Index, key.cbSig, PInvokeMarshalingRequired), - value); + => Out.Write($"PInvokeMarshalingRequired key mth-{key.method:X16} scp-{key.scope:X16} " + + $"sig-{SpmiDumpHelper.DumpPSig(key.pSig_Index, key.cbSig, PInvokeMarshalingRequired)}, value res-{value}"); public void dmpGetUnmanagedCallConv(in MethodOrSigInfoValue key, DD value) - => CFormat.Printf(Out, "GetUnmanagedCallConv key mth-%016llX scp-%016llX sig-%s, value res-%u,%u", - key.method, key.scope, - SpmiDumpHelper.DumpPSig(key.pSig_Index, key.cbSig, GetUnmanagedCallConv), - value.A, value.B); + => Out.Write($"GetUnmanagedCallConv key mth-{key.method:X16} scp-{key.scope:X16} " + + $"sig-{SpmiDumpHelper.DumpPSig(key.pSig_Index, key.cbSig, GetUnmanagedCallConv)}, value res-{value.A},{value.B}"); public void dmpFindSig(in Agnostic_FindSig key, in Agnostic_CORINFO_SIG_INFO value) { - CFormat.Printf(Out, "FindSig key module-%016llX sigTOK-%08X context-%016llX", key.module, key.sigTOK, key.context); - CFormat.Printf(Out, ", value-%s", - SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INFO(value, FindSig, SigInstHandleMap)); + Out.Write($"FindSig key module-{key.module:X16} sigTOK-{key.sigTOK:X8} context-{key.context:X16}"); + Out.Write($", value-{SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INFO(value, FindSig, SigInstHandleMap)}"); } public void dmpGetEEInfo(uint key, in Agnostic_CORINFO_EE_INFO value) - => CFormat.Printf(Out, "GetEEInfo key %u, value icfi{sz-%u sz-witharg-%u ofl-%u ocsp-%u ocsfp-%u oct-%u ora-%u ossa-%u osap-%u} otf-%u ogcs-%u odi-%u odft-%u srpf-%u osps-%u muono-%u tabi-%u osType-%u", - key, value.inlinedCallFrameInfo.size, value.inlinedCallFrameInfo.sizeWithSecretStubArg, - value.inlinedCallFrameInfo.offsetOfFrameLink, - value.inlinedCallFrameInfo.offsetOfCallSiteSP, value.inlinedCallFrameInfo.offsetOfCalleeSavedFP, - value.inlinedCallFrameInfo.offsetOfCallTarget, value.inlinedCallFrameInfo.offsetOfReturnAddress, - value.inlinedCallFrameInfo.offsetOfSecretStubArg, value.inlinedCallFrameInfo.offsetOfSPAfterProlog, - value.offsetOfThreadFrame, value.offsetOfGCState, value.offsetOfDelegateInstance, - value.offsetOfDelegateFirstTarget, - value.sizeOfReversePInvokeFrame, value.osPageSize, value.maxUncheckedOffsetForNullObject, value.targetAbi, - value.osType); + => Out.Write($"GetEEInfo key {key}, value icfi{{sz-{value.inlinedCallFrameInfo.size} " + + $"sz-witharg-{value.inlinedCallFrameInfo.sizeWithSecretStubArg} ofl-{value.inlinedCallFrameInfo.offsetOfFrameLink} " + + $"ocsp-{value.inlinedCallFrameInfo.offsetOfCallSiteSP} ocsfp-{value.inlinedCallFrameInfo.offsetOfCalleeSavedFP} " + + $"oct-{value.inlinedCallFrameInfo.offsetOfCallTarget} ora-{value.inlinedCallFrameInfo.offsetOfReturnAddress} " + + $"ossa-{value.inlinedCallFrameInfo.offsetOfSecretStubArg} osap-{value.inlinedCallFrameInfo.offsetOfSPAfterProlog}}} " + + $"otf-{value.offsetOfThreadFrame} ogcs-{value.offsetOfGCState} odi-{value.offsetOfDelegateInstance} " + + $"odft-{value.offsetOfDelegateFirstTarget} srpf-{value.sizeOfReversePInvokeFrame} osps-{value.osPageSize} " + + $"muono-{value.maxUncheckedOffsetForNullObject} tabi-{value.targetAbi} osType-{value.osType}"); public void dmpGetAsyncInfo(uint key, in Agnostic_CORINFO_ASYNC_INFO value) - => CFormat.Printf(Out, "GetAsyncInfo key %u value contClsHnd-%016llX contNextFldHnd-%016llX contResumeInfoFldHnd-%016llX contStateFldHnd-%016llX contFlagsFldHnd-%016llX", - key, value.continuationClsHnd, value.continuationNextFldHnd, value.continuationResumeInfoFldHnd, - value.continuationStateFldHnd, value.continuationFlagsFldHnd); + => Out.Write($"GetAsyncInfo key {key} value contClsHnd-{value.continuationClsHnd:X16} contNextFldHnd-{value.continuationNextFldHnd:X16} " + + $"contResumeInfoFldHnd-{value.continuationResumeInfoFldHnd:X16} contStateFldHnd-{value.continuationStateFldHnd:X16} " + + $"contFlagsFldHnd-{value.continuationFlagsFldHnd:X16}"); public void dmpGetWasmWellKnownGlobals(uint key, in Agnostic_CORINFO_WASM_WELLKNOWN_GLOBALS value) - => CFormat.Printf(Out, "GetWasmWellKnownGlobals key %u value stackPointer-%016llX imageBase-%016llX tableBase-%016llX asyncContinuation-%016llX", - key, value.stackPointer, value.imageBase, value.tableBase, value.asyncContinuation); + => Out.Write($"GetWasmWellKnownGlobals key {key} value stackPointer-{value.stackPointer:X16} imageBase-{value.imageBase:X16} " + + $"tableBase-{value.tableBase:X16} asyncContinuation-{value.asyncContinuation:X16}"); public void dmpGetAwaitReturnCall(ulong key, in Agnostic_GetAwaitReturnCallResult value) - => CFormat.Printf(Out, "GetAwaitReturnCall key %016llX value methodHnd-%016llX contextHandle-%016llX instArg %s", - key, - value.methodHnd, - value.contextHandle, - SpmiDumpHelper.DumpAgnostic_CORINFO_LOOKUP(value.instArg)); + => Out.Write($"GetAwaitReturnCall key {key:X16} value methodHnd-{value.methodHnd:X16} contextHandle-{value.contextHandle:X16} instArg " + + $"{SpmiDumpHelper.DumpAgnostic_CORINFO_LOOKUP(value.instArg)}"); public void dmpGetAwaitAwaiterInContinuationCall(in Agnostic_GetAwaitAwaiterInContinuationCall key, in Agnostic_GetAwaitReturnCallResult value) - => CFormat.Printf(Out, "GetAwaitAwaiterInContinuationCall caller-%016llX rt{%s} unsafe-%u methodHnd-%016llX contextHandle-%016llX instArg %s", - key.callerHnd, - SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.ResolvedToken), - key.isUnsafe, - value.methodHnd, - value.contextHandle, - SpmiDumpHelper.DumpAgnostic_CORINFO_LOOKUP(value.instArg)); + => Out.Write($"GetAwaitAwaiterInContinuationCall caller-{key.callerHnd:X16} " + + $"rt{{{SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.ResolvedToken)}}} unsafe-{key.isUnsafe} methodHnd-{value.methodHnd:X16} " + + $"contextHandle-{value.contextHandle:X16} instArg {SpmiDumpHelper.DumpAgnostic_CORINFO_LOOKUP(value.instArg)}"); public void dmpGetGSCookie(uint key, DLDL value) - => CFormat.Printf(Out, "GetGSCookie key 0, value pCookieVal-%016llX ppCookieVal-%016llX", value.A, value.B); + => Out.Write($"GetGSCookie key 0, value pCookieVal-{value.A:X16} ppCookieVal-{value.B:X16}"); public void dmpGetOSRInfo(uint key, in Agnostic_GetOSRInfo value) { // todo - dump patchpoint info? - CFormat.Printf(Out, "GetOSRInfo key %u, value patchpointInfo-%u {...} iloffset-%u\n", - key, value.index, value.ilOffset); + Out.Write($"GetOSRInfo key {key}, value patchpointInfo-{value.index} {{...}} iloffset-{value.ilOffset}\n"); } public void dmpGetClassModuleIdForStatics(ulong key, in Agnostic_GetClassModuleIdForStatics value) - => CFormat.Printf(Out, "GetClassModuleIdForStatics key cls-%016llX, value mod-%016llX pp-%016llX res-%016llX", key, value.Module, - value.pIndirection, value.result); + => Out.Write($"GetClassModuleIdForStatics key cls-{key:X16}, value mod-{value.Module:X16} pp-{value.pIndirection:X16} " + + $"res-{value.result:X16}"); public void dmpGetIsClassInitedFlagAddress(ulong key, in Agnostic_GetIsClassInitedFlagAddress value) - => CFormat.Printf(Out, "GetIsClassInitedFlagAddress key hnd-%016llX, value addr-%016llX, result-%u", key, value.addr.handle, value.result); + => Out.Write($"GetIsClassInitedFlagAddress key hnd-{key:X16}, value addr-{value.addr.handle:X16}, result-{value.result}"); public void dmpGetStaticBaseAddress(DLD key, in Agnostic_GetStaticBaseAddress value) - => CFormat.Printf(Out, "GetStaticBaseAddress key hnd-%016llX, value addr-%016llX, result-%u", key.A, value.addr.handle, value.result); + => Out.Write($"GetStaticBaseAddress key hnd-{key.A:X16}, value addr-{value.addr.handle:X16}, result-{value.result}"); public void dmpGetThreadTLSIndex(uint key, DLD value) - => CFormat.Printf(Out, "GetThreadTLSIndex key 0, value ppIndirection-%016llX result-%08X", value.A, value.B); + => Out.Write($"GetThreadTLSIndex key 0, value ppIndirection-{value.A:X16} result-{value.B:X8}"); public void dmpGetAddrOfCaptureThreadGlobal(uint key, DLDL value) - => CFormat.Printf(Out, "GetAddrOfCaptureThreadGlobal key %u, value ppi-%016llX res-%016llX", key, value.A, value.B); + => Out.Write($"GetAddrOfCaptureThreadGlobal key {key}, value ppi-{value.A:X16} res-{value.B:X16}"); public void dmpGetClassStaticDynamicInfo(ulong key, DLD value) - => CFormat.Printf(Out, "GetClassStaticDynamicInfo key cls-%016llX, value pp-%016llX res-%u", key, value.A, value.B); + => Out.Write($"GetClassStaticDynamicInfo key cls-{key:X16}, value pp-{value.A:X16} res-{value.B}"); public void dmpGetClassThreadStaticDynamicInfo(ulong key, DLD value) - => CFormat.Printf(Out, "GetClassThreadStaticDynamicInfo key cls-%016llX, value pp-%016llX res-%u", key, value.A, value.B); + => Out.Write($"GetClassThreadStaticDynamicInfo key cls-{key:X16}, value pp-{value.A:X16} res-{value.B}"); public void dmpGetLocationOfThisType(ulong key, in Agnostic_CORINFO_LOOKUP_KIND value) - => CFormat.Printf(Out, "GetLocationOfThisType key ftn-%016llX, value %s", key, - SpmiDumpHelper.DumpAgnostic_CORINFO_LOOKUP_KIND(value)); + => Out.Write($"GetLocationOfThisType key ftn-{key:X16}, value {SpmiDumpHelper.DumpAgnostic_CORINFO_LOOKUP_KIND(value)}"); public void dmpGetDelegateCtor(in Agnostic_GetDelegateCtorIn key, in Agnostic_GetDelegateCtorOut value) - => CFormat.Printf(Out, "GetDelegateCtor key ftn-%016llX cls-%016llX tftn-%016llX, value pm-%016llX a3-%016llX a4-%016llX a5-%016llX res-%016llX", - key.methHnd, key.clsHnd, key.targetMethodHnd, value.CtorData.pMethod, value.CtorData.pArg3, - value.CtorData.pArg4, value.CtorData.pArg5, value.result); + => Out.Write($"GetDelegateCtor key ftn-{key.methHnd:X16} cls-{key.clsHnd:X16} tftn-{key.targetMethodHnd:X16}, value " + + $"pm-{value.CtorData.pMethod:X16} a3-{value.CtorData.pArg3:X16} a4-{value.CtorData.pArg4:X16} a5-{value.CtorData.pArg5:X16} " + + $"res-{value.result:X16}"); public void dmpGetFunctionFixedEntryPoint(ulong key, in Agnostic_CORINFO_CONST_LOOKUP value) - => CFormat.Printf(Out, "GetFunctionFixedEntryPoint key ftn-%016llX, value %s", key, - SpmiDumpHelper.DumpAgnostic_CORINFO_CONST_LOOKUP(value)); + => Out.Write($"GetFunctionFixedEntryPoint key ftn-{key:X16}, value {SpmiDumpHelper.DumpAgnostic_CORINFO_CONST_LOOKUP(value)}"); public void dmpGetFieldInClass(DLD key, ulong value) - => CFormat.Printf(Out, "GetFieldInClass key cls-%016llX ind-%u, value %016llX", key.A, key.B, value); + => Out.Write($"GetFieldInClass key cls-{key.A:X16} ind-{key.B}, value {value:X16}"); public void dmpGetFieldType(DLDL key, DLD value) - => CFormat.Printf(Out, "GetFieldType key fld-%016llX cls-%016llX, value ch-%016llX cit-%u(%s)", key.A, key.B, value.A, value.B, - toString_CorInfoType(value.B)); + => Out.Write($"GetFieldType key fld-{key.A:X16} cls-{key.B:X16}, value ch-{value.A:X16} cit-{value.B}({toString_CorInfoType(value.B)})"); public void dmpSatisfiesMethodConstraints(DLDL key, uint value) - => CFormat.Printf(Out, "SatisfiesMethodConstraints key cls-%016llX ftn-%016llX, value res-%u", key.A, key.B, value); + => Out.Write($"SatisfiesMethodConstraints key cls-{key.A:X16} ftn-{key.B:X16}, value res-{value}"); public void dmpGetStringLiteral(DLDDD key, DD value) { - CFormat.Printf(Out, "GetStringLiteral key mod-%016llX tok-%08X, bufSize-%u, startIndex-%u, len-%u", key.A, key.B, key.C, key.D, value.A); + Out.Write($"GetStringLiteral key mod-{key.A:X16} tok-{key.B:X8}, bufSize-{key.C}, startIndex-{key.D}, len-{value.A}"); GetStringLiteral.Unlock(); } public void dmpCanCast(DLDL key, uint value) - => CFormat.Printf(Out, "CanCast key chd-%016llX par-%016llX, value res-%u", key.A, key.B, value); + => Out.Write($"CanCast key chd-{key.A:X16} par-{key.B:X16}, value res-{value}"); public void dmpGetChildType(ulong key, DLD value) - => CFormat.Printf(Out, "GetChildType key cls-%016llX, value clsr-%016llX cit-%u(%s)", key, value.A, value.B, - toString_CorInfoType(value.B)); + => Out.Write($"GetChildType key cls-{key:X16}, value clsr-{value.A:X16} cit-{value.B}({toString_CorInfoType(value.B)})"); public void dmpGetArrayInitializationData(DLD key, ulong value) - => CFormat.Printf(Out, "GetArrayInitializationData key field-%016llX size-%08X, value result-%016llX", key.A, key.B, value); + => Out.Write($"GetArrayInitializationData key field-{key.A:X16} size-{key.B:X8}, value result-{value:X16}"); public void dmpGetAddressOfPInvokeTarget(ulong key, DLD value) - => CFormat.Printf(Out, "GetAddressOfPInvokeTarget key ftn-%016llX, value addr-%016llX at-%u", key, value.A, value.B); + => Out.Write($"GetAddressOfPInvokeTarget key ftn-{key:X16}, value addr-{value.A:X16} at-{value.B}"); public void dmpGetMethodHash(ulong key, uint value) - => CFormat.Printf(Out, "GetMethodHash key %016llX, value %u", key, value); + => Out.Write($"GetMethodHash key {key:X16}, value {value}"); public void dmpCanTailCall(in Agnostic_CanTailCall key, uint value) - => CFormat.Printf(Out, "CanTailCall key clr-%016llX dcle-%016llX ecle-%016llX pfx-%u, value res-%u", key.callerHnd, - key.declaredCalleeHnd, key.exactCalleeHnd, key.fIsTailPrefix, value); + => Out.Write($"CanTailCall key clr-{key.callerHnd:X16} dcle-{key.declaredCalleeHnd:X16} ecle-{key.exactCalleeHnd:X16} " + + $"pfx-{key.fIsTailPrefix}, value res-{value}"); public void dmpIsDelegateCreationAllowed(DLDL key, uint value) - => CFormat.Printf(Out, "IsDelegateCreationAllowed key delegateHnd-%016llX calleeHnd-%016llX result-%08X", key.A, key.B, value); + => Out.Write($"IsDelegateCreationAllowed key delegateHnd-{key.A:X16} calleeHnd-{key.B:X16} result-{value:X8}"); public void dmpFindCallSiteSig(in Agnostic_FindCallSiteSig key, in Agnostic_CORINFO_SIG_INFO value) { - CFormat.Printf(Out, "dmpFindCallSiteSig key module-%016llX methTok-%08X context-%016llX", key.module, key.methTok, key.context); - CFormat.Printf(Out, ", value-%s", - SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INFO(value, FindCallSiteSig, SigInstHandleMap)); + Out.Write($"dmpFindCallSiteSig key module-{key.module:X16} methTok-{key.methTok:X8} context-{key.context:X16}"); + Out.Write($", value-{SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INFO(value, FindCallSiteSig, SigInstHandleMap)}"); } public void dmpGetVarArgsHandle(in GetVarArgsHandleValue key, DLDL value) { - CFormat.Printf(Out, "GetVarArgsHandle key sig-%s scope-%016llX token-%08X methHnd-%016llX", - SpmiDumpHelper.DumpPSig(key.pSig_Index, key.cbSig, GetVarArgsHandle), - key.scope, key.token, key.methHnd); - CFormat.Printf(Out, ", value ppIndirection-%016llX result-%016llX", value.A, value.B); + Out.Write($"GetVarArgsHandle key sig-{SpmiDumpHelper.DumpPSig(key.pSig_Index, key.cbSig, GetVarArgsHandle)} scope-{key.scope:X16} " + + $"token-{key.token:X8} methHnd-{key.methHnd:X16}"); + Out.Write($", value ppIndirection-{value.A:X16} result-{value.B:X16}"); } public void dmpGetFieldThreadLocalStoreID(ulong key, DLD value) - => CFormat.Printf(Out, "GetFieldThreadLocalStoreID key field-%016llX, value ppIndirection-%016llX result-%08X", key, value.A, - value.B); + => Out.Write($"GetFieldThreadLocalStoreID key field-{key:X16}, value ppIndirection-{value.A:X16} result-{value.B:X8}"); public void dmpIsMoreSpecificType(DLDL key, uint value) - => CFormat.Printf(Out, "IsMoreSpecificType key cls1-%016llX cls2-%016llX, value %u", key.A, key.B, value); + => Out.Write($"IsMoreSpecificType key cls1-{key.A:X16} cls2-{key.B:X16}, value {value}"); public void dmpIsExactType(ulong key, uint value) - => CFormat.Printf(Out, "IsExactType key cls-%016llX, value res-%u", key, value); + => Out.Write($"IsExactType key cls-{key:X16}, value res-{value}"); public void dmpIsGenericType(ulong key, uint value) - => CFormat.Printf(Out, "IsGenericType key cls-%016llX, value res-%d", key, value); + => Out.Write($"IsGenericType key cls-{key:X16}, value res-{(int)value}"); public void dmpIsNullableType(ulong key, uint value) - => CFormat.Printf(Out, "IsNullableType key cls-%016llX, value res-%d", key, value); + => Out.Write($"IsNullableType key cls-{key:X16}, value res-{(int)value}"); public void dmpIsEnum(ulong key, DLD value) - => CFormat.Printf(Out, "IsEnum key cls-%016llX, value underlyingType-%016llX result-%u", key, value.A, value.B); + => Out.Write($"IsEnum key cls-{key:X16}, value underlyingType-{value.A:X16} result-{value.B}"); public void dmpGetCookieForInterpreterCalliSig(in GetCookieForInterpreterCalliSigValue key, DLDL value) - => CFormat.Printf(Out, "GetCookieForInterpreterCalliSig NYI"); + => Out.Write("GetCookieForInterpreterCalliSig NYI"); public void dmpErrorList(uint key, uint value) - => CFormat.Printf(Out, "ErrorList NYI"); + => Out.Write("ErrorList NYI"); public void dmpGetProfilingHandle(uint key, in Agnostic_GetProfilingHandle value) - => CFormat.Printf(Out, "GetProfilingHandle key %u, value bHookFtn-%u profHnd-%016llX bIndHnd-%u", key, value.bHookFunction, - value.ProfilerHandle, value.bIndirectedHandles); + => Out.Write($"GetProfilingHandle key {key}, value bHookFtn-{value.bHookFunction} profHnd-{value.ProfilerHandle:X16} " + + $"bIndHnd-{value.bIndirectedHandles}"); public void dmpEmbedFieldHandle(ulong key, DLDL value) - => CFormat.Printf(Out, "EmbedFieldHandle NYI"); + => Out.Write("EmbedFieldHandle NYI"); public void dmpCompareTypesForCast(DLDL key, uint value) - => CFormat.Printf(Out, "CompareTypesForCast key fromClass=%016llX, toClass=%016llx, result=%d", key.A, key.B, value); + => Out.Write($"CompareTypesForCast key fromClass={key.A:X16}, toClass={key.B:x16}, result={(int)value}"); public void dmpCompareTypesForEquality(DLDL key, uint value) - => CFormat.Printf(Out, "CompareTypesForEquality key cls1=%016llX, cls2=%016llx, result=%d", key.A, key.B, value); + => Out.Write($"CompareTypesForEquality key cls1={key.A:X16}, cls2={key.B:x16}, result={(int)value}"); public void dmpGetWasmLowering(ulong key, uint value) - => CFormat.Printf(Out, "GetWasmLowering key structHnd-%016llX, value %d ", key, value); + => Out.Write($"GetWasmLowering key structHnd-{key:X16}, value {(int)value} "); public void dmpGetRelocTypeHint(ulong key, uint value) - => CFormat.Printf(Out, "GetRelocTypeHint key tgt-%016llX, value hint-%u", key, value); + => Out.Write($"GetRelocTypeHint key tgt-{key:X16}, value hint-{value}"); public void dmpGetAddressAlignment(ulong key, uint value) - => CFormat.Printf(Out, "GetAddressAlignment key addr-%016llX, value align-%u", key, value); + => Out.Write($"GetAddressAlignment key addr-{key:X16}, value align-{value}"); public void dmpGetExpectedTargetArchitecture(uint key, uint result) - => CFormat.Printf(Out, "GetExpectedTargetArchitecture key %u, res %u", key, result); + => Out.Write($"GetExpectedTargetArchitecture key {key}, res {result}"); public void dmpDoesFieldBelongToClass(DLDL key, uint value) - => CFormat.Printf(Out, "DoesFieldBelongToClass key fld=%016llX, cls=%016llx, result=%d", key.A, key.B, value); + => Out.Write($"DoesFieldBelongToClass key fld={key.A:X16}, cls={key.B:x16}, result={(int)value}"); public void dmpGetTypeInstantiationArgument(DLD key, ulong value) { - CFormat.Printf(Out, "GetTypeInstantiationArgument key - classNonNull-%llu, index-%u, value NonNull-%llu", key.A, key.B, value); + Out.Write($"GetTypeInstantiationArgument key - classNonNull-{key.A}, index-{key.B}, value NonNull-{value}"); GetTypeInstantiationArgument.Unlock(); } public void dmpGetMethodInstantiationArgument(DLD key, ulong value) { - CFormat.Printf(Out, "GetMethodInstantiationArgument key - methodNonNull-%llu, index-%u, value NonNull-%llu", key.A, key.B, value); + Out.Write($"GetMethodInstantiationArgument key - methodNonNull-{key.A}, index-{key.B}, value NonNull-{value}"); GetMethodInstantiationArgument.Unlock(); } @@ -951,54 +888,46 @@ public void dmpPrintMethodName(ulong key, in Agnostic_PrintResult value) public void dmpGetTailCallHelpers(in Agnostic_GetTailCallHelpers key, in Agnostic_CORINFO_TAILCALL_HELPERS value) { - CFormat.Printf(Out, "GetTailCallHelpers key callToken-%s sig-%s flg-%08X", - SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.callToken), - SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INFO(key.sig, GetTailCallHelpers, SigInstHandleMap), - key.flags); - CFormat.Printf(Out, ", value result-%s flg-%08X hStoreArgs-%016llX hCallTarget-%016llX hDispatcher-%016llX", - (value.result != 0) ? "true" : "false", - value.flags, - value.hStoreArgs, - value.hCallTarget, - value.hDispatcher); + Out.Write($"GetTailCallHelpers key callToken-{SpmiDumpHelper.DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.callToken)} " + + $"sig-{SpmiDumpHelper.DumpAgnostic_CORINFO_SIG_INFO(key.sig, GetTailCallHelpers, SigInstHandleMap)} flg-{key.flags:X8}"); + Out.Write($", value result-{((value.result != 0) ? "true" : "false")} flg-{value.flags:X8} hStoreArgs-{value.hStoreArgs:X16} " + + $"hCallTarget-{value.hCallTarget:X16} hDispatcher-{value.hDispatcher:X16}"); } public void dmpGetAsyncResumptionStub(uint key, in DLDL value) - => CFormat.Printf(Out, "GetAsyncResumptionStub key-%u, hnd-%016llX, entrypoint-%016llX", key, value.A, value.B); + => Out.Write($"GetAsyncResumptionStub key-{key}, hnd-{value.A:X16}, entrypoint-{value.B:X16}"); public void dmpGetContinuationType(in Agnostic_GetContinuationTypeIn key, ulong value) - => CFormat.Printf(Out, "GetContinuationType dataSize-%016llX, objRefs-%u, handle-%016llX", - key.dataSize, key.objRefs, value); + => Out.Write($"GetContinuationType dataSize-{key.dataSize:X16}, objRefs-{key.objRefs}, handle-{value:X16}"); public void dmpUpdateEntryPointForTailCall(in Agnostic_CORINFO_CONST_LOOKUP origEntryPoint, in Agnostic_CORINFO_CONST_LOOKUP newEntryPoint) - => CFormat.Printf(Out, "UpdateEntryPointForTailcall orig=%s new=%s", - SpmiDumpHelper.DumpAgnostic_CORINFO_CONST_LOOKUP(origEntryPoint), - SpmiDumpHelper.DumpAgnostic_CORINFO_CONST_LOOKUP(newEntryPoint)); + => Out.Write($"UpdateEntryPointForTailcall orig={SpmiDumpHelper.DumpAgnostic_CORINFO_CONST_LOOKUP(origEntryPoint)} " + + $"new={SpmiDumpHelper.DumpAgnostic_CORINFO_CONST_LOOKUP(newEntryPoint)}"); public void dmpGetMethodDefFromMethod(ulong key, uint value) - => CFormat.Printf(Out, "GetMethodDefFromMethod key ftn-%016llX, value res-%u", key, value); + => Out.Write($"GetMethodDefFromMethod key ftn-{key:X16}, value res-{value}"); public void dmpGetArrayRank(ulong key, uint value) - => CFormat.Printf(Out, "GetArrayRank key %016llX, value %u", key, value); + => Out.Write($"GetArrayRank key {key:X16}, value {value}"); public void dmpGetArrayIntrinsicID(ulong key, uint value) - => CFormat.Printf(Out, "GetArrayIntrinsicID key %016llX, value %u", key, value); + => Out.Write($"GetArrayIntrinsicID key {key:X16}, value {value}"); public void dmpIsFieldStatic(ulong key, uint value) - => CFormat.Printf(Out, "IsFieldStatic key %016llX, value %u", key, value); + => Out.Write($"IsFieldStatic key {key:X16}, value {value}"); public void dmpGetArrayOrStringLength(ulong key, uint value) - => CFormat.Printf(Out, "GetArrayOrStringLength key %016llX, value %u", key, value); + => Out.Write($"GetArrayOrStringLength key {key:X16}, value {value}"); public void dmpGetSpecialCopyHelper(ulong key, ulong value) - => CFormat.Printf(Out, "getSpecialCopyHelper key %016llX, value %016llX", key, value); + => Out.Write($"getSpecialCopyHelper key {key:X16}, value {value:X16}"); public void dmpGetWasmTypeSymbol(in Agnostic_GetWasmTypeSymbol key, ulong value) - => CFormat.Printf(Out, "getWasmTypeSymbol types %u, typesSize %u, value %016llX", key.types, key.typesSize, value); + => Out.Write($"getWasmTypeSymbol types {key.types}, typesSize {key.typesSize}, value {value:X16}"); public void dmpSigInstHandleMap(uint key, ulong value) - => CFormat.Printf(Out, "SigInstHandleMap key %u, value %016llX", key, value); + => Out.Write($"SigInstHandleMap key {key}, value {value:X16}"); public void dmpCanValueClassInstancePointerEscape(ulong key, uint value) - => CFormat.Printf(Out, "CanValueClassInstancePointerEscape key ftn-%016llX, value res-%u", key, value); + => Out.Write($"CanValueClassInstancePointerEscape key ftn-{key:X16}, value res-{value}"); } diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Replay.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Replay.cs index adbe3151c06cb8..5953a2be9f3847 100644 --- a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Replay.cs +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Replay.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Internal.JitInterface; @@ -28,7 +29,8 @@ public void Reset() tempAllocations = null; } - // 'keyFormat' describes the key for the failure message, printf-style. + // 'keyFormat' describes the key for the failure message, as a composite format string of a, b, c and d. It is only + // formatted on failure, so that the lookups that succeed don't format anything. private static TItem LookupByKeyOrMiss(LightWeightMap map, TKey key, string keyFormat = "", ulong a = 0, ulong b = 0, ulong c = 0, ulong d = 0, [CallerArgumentExpression(nameof(map))] string mapName = "", [CallerArgumentExpression(nameof(key))] string keyName = "") @@ -36,13 +38,15 @@ private static TItem LookupByKeyOrMiss(LightWeightMap where TItem : unmanaged { if (map == null) - ErrorHandling.LogException(ExceptionCodes.MC, $"SuperPMI assertion failed (missing map {mapName}){CFormat.Sprintf(keyFormat, a, b, c, d)}"); + ErrorHandling.LogException(ExceptionCodes.MC, "SuperPMI assertion failed (missing map " + + $"{mapName}){string.Format(CultureInfo.InvariantCulture, keyFormat, a, b, c, d)}"); int index = map.GetIndex(key); if (index == -1) { ErrorHandling.LogException(ExceptionCodes.MC, - $"SuperPMI assertion failed (missing key \"{(keyName == "0u" ? "0" : keyName)}\" in map {mapName}){CFormat.Sprintf(keyFormat, a, b, c, d)}"); + $"SuperPMI assertion failed (missing key \"{(keyName == "0u" ? "0" : keyName)}\" in map " + + $"{mapName}){string.Format(CultureInfo.InvariantCulture, keyFormat, a, b, c, d)}"); } return map.GetItem(index); @@ -66,14 +70,15 @@ private static TItem LookupByHandle(LightWeightMap map, voi where TItem : unmanaged { ulong key = CastHandle(handle); - return LookupByKeyOrMiss(map, key, ": key %016llX", key, mapName: mapName); + return LookupByKeyOrMiss(map, key, ": key {0:X16}", key, mapName: mapName); } private static void AssertMapExists(LightWeightMapBuffer map, string keyFormat = "", ulong a = 0, ulong b = 0, [CallerArgumentExpression(nameof(map))] string mapName = "") { if (map == null) - ErrorHandling.LogException(ExceptionCodes.MC, $"SuperPMI assertion failed (missing map {mapName}){CFormat.Sprintf(keyFormat, a, b)}"); + ErrorHandling.LogException(ExceptionCodes.MC, "SuperPMI assertion failed (missing map " + + $"{mapName}){string.Format(CultureInfo.InvariantCulture, keyFormat, a, b)}"); } private static ReadOnlySpan Bytes(void* data, nuint length) => data == null ? default : new ReadOnlySpan(data, (int)length); @@ -175,7 +180,7 @@ public void repGetBoundaries(CORINFO_METHOD_STRUCT_* ftn, uint* cILOffsets, uint public CorInfoInitClassResult repInitClass(CORINFO_FIELD_STRUCT_* field, CORINFO_METHOD_STRUCT_* method, CORINFO_CONTEXT_STRUCT* context) { var key = new Agnostic_InitClass { field = CastHandle(field), method = CastHandle(method), context = CastHandle(context) }; - return (CorInfoInitClassResult)LookupByKeyOrMiss(InitClass, key, ": fld-%016llX meth-%016llX con-%016llX", key.field, key.method, key.context); + return (CorInfoInitClassResult)LookupByKeyOrMiss(InitClass, key, ": fld-{0:X16} meth-{1:X16} con-{2:X16}", key.field, key.method, key.context); } public byte* repGetMethodNameFromMetadata(CORINFO_METHOD_STRUCT_* ftn, byte** moduleName, byte** namespaceName, byte** enclosingClassNames, @@ -190,7 +195,7 @@ public CorInfoInitClassResult repInitClass(CORINFO_FIELD_STRUCT_* field, CORINFO }; Agnostic_CORINFO_METHODNAME_TOKENout value = LookupByKeyOrMiss(GetMethodNameFromMetadata, key, - ": ftn-%016llX className-%u namespaceName-%u maxEnclosingClassNames-%u", key.ftn, key.className, key.namespaceName, key.maxEnclosingClassNames); + ": ftn-{0:X16} className-{1} namespaceName-{2} maxEnclosingClassNames-{3}", key.ftn, key.className, key.namespaceName, key.maxEnclosingClassNames); byte* result = GetMethodNameFromMetadata.GetBufferPointer(value.methodName); if (moduleName != null) @@ -230,7 +235,7 @@ public CorInfoInline repCanInline(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_MET public void repResolveToken(CORINFO_RESOLVED_TOKEN* pResolvedToken, out uint exceptionCode) { Agnostic_CORINFO_RESOLVED_TOKENin key = CreateAgnostic_CORINFO_RESOLVED_TOKENin(pResolvedToken); - ResolveTokenValue value = LookupByKeyOrMiss(ResolveToken, key, ": token %x", (uint)pResolvedToken->token); + ResolveTokenValue value = LookupByKeyOrMiss(ResolveToken, key, ": token {0:x}", (uint)pResolvedToken->token); Restore_CORINFO_RESOLVED_TOKENout(pResolvedToken, value.tokenOut, ResolveToken); exceptionCode = value.exceptionCode; } @@ -249,7 +254,7 @@ public void repGetCallInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_RESOL if (pConstrainedResolvedToken != null) key.ConstrainedResolvedToken = RestoreAgnostic_CORINFO_RESOLVED_TOKEN(pConstrainedResolvedToken, GetCallInfo); - Agnostic_CORINFO_CALL_INFO value = LookupByKeyOrMiss(GetCallInfo, key, ": key %08x, %016llx", key.ResolvedToken.inValue.token, key.ResolvedToken.outValue.hClass); + Agnostic_CORINFO_CALL_INFO value = LookupByKeyOrMiss(GetCallInfo, key, ": key {0:x8}, {1:x16}", key.ResolvedToken.inValue.token, key.ResolvedToken.outValue.hClass); if (value.exceptionCode != 0) { @@ -319,7 +324,7 @@ public void repGetCallInfoFromMethodHandle(CORINFO_METHOD_STRUCT_* methodHandle, } } - ErrorHandling.LogException(ExceptionCodes.MC, CFormat.Sprintf("Didn't find key %016llX.", CastHandle(methodHandle))); + ErrorHandling.LogException(ExceptionCodes.MC, $"Didn't find key {CastHandle(methodHandle):X16}."); } public void repExpandRawHandleIntrinsic(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_GENERICHANDLE_RESULT* pResult) @@ -329,7 +334,7 @@ public void repExpandRawHandleIntrinsic(CORINFO_RESOLVED_TOKEN* pResolvedToken, ResolvedToken = CreateAgnostic_CORINFO_RESOLVED_TOKENin(pResolvedToken), hCallerHandle = CastHandle(callerHandle), }; - Agnostic_CORINFO_GENERICHANDLE_RESULT value = LookupByKeyOrMiss(ExpandRawHandleIntrinsic, key, ": key %x", (uint)pResolvedToken->token); + Agnostic_CORINFO_GENERICHANDLE_RESULT value = LookupByKeyOrMiss(ExpandRawHandleIntrinsic, key, ": key {0:x}", (uint)pResolvedToken->token); Restore_CORINFO_GENERICHANDLE_RESULT(pResult, value); } @@ -362,7 +367,7 @@ public void repExpandRawHandleIntrinsic(CORINFO_RESOLVED_TOKEN* pResolvedToken, public CORINFO_CLASS_STRUCT_* repGetBuiltinClass(CorInfoClassId classId) { uint key = (uint)classId; - return (CORINFO_CLASS_STRUCT_*)LookupByKeyOrMiss(GetBuiltinClass, key, ": key %08X", key); + return (CORINFO_CLASS_STRUCT_*)LookupByKeyOrMiss(GetBuiltinClass, key, ": key {0:X8}", key); } public CorInfoType repGetTypeForPrimitiveValueClass(CORINFO_CLASS_STRUCT_* cls) => (CorInfoType)LookupByHandle(GetTypeForPrimitiveValueClass, cls); @@ -386,7 +391,7 @@ public void repExpandRawHandleIntrinsic(CORINFO_RESOLVED_TOKEN* pResolvedToken, public bool repGetStringChar(CORINFO_OBJECT_STRUCT_* strObj, int index, ushort* charValue) { var key = new DLD { A = CastHandle(strObj), B = (uint)index }; - DD value = LookupByKeyOrMiss(GetStringChar, key, ": key %016llX", key.A); + DD value = LookupByKeyOrMiss(GetStringChar, key, ": key {0:X16}", key.A); *charValue = (ushort)value.B; return value.A != 0; } @@ -426,7 +431,7 @@ public void repGetReadyToRunDelegateCtorHelper(CORINFO_RESOLVED_TOKEN* pTargetMe public void repGetHelperFtn(CorInfoHelpFunc ftnNum, CORINFO_CONST_LOOKUP* pNativeEntrypoint, CORINFO_METHOD_STRUCT_** pMethodHandle) { uint key = (uint)ftnNum; - Agnostic_GetHelperFtn value = LookupByKeyOrMiss(GetHelperFtn, key, ": key %u", key); + Agnostic_GetHelperFtn value = LookupByKeyOrMiss(GetHelperFtn, key, ": key {0}", key); if (pNativeEntrypoint != null) *pNativeEntrypoint = RestoreCORINFO_CONST_LOOKUP(value.helperLookup); if (pMethodHandle != null) @@ -509,7 +514,7 @@ public bool fndGetFunctionEntryPoint(DLD value, out CORINFO_METHOD_STRUCT_* resu public InfoAccessType repConstructStringLiteral(CORINFO_MODULE_STRUCT_* moduleHandle, mdToken metaTok, void** ppValue) { var key = new DLD { A = CastHandle(moduleHandle), B = (uint)metaTok }; - DLD value = LookupByKeyOrMiss(ConstructStringLiteral, key, ": key %016llX", CastHandle(moduleHandle)); + DLD value = LookupByKeyOrMiss(ConstructStringLiteral, key, ": key {0:X16}", CastHandle(moduleHandle)); *ppValue = (void*)value.A; return (InfoAccessType)value.B; } @@ -535,7 +540,7 @@ public InfoAccessType repEmptyStringLiteral(void** ppValue) public CorInfoTypeWithMod repGetArgType(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_STRUCT_* args, CORINFO_CLASS_STRUCT_** vcTypeRet, out uint exceptionCode) { - AssertMapExists(GetArgType, ": key %016llX %016llX", CastHandle(sig->scope), CastHandle(args)); + AssertMapExists(GetArgType, ": key {0:X16} {1:X16}", CastHandle(sig->scope), CastHandle(args)); var key = new Agnostic_GetArgType_Key { @@ -550,7 +555,7 @@ public CorInfoTypeWithMod repGetArgType(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_ sigInst_methInst_Index = ContainsHandleMap(sig->sigInst.methInstCount, sig->sigInst.methInst, SigInstHandleMap), }; - Agnostic_GetArgType_Value value = LookupByKeyOrMiss(GetArgType, key, ": key %016llX %016llX", key.scope, key.args); + Agnostic_GetArgType_Value value = LookupByKeyOrMiss(GetArgType, key, ": key {0:X16} {1:X16}", key.scope, key.args); *vcTypeRet = (CORINFO_CLASS_STRUCT_*)value.vcTypeRet; exceptionCode = value.exceptionCode; return (CorInfoTypeWithMod)value.result; @@ -559,7 +564,7 @@ public CorInfoTypeWithMod repGetArgType(CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_ public int repGetExactClasses(CORINFO_CLASS_STRUCT_* baseType, int maxExactClasses, CORINFO_CLASS_STRUCT_** exactClsRet) { var key = new DLD { A = CastHandle(baseType), B = (uint)maxExactClasses }; - Agnostic_GetExactClassesResult value = LookupByKeyOrMiss(GetExactClasses, key, ": key %016llX %08X", key.A, key.B); + Agnostic_GetExactClassesResult value = LookupByKeyOrMiss(GetExactClasses, key, ": key {0:X16} {1:X8}", key.A, key.B); ErrorHandling.AssertCode(maxExactClasses >= value.numClasses, ExceptionCodes.ASSERT, "maxExactClasses >= value.numClasses"); byte* buffer = GetExactClasses.GetBufferPointer(value.classes); @@ -573,7 +578,7 @@ public int repGetExactClasses(CORINFO_CLASS_STRUCT_* baseType, int maxExactClass public void repGetMethodSig(CORINFO_METHOD_STRUCT_* ftn, CORINFO_SIG_INFO* sig, CORINFO_CLASS_STRUCT_* memberParent) { var key = new DLDL { A = CastHandle(ftn), B = CastHandle(memberParent) }; - Agnostic_CORINFO_SIG_INFO value = LookupByKeyOrMiss(GetMethodSig, key, ": key ftn-%016llX prt-%016llX", key.A, key.B); + Agnostic_CORINFO_SIG_INFO value = LookupByKeyOrMiss(GetMethodSig, key, ": key ftn-{0:X16} prt-{1:X16}", key.A, key.B); *sig = Restore_CORINFO_SIG_INFO(value, GetMethodSig, SigInstHandleMap, cr.MemoryTracker); } @@ -590,7 +595,7 @@ public void repGetMethodSig(CORINFO_METHOD_STRUCT_* ftn, CORINFO_SIG_INFO* sig, sigInst_methInst_Index = ContainsHandleMap(sig->sigInst.methInstCount, sig->sigInst.methInst, SigInstHandleMap), }; - Agnostic_GetArgClass_Value value = LookupByKeyOrMiss(GetArgClass, key, ": key %016llX %016llX", key.scope, key.args); + Agnostic_GetArgClass_Value value = LookupByKeyOrMiss(GetArgClass, key, ": key {0:X16} {1:X16}", key.scope, key.args); exceptionCode = value.exceptionCode; return (CORINFO_CLASS_STRUCT_*)value.result; } @@ -600,7 +605,7 @@ public void repGetMethodSig(CORINFO_METHOD_STRUCT_* ftn, CORINFO_SIG_INFO* sig, public bool repGetMethodInfo(CORINFO_METHOD_STRUCT_* ftn, CORINFO_METHOD_INFO* info, CORINFO_CONTEXT_STRUCT* context, out uint exceptionCode) { var key = new DLDL { A = CastHandle(ftn), B = CastHandle(context) }; - Agnostic_GetMethodInfo value = LookupByKeyOrMiss(GetMethodInfo, key, ": key %016llX", key.A); + Agnostic_GetMethodInfo value = LookupByKeyOrMiss(GetMethodInfo, key, ": key {0:X16}", key.A); if (value.result != 0) Restore_CORINFO_METHOD_INFO(info, value.info, GetMethodInfo); exceptionCode = value.exceptionCode; @@ -610,7 +615,7 @@ public bool repGetMethodInfo(CORINFO_METHOD_STRUCT_* ftn, CORINFO_METHOD_INFO* i public bool repHaveSameMethodDefinition(CORINFO_METHOD_STRUCT_* methHnd1, CORINFO_METHOD_STRUCT_* methHnd2) { var key = new DLDL { A = CastHandle(methHnd1), B = CastHandle(methHnd2) }; - return LookupByKeyOrMiss(HaveSameMethodDefinition, key, "key %016llX, %016llX", key.A, key.B) != 0; + return LookupByKeyOrMiss(HaveSameMethodDefinition, key, "key {0:X16}, {1:X16}", key.A, key.B) != 0; } public CORINFO_CLASS_STRUCT_* repGetTypeDefinition(CORINFO_CLASS_STRUCT_* cls) => (CORINFO_CLASS_STRUCT_*)LookupByHandle(GetTypeDefinition, cls); @@ -639,10 +644,10 @@ public void repEmbedGenericHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken, bool f public void repGetEHinfo(CORINFO_METHOD_STRUCT_* ftn, uint EHnumber, CORINFO_EH_CLAUSE* clause) { - AssertMapExists(GetEHinfo, ": key %016llX", CastHandle(ftn)); + AssertMapExists(GetEHinfo, ": key {0:X16}", CastHandle(ftn)); var key = new DLD { A = CastHandle(ftn), B = EHnumber }; - Agnostic_CORINFO_EH_CLAUSE value = LookupByKeyOrMiss(GetEHinfo, key, ": key %016llX", CastHandle(ftn)); + Agnostic_CORINFO_EH_CLAUSE value = LookupByKeyOrMiss(GetEHinfo, key, ": key {0:X16}", CastHandle(ftn)); clause->Flags = (CORINFO_EH_CLAUSE_FLAGS)value.Flags; clause->TryOffset = value.TryOffset; clause->TryLength = value.TryLength; @@ -671,7 +676,7 @@ public bool repResolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) if (key.pResolvedTokenVirtualMethodNonNull != 0) key.pResolvedTokenVirtualMethod = StoreAgnostic_CORINFO_RESOLVED_TOKEN(info->pResolvedTokenVirtualMethod, ResolveToken); - Agnostic_ResolveVirtualMethodResult result = LookupByKeyOrMiss(ResolveVirtualMethod, key, ": %016llX-%016llX-%016llX-%08X", + Agnostic_ResolveVirtualMethodResult result = LookupByKeyOrMiss(ResolveVirtualMethod, key, ": {0:X16}-{1:X16}-{2:X16}-{3:X8}", key.virtualMethod, key.objClass, key.context, key.pResolvedTokenVirtualMethodNonNull); info->devirtualizedMethod = (CORINFO_METHOD_STRUCT_*)result.devirtualizedMethod; @@ -707,7 +712,7 @@ public bool repResolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) public void repGetFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult) { - AssertMapExists(GetFieldInfo, ": key %x", (uint)pResolvedToken->token); + AssertMapExists(GetFieldInfo, ": key {0:x}", (uint)pResolvedToken->token); var key = new Agnostic_GetFieldInfo { @@ -733,7 +738,7 @@ public void repGetFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METH if (keyIndex != -1) Logger.LogDebug("Sparse - repGetFieldInfo found value with inverted CORINFO_ACCESS_INLINECHECK"); else - ErrorHandling.LogException(ExceptionCodes.MC, CFormat.Sprintf("repGetFieldInfo: didn't find %x", (uint)pResolvedToken->token)); + ErrorHandling.LogException(ExceptionCodes.MC, $"repGetFieldInfo: didn't find {(uint)pResolvedToken->token:x}"); } } @@ -752,13 +757,13 @@ public void repGetFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METH public uint repGetThreadLocalFieldInfo(CORINFO_FIELD_STRUCT_* field, bool isGCType) { var key = new DLD { A = CastHandle(field), B = isGCType ? 0u : 1u }; - return LookupByKeyOrMiss(GetThreadLocalFieldInfo, key, ": key hnd-%016llX, gctype-%u", key.A, key.B); + return LookupByKeyOrMiss(GetThreadLocalFieldInfo, key, ": key hnd-{0:X16}, gctype-{1}", key.A, key.B); } public void repGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) { uint key = 0; - Agnostic_GetThreadLocalStaticBlocksInfo value = LookupByKeyOrMiss(GetThreadLocalStaticBlocksInfo, key, ": key %u", key); + Agnostic_GetThreadLocalStaticBlocksInfo value = LookupByKeyOrMiss(GetThreadLocalStaticBlocksInfo, key, ": key {0}", key); pInfo->tlsIndex = RestoreCORINFO_CONST_LOOKUP(value.tlsIndex); pInfo->tlsGetAddrFtnPtr = (nuint)value.tlsGetAddrFtnPtr; pInfo->tlsIndexObject = (nuint)value.tlsIndexObject; @@ -772,7 +777,7 @@ public void repGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* public void repGetThreadLocalStaticInfo_NativeAOT(CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo) { ulong key = 1; - Agnostic_GetThreadStaticInfo_NativeAOT value = LookupByKeyOrMiss(GetThreadLocalStaticInfo_NativeAOT, key, ": key %016llX", key); + Agnostic_GetThreadStaticInfo_NativeAOT value = LookupByKeyOrMiss(GetThreadLocalStaticInfo_NativeAOT, key, ": key {0:X16}", key); pInfo->tlsRootObject = RestoreCORINFO_CONST_LOOKUP(value.tlsRootObject); pInfo->tlsIndexObject = RestoreCORINFO_CONST_LOOKUP(value.tlsIndexObject); pInfo->offsetOfThreadLocalStoragePointer = value.offsetOfThreadLocalStoragePointer; @@ -791,7 +796,7 @@ public void repGetThreadLocalStaticInfo_NativeAOT(CORINFO_THREAD_STATIC_INFO_NAT public bool repGetStaticFieldContent(CORINFO_FIELD_STRUCT_* field, byte* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects) { var key = new DLDDD { A = CastHandle(field), B = (uint)bufferSize, C = ignoreMovableObjects ? 1u : 0u, D = (uint)valueOffset }; - DD value = LookupByKeyOrMiss(GetStaticFieldContent, key, ": key %016llX", key.A); + DD value = LookupByKeyOrMiss(GetStaticFieldContent, key, ": key {0:X16}", key.A); if (buffer != null && value.A != 0) CopyContent(GetStaticFieldContent.GetBufferPointer(value.B), buffer, bufferSize); return value.A != 0; @@ -800,7 +805,7 @@ public bool repGetStaticFieldContent(CORINFO_FIELD_STRUCT_* field, byte* buffer, public bool repGetObjectContent(CORINFO_OBJECT_STRUCT_* obj, byte* buffer, int bufferSize, int valueOffset) { var key = new DLDD { A = CastHandle(obj), B = (uint)bufferSize, C = (uint)valueOffset }; - DD value = LookupByKeyOrMiss(GetObjectContent, key, ": key %016llX", key.A); + DD value = LookupByKeyOrMiss(GetObjectContent, key, ": key {0:X16}", key.A); if (buffer != null && value.A != 0) CopyContent(GetObjectContent.GetBufferPointer(value.B), buffer, bufferSize); return value.A != 0; @@ -815,7 +820,7 @@ private static void CopyContent(byte* srcBuffer, byte* buffer, int bufferSize) public CORINFO_CLASS_STRUCT_* repGetStaticFieldCurrentClass(CORINFO_FIELD_STRUCT_* field, byte* pIsSpeculative) { var key = new DLD { A = CastHandle(field), B = pIsSpeculative != null ? 1u : 0u }; - Agnostic_GetStaticFieldCurrentClass value = LookupByKeyOrMiss(GetStaticFieldCurrentClass, key, ": key %016llX", key.A); + Agnostic_GetStaticFieldCurrentClass value = LookupByKeyOrMiss(GetStaticFieldCurrentClass, key, ": key {0:X16}", key.A); if (pIsSpeculative != null) *pIsSpeculative = value.isSpeculative; return (CORINFO_CLASS_STRUCT_*)value.classHandle; @@ -832,19 +837,19 @@ public uint repGetClassGClayout(CORINFO_CLASS_STRUCT_* cls, byte* gcPtrs) public uint repGetClassAlignmentRequirement(CORINFO_CLASS_STRUCT_* cls, bool fDoubleAlignHint) { var key = new DLD { A = CastHandle(cls), B = fDoubleAlignHint ? 1u : 0u }; - return LookupByKeyOrMiss(GetClassAlignmentRequirement, key, ": key %016llX", key.A); + return LookupByKeyOrMiss(GetClassAlignmentRequirement, key, ": key {0:X16}", key.A); } public CorInfoIsAccessAllowedResult repCanAccessClass(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_HELPER_DESC* pAccessHelper) { - AssertMapExists(CanAccessClass, ": key %016llX", CastHandle(pResolvedToken->hClass)); + AssertMapExists(CanAccessClass, ": key {0:X16}", CastHandle(pResolvedToken->hClass)); var key = new Agnostic_CanAccessClassIn { ResolvedToken = RestoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, CanAccessClass), callerHandle = CastHandle(callerHandle), }; - Agnostic_CanAccessClassOut value = LookupByKeyOrMiss(CanAccessClass, key, ": key %016llX", CastHandle(pResolvedToken->hClass)); + Agnostic_CanAccessClassOut value = LookupByKeyOrMiss(CanAccessClass, key, ": key {0:X16}", CastHandle(pResolvedToken->hClass)); *pAccessHelper = RestoreCORINFO_HELPER_DESC(value.AccessHelper); return (CorInfoIsAccessAllowedResult)value.result; } @@ -852,7 +857,7 @@ public CorInfoIsAccessAllowedResult repCanAccessClass(CORINFO_RESOLVED_TOKEN* pR public CorInfoHelpFunc repGetCastingHelper(CORINFO_RESOLVED_TOKEN* pResolvedToken, bool fThrowing) { var key = new Agnostic_GetCastingHelper { hClass = CastHandle(pResolvedToken->hClass), fThrowing = fThrowing ? 1u : 0u }; - return (CorInfoHelpFunc)LookupByKeyOrMiss(GetCastingHelper, key, ": key %016llX", key.hClass); + return (CorInfoHelpFunc)LookupByKeyOrMiss(GetCastingHelper, key, ": key {0:X16}", key.hClass); } public CORINFO_MODULE_STRUCT_* repEmbedModuleHandle(CORINFO_MODULE_STRUCT_* handle, void** ppIndirection) @@ -880,7 +885,7 @@ public CorInfoHelpFunc repGetCastingHelper(CORINFO_RESOLVED_TOKEN* pResolvedToke return handle; } - DLDL value = LookupByKeyOrMiss(EmbedClassHandle, key, ": key %016llX", key); + DLDL value = LookupByKeyOrMiss(EmbedClassHandle, key, ": key {0:X16}", key); *ppIndirection = (void*)value.A; return (CORINFO_CLASS_STRUCT_*)value.B; } @@ -1043,7 +1048,7 @@ public bool repGetIsClassInitedFlagAddress(CORINFO_CLASS_STRUCT_* cls, CORINFO_C public bool repGetStaticBaseAddress(CORINFO_CLASS_STRUCT_* cls, bool isGc, CORINFO_CONST_LOOKUP* addr) { var key = new DLD { A = CastHandle(cls), B = isGc ? 1u : 0u }; - Agnostic_GetStaticBaseAddress value = LookupByKeyOrMiss(GetStaticBaseAddress, key, ": key %016llX", key.A); + Agnostic_GetStaticBaseAddress value = LookupByKeyOrMiss(GetStaticBaseAddress, key, ": key {0:X16}", key.A); addr->accessType = (InfoAccessType)value.addr.accessType; addr->addr = (void*)value.addr.handle; return value.result != 0; @@ -1084,7 +1089,7 @@ public void repGetLocationOfThisType(CORINFO_METHOD_STRUCT_* context, CORINFO_LO DelegateCtorArgs* pCtorData) { var key = new Agnostic_GetDelegateCtorIn { methHnd = CastHandle(methHnd), clsHnd = CastHandle(clsHnd), targetMethodHnd = CastHandle(targetMethodHnd) }; - Agnostic_GetDelegateCtorOut value = LookupByKeyOrMiss(GetDelegateCtor, key, ": key %016llX", key.methHnd); + Agnostic_GetDelegateCtorOut value = LookupByKeyOrMiss(GetDelegateCtor, key, ": key {0:X16}", key.methHnd); pCtorData->pMethod = (void*)value.CtorData.pMethod; pCtorData->pArg3 = (void*)value.CtorData.pArg3; pCtorData->pArg4 = (void*)value.CtorData.pArg4; @@ -1099,13 +1104,13 @@ public void repGetFunctionFixedEntryPoint(CORINFO_METHOD_STRUCT_* ftn, bool isUn public CORINFO_FIELD_STRUCT_* repGetFieldInClass(CORINFO_CLASS_STRUCT_* clsHnd, int num) { var key = new DLD { A = CastHandle(clsHnd), B = (uint)num }; - return (CORINFO_FIELD_STRUCT_*)LookupByKeyOrMiss(GetFieldInClass, key, ": key %016llX", key.A); + return (CORINFO_FIELD_STRUCT_*)LookupByKeyOrMiss(GetFieldInClass, key, ": key {0:X16}", key.A); } public GetTypeLayoutResult repGetTypeLayout(CORINFO_CLASS_STRUCT_* typeHnd, CORINFO_TYPE_LAYOUT_NODE* nodes, nuint* numNodes) { ulong key = CastHandle(typeHnd); - Agnostic_GetTypeLayoutResult value = LookupByKeyOrMiss(GetTypeLayout, key, ": key type-%016llX", key); + Agnostic_GetTypeLayoutResult value = LookupByKeyOrMiss(GetTypeLayout, key, ": key type-{0:X16}", key); var result = (GetTypeLayoutResult)value.result; if (result == GetTypeLayoutResult.Failure) @@ -1123,7 +1128,7 @@ public GetTypeLayoutResult repGetTypeLayout(CORINFO_CLASS_STRUCT_* typeHnd, CORI public CorInfoType repGetFieldType(CORINFO_FIELD_STRUCT_* field, CORINFO_CLASS_STRUCT_** structType, CORINFO_CLASS_STRUCT_* fieldOwnerHint) { var key = new DLDL { A = CastHandle(field), B = CastHandle(fieldOwnerHint) }; - DLD value = LookupByKeyOrMiss(GetFieldType, key, ": key %016llX", key.A); + DLD value = LookupByKeyOrMiss(GetFieldType, key, ": key {0:X16}", key.A); if (structType != null) *structType = (CORINFO_CLASS_STRUCT_*)value.A; return (CorInfoType)value.B; @@ -1138,7 +1143,7 @@ public bool repSatisfiesMethodConstraints(CORINFO_CLASS_STRUCT_* parent, CORINFO public int repGetStringLiteral(CORINFO_MODULE_STRUCT_* module, uint metaTOK, char* buffer, int bufferSize, int startIndex) { var key = new DLDDD { A = CastHandle(module), B = metaTOK, C = (uint)bufferSize, D = (uint)startIndex }; - DD value = LookupByKeyOrMiss(GetStringLiteral, key, ": key handle-%016llX token-%X bufferSize-%d startIndex-%d", key.A, key.B, key.C, key.D); + DD value = LookupByKeyOrMiss(GetStringLiteral, key, ": key handle-{0:X16} token-{1:X} bufferSize-{2} startIndex-{3}", key.A, key.B, key.C, key.D); int srcBufferLength = (int)value.A; if (buffer != null && srcBufferLength > 0) @@ -1154,7 +1159,7 @@ public int repGetStringLiteral(CORINFO_MODULE_STRUCT_* module, uint metaTOK, cha public bool repCanCast(CORINFO_CLASS_STRUCT_* child, CORINFO_CLASS_STRUCT_* parent) { var key = new DLDL { A = CastHandle(child), B = CastHandle(parent) }; - return LookupByKeyOrMiss(CanCast, key, ": key %016llX %016llX", key.A, key.B) != 0; + return LookupByKeyOrMiss(CanCast, key, ": key {0:X16} {1:X16}", key.A, key.B) != 0; } public CorInfoType repGetChildType(CORINFO_CLASS_STRUCT_* clsHnd, CORINFO_CLASS_STRUCT_** clsRet) @@ -1192,13 +1197,13 @@ public bool repCanTailCall(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STR exactCalleeHnd = CastHandle(exactCalleeHnd), fIsTailPrefix = fIsTailPrefix ? (ushort)1 : (ushort)0, }; - return LookupByKeyOrMiss(CanTailCall, key, ": key %016llX", key.callerHnd) != 0; + return LookupByKeyOrMiss(CanTailCall, key, ": key {0:X16}", key.callerHnd) != 0; } public void repFindCallSiteSig(CORINFO_MODULE_STRUCT_* module, uint methTOK, CORINFO_CONTEXT_STRUCT* context, CORINFO_SIG_INFO* sig) { var key = new Agnostic_FindCallSiteSig { module = CastHandle(module), methTok = methTOK, context = CastHandle(context) }; - Agnostic_CORINFO_SIG_INFO value = LookupByKeyOrMiss(FindCallSiteSig, key, ": key %08X", key.methTok); + Agnostic_CORINFO_SIG_INFO value = LookupByKeyOrMiss(FindCallSiteSig, key, ": key {0:X8}", key.methTok); *sig = Restore_CORINFO_SIG_INFO(value, FindCallSiteSig, SigInstHandleMap, cr.MemoryTracker); } @@ -1337,7 +1342,7 @@ public HRESULT repGetPgoInstrumentationResults(CORINFO_METHOD_STRUCT_* ftnHnd, P public bool repIsMoreSpecificType(CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2) { var key = new DLDL { A = CastHandle(cls1), B = CastHandle(cls2) }; - return LookupByKeyOrMiss(IsMoreSpecificType, key, ": key %016llX %016llX", key.A, key.B) != 0; + return LookupByKeyOrMiss(IsMoreSpecificType, key, ": key {0:X16} {1:X16}", key.A, key.B) != 0; } public bool repIsExactType(CORINFO_CLASS_STRUCT_* cls) => LookupByHandle(IsExactType, cls) != 0; @@ -1387,13 +1392,13 @@ public void repGetProfilingHandle(bool* pbHookFunction, void** pProfilerHandle, public TypeCompareState repCompareTypesForCast(CORINFO_CLASS_STRUCT_* fromClass, CORINFO_CLASS_STRUCT_* toClass) { var key = new DLDL { A = CastHandle(fromClass), B = CastHandle(toClass) }; - return (TypeCompareState)LookupByKeyOrMiss(CompareTypesForCast, key, ": key %016llX %016llX", key.A, key.B); + return (TypeCompareState)LookupByKeyOrMiss(CompareTypesForCast, key, ": key {0:X16} {1:X16}", key.A, key.B); } public TypeCompareState repCompareTypesForEquality(CORINFO_CLASS_STRUCT_* cls1, CORINFO_CLASS_STRUCT_* cls2) { var key = new DLDL { A = CastHandle(cls1), B = CastHandle(cls2) }; - return (TypeCompareState)LookupByKeyOrMiss(CompareTypesForEquality, key, ": key %016llX %016llX", key.A, key.B); + return (TypeCompareState)LookupByKeyOrMiss(CompareTypesForEquality, key, ": key {0:X16} {1:X16}", key.A, key.B); } public bool repGetSystemVAmd64PassStructInRegisterDescriptor(CORINFO_CLASS_STRUCT_* structHnd, SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr) @@ -1463,13 +1468,13 @@ public uint repGetAddressAlignment(void* address) public uint repGetExpectedTargetArchitecture() { uint key = 0; - return LookupByKeyOrMiss(GetExpectedTargetArchitecture, key, ": key %08X", key); + return LookupByKeyOrMiss(GetExpectedTargetArchitecture, key, ": key {0:X8}", key); } public byte* repGetClassNameFromMetadata(CORINFO_CLASS_STRUCT_* cls, byte** namespaceName) { var key = new DLD { A = CastHandle(cls), B = namespaceName != null ? 1u : 0u }; - DD value = LookupByKeyOrMiss(GetClassNameFromMetadata, key, " : key cls-%016llX hasNs-%u", key.A, key.B); + DD value = LookupByKeyOrMiss(GetClassNameFromMetadata, key, " : key cls-{0:X16} hasNs-{1}", key.A, key.B); if (namespaceName != null) *namespaceName = GetClassNameFromMetadata.GetBufferPointer(value.B); return GetClassNameFromMetadata.GetBufferPointer(value.A); @@ -1493,7 +1498,7 @@ public nuint repPrint(string name, LightWeightMap m { int index = map?.GetIndex(handle) ?? -1; if (index == -1) - LookupByKeyOrMiss(map, handle, ": map " + name + " key %016llx", handle, mapName: "map", keyName: "handle"); + LookupByKeyOrMiss(map, handle, ": map " + name + " key {0:x16}", handle, mapName: "map", keyName: "handle"); Agnostic_PrintResult res = map.GetItem(index); if (pRequiredBufferSize != null) @@ -1667,7 +1672,7 @@ public int repGetIntConfigValue(byte* name, int defaultValue) types = (uint)GetWasmTypeSymbol.Contains(Bytes(types, (nuint)sizeof(CorInfoWasmType) * typesSize)), typesSize = (uint)typesSize, }; - return (CORINFO_WASM_TYPE_SYMBOL_STRUCT_*)LookupByKeyOrMiss(GetWasmTypeSymbol, key, ": types %u, typesSize %u", key.types, key.typesSize); + return (CORINFO_WASM_TYPE_SYMBOL_STRUCT_*)LookupByKeyOrMiss(GetWasmTypeSymbol, key, ": types {0}, typesSize {1}", key.types, key.typesSize); } public bool repCanValueClassInstancePointerEscape(CORINFO_METHOD_STRUCT_* ftn) => LookupByHandle(CanValueClassInstancePointerEscape, ftn) != 0; diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/SpmiDumpHelper.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/SpmiDumpHelper.cs index 1a2ab2f1e13de5..4858d98815b143 100644 --- a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/SpmiDumpHelper.cs +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/SpmiDumpHelper.cs @@ -56,27 +56,27 @@ public static class SpmiDumpHelper private const int MaxHandleArrayDisplayElems = 5; public static string DumpAgnostic_CORINFO_RESOLVED_TOKENin(in Agnostic_CORINFO_RESOLVED_TOKENin tokenIn) - => CFormat.Sprintf("tc-%016llX ts-%016llX tok-%08X tt-%u", tokenIn.tokenContext, tokenIn.tokenScope, tokenIn.token, tokenIn.tokenType); + => $"tc-{tokenIn.tokenContext:X16} ts-{tokenIn.tokenScope:X16} tok-{tokenIn.token:X8} tt-{tokenIn.tokenType}"; public static string DumpAgnostic_CORINFO_RESOLVED_TOKENout(in Agnostic_CORINFO_RESOLVED_TOKENout tokenOut) - => CFormat.Sprintf("cls-%016llX meth-%016llX fld-%016llX ti-%u ts-%u mi-%u ms-%u", tokenOut.hClass, tokenOut.hMethod, tokenOut.hField, - tokenOut.pTypeSpec_Index, tokenOut.cbTypeSpec, tokenOut.pMethodSpec_Index, tokenOut.cbMethodSpec); + => $"cls-{tokenOut.hClass:X16} meth-{tokenOut.hMethod:X16} fld-{tokenOut.hField:X16} ti-{tokenOut.pTypeSpec_Index} " + + $"ts-{tokenOut.cbTypeSpec} mi-{tokenOut.pMethodSpec_Index} ms-{tokenOut.cbMethodSpec}"; public static string DumpAgnostic_CORINFO_RESOLVED_TOKEN(in Agnostic_CORINFO_RESOLVED_TOKEN token) => DumpAgnostic_CORINFO_RESOLVED_TOKENin(token.inValue) + " " + DumpAgnostic_CORINFO_RESOLVED_TOKENout(token.outValue); public static string DumpAgnostic_CORINFO_LOOKUP_KIND(in Agnostic_CORINFO_LOOKUP_KIND lookupKind) - => CFormat.Sprintf("nrl-%u rlk-%u", lookupKind.needsRuntimeLookup, lookupKind.runtimeLookupKind); + => $"nrl-{lookupKind.needsRuntimeLookup} rlk-{lookupKind.runtimeLookupKind}"; public static string DumpAgnostic_CORINFO_CONST_LOOKUP(in Agnostic_CORINFO_CONST_LOOKUP constLookup) - => CFormat.Sprintf("at-%u handle/address-%016llX", constLookup.accessType, constLookup.handle); + => $"at-{constLookup.accessType} handle/address-{constLookup.handle:X16}"; public static string DumpAgnostic_CORINFO_RUNTIME_LOOKUP(in Agnostic_CORINFO_RUNTIME_LOOKUP lookup) { - var sb = new StringBuilder(CFormat.Sprintf(" sig-%016llX hlp-%u ind-%u tfn-%u so-%u { ", lookup.signature, lookup.helper, - lookup.indirections, lookup.testForNull, lookup.sizeOffset)); + var sb = new StringBuilder($" sig-{lookup.signature:X16} hlp-{lookup.helper} ind-{lookup.indirections} tfn-{lookup.testForNull} " + + $"so-{lookup.sizeOffset} {{ "); foreach (ulong offset in lookup.offsets) - sb.Append(CFormat.Sprintf("%016llX ", offset)); + sb.Append($"{offset:X16} "); sb.Append('}'); return sb.ToString(); } @@ -94,7 +94,7 @@ public static string DumpPSig(uint pSig_Index, uint cbSig, LightWei where TKey : unmanaged where TItem : unmanaged { - var sb = new StringBuilder(CFormat.Sprintf("cbSig-%u, si-%08X", cbSig, pSig_Index)); + var sb = new StringBuilder($"cbSig-{cbSig}, si-{pSig_Index:X8}"); // pSig_Index is usually -1 without a signature, but can be 0 in error cases where it is never // consulted, so only look at the buffer when there is a size. @@ -134,13 +134,13 @@ public static string DumpAgnostic_CORINFO_SIG_INFO(in Agnostic_CORI where TKey : unmanaged where TItem : unmanaged { - var sb = new StringBuilder(CFormat.Sprintf("{callConv-%08X retTypeClass-%016llX retTypeSigClass-%016llX retType-%08X(%s) flg-%08X na-%u", - sigInfo.callConv, sigInfo.retTypeClass, sigInfo.retTypeSigClass, sigInfo.retType, DumpStrings.toString_CorInfoType(sigInfo.retType), - sigInfo.flags, sigInfo.numArgs)); + var sb = new StringBuilder($"{{callConv-{sigInfo.callConv:X8} retTypeClass-{sigInfo.retTypeClass:X16} " + + $"retTypeSigClass-{sigInfo.retTypeSigClass:X16} retType-{sigInfo.retType:X8}({DumpStrings.toString_CorInfoType(sigInfo.retType)}) " + + $"flg-{sigInfo.flags:X8} na-{sigInfo.numArgs}"); FormatAgnostic_CORINFO_SIG_INST_Element(sb, " ", "cc", "ci", sigInfo.sigInst_classInstCount, sigInfo.sigInst_classInst_Index, handleMap); FormatAgnostic_CORINFO_SIG_INST_Element(sb, " ", "mc", "mi", sigInfo.sigInst_methInstCount, sigInfo.sigInst_methInst_Index, handleMap); - sb.Append(CFormat.Sprintf(" args-%016llX sig-%s msig-%016llX scp-%016llX tok-%08X}", sigInfo.args, - DumpPSig(sigInfo.pSig_Index, sigInfo.cbSig, buffers), sigInfo.methodSignature, sigInfo.scope, sigInfo.token)); + sb.Append($" args-{sigInfo.args:X16} sig-{DumpPSig(sigInfo.pSig_Index, sigInfo.cbSig, buffers)} msig-{sigInfo.methodSignature:X16} " + + $"scp-{sigInfo.scope:X16} tok-{sigInfo.token:X8}}}"); return sb.ToString(); } @@ -155,7 +155,7 @@ public static string DumpAgnostic_CORINFO_SIG_INST_Element(string prefixStr, str private static void FormatAgnostic_CORINFO_SIG_INST_Element(StringBuilder sb, string prefixStr, string instCountPrefixStr, string instIndexPrefixStr, uint handleInstCount, uint handleInstIndex, DenseLightWeightMap handleMap) { - sb.Append(CFormat.Sprintf("%s%s-%u %s-%u ", prefixStr, instCountPrefixStr, handleInstCount, instIndexPrefixStr, handleInstIndex)); + sb.Append($"{prefixStr}{instCountPrefixStr}-{handleInstCount} {instIndexPrefixStr}-{handleInstIndex} "); FormatHandleArray(sb, handleMap, handleInstCount, handleInstIndex); } @@ -165,7 +165,7 @@ private static void FormatHandleArray(StringBuilder sb, DenseLightWeightMap CFormat.Sprintf("HCS%d %d CCS%d %d RDS%d %d xcpnt%d %d HCB %p CCB %p RDB %p ohcb %p occb %p odb %p", - n, hotCodeSize, n, coldCodeSize, n, roDataSize1, n, xcptnsCount, (ulong)hotCodeBlock, (ulong)coldCodeBlock, (ulong)roDataBlock, - CastHandle(origHotCodeBlock), CastHandle(origColdCodeBlock), CastHandle(origRoDataBlock1)); + public readonly string Describe(int n) => $"HCS{n} {hotCodeSize} CCS{n} {coldCodeSize} RDS{n} {roDataSize1} xcpnt{n} {xcptnsCount} HCB " + + $"0x{(ulong)hotCodeBlock:x} CCB 0x{(ulong)coldCodeBlock:x} RDB 0x{(ulong)roDataBlock:x} ohcb 0x{CastHandle(origHotCodeBlock):x} occb " + + $"0x{CastHandle(origColdCodeBlock):x} odb 0x{CastHandle(origRoDataBlock1):x}"; // Fixes up the code with the recorded relocations, for the original base addresses. public readonly void ApplyRelocs(MethodContext mc, CompileResult cr) diff --git a/src/coreclr/tools/superpmi/managed/superpmi/Output.cs b/src/coreclr/tools/superpmi/managed/superpmi/Output.cs index db054ba10e0532..bf253e9235ee35 100644 --- a/src/coreclr/tools/superpmi/managed/superpmi/Output.cs +++ b/src/coreclr/tools/superpmi/managed/superpmi/Output.cs @@ -29,8 +29,6 @@ public static FileWriter CreateNew(string path) public void Print(string value) => _writer.Write(value); - public void Printf(string format, params object[] args) => _writer.Write(CFormat.Sprintf(format, args)); - public void PrintQuotedCsvField(string value) => _writer.Write($"\"{value.Replace("\"", "\"\"")}\""); public void Dispose() => _writer.Dispose(); diff --git a/src/coreclr/tools/superpmi/managed/superpmi/ParallelReplay.cs b/src/coreclr/tools/superpmi/managed/superpmi/ParallelReplay.cs index 7ed2d8039c9cf0..b215615aa2e0e2 100644 --- a/src/coreclr/tools/superpmi/managed/superpmi/ParallelReplay.cs +++ b/src/coreclr/tools/superpmi/managed/superpmi/ParallelReplay.cs @@ -235,12 +235,12 @@ public static int Run(Options o, string program) if (!usageError) { if (o.applyDiff) - Logger.LogInfo(CFormat.Sprintf(Replay.AsmDiffsSummaryFormatString, loaded, jitted, failed, excluded, missing, diffs)); + Logger.LogInfo(Replay.AsmDiffsSummary(loaded, jitted, failed, excluded, missing, diffs)); else - Logger.LogInfo(CFormat.Sprintf(Replay.SummaryFormatString, loaded, jitted, failed, excluded, missing)); + Logger.LogInfo(Replay.Summary(loaded, jitted, failed, excluded, missing)); } - Logger.LogVerbose(CFormat.Sprintf("Total time: %fms", st.Elapsed.TotalMilliseconds)); + Logger.LogVerbose($"Total time: {st.Elapsed.TotalMilliseconds:F6}ms"); } if (!o.skipCleanup) diff --git a/src/coreclr/tools/superpmi/managed/superpmi/Replay.cs b/src/coreclr/tools/superpmi/managed/superpmi/Replay.cs index 8722d6dda087e7..a34d51eb9089a0 100644 --- a/src/coreclr/tools/superpmi/managed/superpmi/Replay.cs +++ b/src/coreclr/tools/superpmi/managed/superpmi/Replay.cs @@ -12,8 +12,12 @@ internal static class Replay // Parallel mode parses these status lines from the child processes. They must all start with the same // fixed prefix, to quickly tell when to parse a line fully. public const string AllFormatStringFixedPrefix = "Loaded "; - public const string SummaryFormatString = "Loaded %d Jitted %d FailedCompile %d Excluded %d Missing %d"; - public const string AsmDiffsSummaryFormatString = "Loaded %d Jitted %d FailedCompile %d Excluded %d Missing %d Diffs %d"; + + public static string Summary(int loaded, int jitted, int failed, int excluded, int missing) + => $"Loaded {loaded} Jitted {jitted} FailedCompile {failed} Excluded {excluded} Missing {missing}"; + + public static string AsmDiffsSummary(int loaded, int jitted, int failed, int excluded, int missing, int diffs) + => $"{Summary(loaded, jitted, failed, excluded, missing)} Diffs {diffs}"; private enum NearDifferResult { @@ -172,8 +176,8 @@ public static int Run(string[] args) Stopwatch st3 = Stopwatch.StartNew(); ReplayResults res = jit.CompileMethod(mc, mcIndex, collectThroughput); st3.Stop(); - Logger.LogDebug(CFormat.Sprintf("Method %d compiled%s in %fms, result %d", mcIndex, o.nameOfJit2 == null ? "" : " by JIT1", - st3.Elapsed.TotalMilliseconds, (int)res.Result)); + Logger.LogDebug($"Method {mcIndex} compiled{(o.nameOfJit2 == null ? "" : " by JIT1")} in {st3.Elapsed.TotalMilliseconds:F6}ms, " + + $"result {(int)res.Result}"); if (res.Result == ReplayResult.Success) { @@ -209,7 +213,7 @@ public static int Run(string[] args) Stopwatch st4 = Stopwatch.StartNew(); res2 = jit2.CompileMethod(mc, mcIndex, collectThroughput); st4.Stop(); - Logger.LogDebug(CFormat.Sprintf("Method %d compiled by JIT2 in %fms, result %d", mcIndex, st4.Elapsed.TotalMilliseconds, (int)res2.Result)); + Logger.LogDebug($"Method {mcIndex} compiled by JIT2 in {st4.Elapsed.TotalMilliseconds:F6}ms, result {(int)res2.Result}"); if (res2.Result == ReplayResult.Success) { @@ -314,11 +318,11 @@ public static int Run(string[] args) double percentComplete = 100.0 * (progressBeforeCurrentMC + iter) / totalWork; int perSecond = (int)(progressInterval / st1.Elapsed.TotalSeconds); if (o.applyDiff) - Logger.LogVerbose(CFormat.Sprintf(" %2.1f%% - Loaded %d Jitted %d Diffs %d FailedCompile %d at %d per second", percentComplete, - loadedCount, jittedCount, diffsCount, failToReplayCount, perSecond)); + Logger.LogVerbose($" {percentComplete,2:F1}% - Loaded {loadedCount} Jitted {jittedCount} Diffs {diffsCount} " + + $"FailedCompile {failToReplayCount} at {perSecond} per second"); else - Logger.LogVerbose(CFormat.Sprintf(" %2.1f%% - Loaded %d Jitted %d FailedCompile %d at %d per second", percentComplete, - loadedCount, jittedCount, failToReplayCount, perSecond)); + Logger.LogVerbose($" {percentComplete,2:F1}% - Loaded {loadedCount} Jitted {jittedCount} FailedCompile " + + $"{failToReplayCount} at {perSecond} per second"); st1.Restart(); } @@ -329,11 +333,11 @@ public static int Run(string[] args) doneRepeatCount: if (o.applyDiff) - Logger.LogInfo(CFormat.Sprintf(AsmDiffsSummaryFormatString, loadedCount, jittedCount, failToReplayCount, excludedCount, missingCount, diffsCount)); + Logger.LogInfo(AsmDiffsSummary(loadedCount, jittedCount, failToReplayCount, excludedCount, missingCount, diffsCount)); else - Logger.LogInfo(CFormat.Sprintf(SummaryFormatString, loadedCount, jittedCount, failToReplayCount, excludedCount, missingCount)); + Logger.LogInfo(Summary(loadedCount, jittedCount, failToReplayCount, excludedCount, missingCount)); - Logger.LogVerbose(CFormat.Sprintf("Total time: %fms", st2.Elapsed.TotalMilliseconds)); + Logger.LogVerbose($"Total time: {st2.Elapsed.TotalMilliseconds:F6}ms"); if (o.mclFilename != null) failingToReplayMCL.CloseMCL(); @@ -422,10 +426,10 @@ private static void PrintDiffsCsvHeader(FileWriter fw) private static void PrintDiffsCsvRow(FileWriter fw, int context, uint contextSize, in ReplayResults baseRes, in ReplayResults diffRes, bool hasDiff) { - fw.Printf("%d,%u,", context, contextSize); + fw.Print($"{context},{contextSize},"); fw.PrintQuotedCsvField(diffRes.CompileResults.MethodFullName ?? ""); - fw.Printf(",%s,%s,%s,%s,%s,%lld,%lld", diffRes.CompileResults.TieringName ?? "", ResultToString(baseRes.Result), ResultToString(diffRes.Result), - diffRes.IsMinOpts ? "True" : "False", hasDiff ? "True" : "False", baseRes.NumExecutedInstructions, diffRes.NumExecutedInstructions); + fw.Print($",{diffRes.CompileResults.TieringName ?? ""},{ResultToString(baseRes.Result)},{ResultToString(diffRes.Result)}," + + $"{(diffRes.IsMinOpts ? "True" : "False")},{(hasDiff ? "True" : "False")},{baseRes.NumExecutedInstructions},{diffRes.NumExecutedInstructions}"); for (int i = 0; i < JitMetrics.All.Length; i++) fw.Print($",{baseRes.CompileResults.Metrics.Format(i)},{diffRes.CompileResults.Metrics.Format(i)}"); fw.Print("\n"); @@ -441,9 +445,9 @@ private static void PrintReplayCsvHeader(FileWriter fw) private static void PrintReplayCsvRow(FileWriter fw, int context, uint contextSize, in ReplayResults res) { - fw.Printf("%d,%u,", context, contextSize); + fw.Print($"{context},{contextSize},"); fw.PrintQuotedCsvField(res.CompileResults.MethodFullName ?? ""); - fw.Printf(",%s,%s,%s,%lld", res.CompileResults.TieringName ?? "", ResultToString(res.Result), res.IsMinOpts ? "True" : "False", res.NumExecutedInstructions); + fw.Print($",{res.CompileResults.TieringName ?? ""},{ResultToString(res.Result)},{(res.IsMinOpts ? "True" : "False")},{res.NumExecutedInstructions}"); for (int i = 0; i < JitMetrics.All.Length; i++) fw.Print($",{res.CompileResults.Metrics.Format(i)}"); fw.Print("\n"); From 7524ba64e9a03a4ecd60fe962136050347434a6e Mon Sep 17 00:00:00 2001 From: am11 <3840695+am11@users.noreply.github.com> Date: Mon, 9 Nov 2026 12:23:21 +0200 Subject: [PATCH 08/10] Pin the JIT-EE byrefs with fixed instead of converting them to pointers Co-authored-by: Cursor --- .../CorInfoImpl.Collector.cs | 182 +++++++++++------- .../managed/superpmi/CorInfoImpl.SuperPmi.cs | 140 ++++++++++---- 2 files changed, 207 insertions(+), 115 deletions(-) diff --git a/src/coreclr/tools/superpmi/managed/superpmi-shim-collector/CorInfoImpl.Collector.cs b/src/coreclr/tools/superpmi/managed/superpmi-shim-collector/CorInfoImpl.Collector.cs index 91b68d1c4cab36..424b7251aa5bbb 100644 --- a/src/coreclr/tools/superpmi/managed/superpmi-shim-collector/CorInfoImpl.Collector.cs +++ b/src/coreclr/tools/superpmi/managed/superpmi-shim-collector/CorInfoImpl.Collector.cs @@ -35,33 +35,6 @@ public CorInfoImpl(CollectorJitCompiler compiler, OriginalJitInfo original, Meth private void AddCall(string name) => cr.AddCall(name); - private static T* P(ref T value) where T : unmanaged => (T*)Unsafe.AsPointer(ref value); - - // The by-ref parameters of pointer types, which refer to the JIT's memory. - private static void** P(ref void* value) - { - fixed (void** p = &value) - return p; - } - - private static uint** P(ref uint* value) - { - fixed (uint** p = &value) - return p; - } - - private static PgoInstrumentationSchema** P(ref PgoInstrumentationSchema* value) - { - fixed (PgoInstrumentationSchema** p = &value) - return p; - } - - private static CORINFO_JUST_MY_CODE_HANDLE_** P(ref CORINFO_JUST_MY_CODE_HANDLE_* value) - { - fixed (CORINFO_JUST_MY_CODE_HANDLE_** p = &value) - return p; - } - // An exception filter that records the code of the exception and lets it continue, so that the call is // recorded with it (and replayed by throwing). private static bool CaptureExceptionCode(Exception e, ref uint exceptionCode) @@ -172,7 +145,8 @@ private void resolveToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken) } finally { - mc.recResolveToken(P(ref pResolvedToken), exceptionCode); + fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) + mc.recResolveToken(pResolvedTokenPtr, exceptionCode); } } @@ -315,7 +289,8 @@ private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESO } finally { - mc.recGetCallInfo(P(ref pResolvedToken), pConstrainedResolvedToken, callerHandle, flags, pResult, exceptionCode); + fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) + mc.recGetCallInfo(pResolvedTokenPtr, pConstrainedResolvedToken, callerHandle, flags, pResult, exceptionCode); } } @@ -323,7 +298,9 @@ private bool getTailCallHelpers(ref CORINFO_RESOLVED_TOKEN callToken, CORINFO_SI { AddCall("getTailCallHelpers"); bool result = _original.getTailCallHelpers(ref callToken, sig, flags, ref pResult); - mc.recGetTailCallHelpers(P(ref callToken), sig, flags, result ? P(ref pResult) : null); + fixed (CORINFO_RESOLVED_TOKEN* callTokenPtr = &callToken) + fixed (CORINFO_TAILCALL_HELPERS* pResultPtr = &pResult) + mc.recGetTailCallHelpers(callTokenPtr, sig, flags, result ? pResultPtr : null); return result; } @@ -397,7 +374,11 @@ private HRESULT getPgoInstrumentationResults(CORINFO_METHOD_STRUCT_* ftnHnd, ref { AddCall("getPgoInstrumentationResults"); HRESULT temp = _original.getPgoInstrumentationResults(ftnHnd, ref pSchema, ref pCountSchemaItems, pInstrumentationData, ref pPgoSource, ref pDynamicPgo); - mc.recGetPgoInstrumentationResults(ftnHnd, P(ref pSchema), P(ref pCountSchemaItems), pInstrumentationData, P(ref pPgoSource), P(ref pDynamicPgo), (int)temp); + fixed (PgoInstrumentationSchema** pSchemaPtr = &pSchema) + fixed (uint* pCountSchemaItemsPtr = &pCountSchemaItems) + fixed (PgoSource* pPgoSourcePtr = &pPgoSource) + fixed (bool* pDynamicPgoPtr = &pDynamicPgo) + mc.recGetPgoInstrumentationResults(ftnHnd, pSchemaPtr, pCountSchemaItemsPtr, pInstrumentationData, pPgoSourcePtr, pDynamicPgoPtr, (int)temp); return temp; } @@ -493,7 +474,8 @@ private void getEHinfo(CORINFO_METHOD_STRUCT_* ftn, uint EHnumber, ref CORINFO_E { AddCall("getEHinfo"); _original.getEHinfo(ftn, EHnumber, ref clause); - mc.recGetEHinfo(ftn, EHnumber, P(ref clause)); + fixed (CORINFO_EH_CLAUSE* clausePtr = &clause) + mc.recGetEHinfo(ftn, EHnumber, clausePtr); } private CORINFO_CLASS_STRUCT_* getMethodClass(CORINFO_METHOD_STRUCT_* method) @@ -508,7 +490,10 @@ private void getMethodVTableOffset(CORINFO_METHOD_STRUCT_* method, ref uint offs { AddCall("getMethodVTableOffset"); _original.getMethodVTableOffset(method, ref offsetOfIndirection, ref offsetAfterIndirection, ref isRelative); - mc.recGetMethodVTableOffset(method, P(ref offsetOfIndirection), P(ref offsetAfterIndirection), P(ref isRelative)); + fixed (uint* offsetOfIndirectionPtr = &offsetOfIndirection) + fixed (uint* offsetAfterIndirectionPtr = &offsetAfterIndirection) + fixed (bool* isRelativePtr = &isRelative) + mc.recGetMethodVTableOffset(method, offsetOfIndirectionPtr, offsetAfterIndirectionPtr, isRelativePtr); } private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) @@ -555,7 +540,9 @@ private void expandRawHandleIntrinsic(ref CORINFO_RESOLVED_TOKEN pResolvedToken, { AddCall("expandRawHandleIntrinsic"); _original.expandRawHandleIntrinsic(ref pResolvedToken, callerHandle, ref pResult); - mc.recExpandRawHandleIntrinsic(P(ref pResolvedToken), callerHandle, P(ref pResult)); + fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) + fixed (CORINFO_GENERICHANDLE_RESULT* pResultPtr = &pResult) + mc.recExpandRawHandleIntrinsic(pResolvedTokenPtr, callerHandle, pResultPtr); } private bool isIntrinsicType(CORINFO_CLASS_STRUCT_* classHnd) @@ -608,7 +595,8 @@ private void setPatchpointInfo(PatchpointInfo* patchpointInfo) { AddCall("getOSRInfo"); var patchpointInfo = _original.getOSRInfo(ref ilOffset); - mc.recGetOSRInfo(patchpointInfo, P(ref ilOffset)); + fixed (uint* ilOffsetPtr = &ilOffset) + mc.recGetOSRInfo(patchpointInfo, ilOffsetPtr); return patchpointInfo; } @@ -630,7 +618,8 @@ private void findCallSiteSig(CORINFO_MODULE_STRUCT_* module, uint methTOK, CORIN { AddCall("getTokenTypeAsHandle"); var temp = _original.getTokenTypeAsHandle(ref pResolvedToken); - mc.recGetTokenTypeAsHandle(P(ref pResolvedToken), temp); + fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) + mc.recGetTokenTypeAsHandle(pResolvedTokenPtr, temp); return temp; } @@ -746,7 +735,9 @@ private bool getIsClassInitedFlagAddress(CORINFO_CLASS_STRUCT_* cls, ref CORINFO { AddCall("getIsClassInitedFlagAddress"); var temp = _original.getIsClassInitedFlagAddress(cls, ref addr, ref offset); - mc.recGetIsClassInitedFlagAddress(cls, P(ref addr), P(ref offset), temp); + fixed (CORINFO_CONST_LOOKUP* addrPtr = &addr) + fixed (int* offsetPtr = &offset) + mc.recGetIsClassInitedFlagAddress(cls, addrPtr, offsetPtr, temp); return temp; } @@ -770,7 +761,8 @@ private bool getStaticBaseAddress(CORINFO_CLASS_STRUCT_* cls, bool isGc, ref COR { AddCall("getStaticBaseAddress"); var temp = _original.getStaticBaseAddress(cls, isGc, ref addr); - mc.recGetStaticBaseAddress(cls, isGc, P(ref addr), temp); + fixed (CORINFO_CONST_LOOKUP* addrPtr = &addr) + mc.recGetStaticBaseAddress(cls, isGc, addrPtr, temp); return temp; } @@ -850,7 +842,8 @@ private CorInfoHelpFunc getCastingHelper(ref CORINFO_RESOLVED_TOKEN pResolvedTok { AddCall("getCastingHelper"); var temp = _original.getCastingHelper(ref pResolvedToken, fThrowing); - mc.recGetCastingHelper(P(ref pResolvedToken), fThrowing, temp); + fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) + mc.recGetCastingHelper(pResolvedTokenPtr, fThrowing, temp); return temp; } @@ -922,7 +915,9 @@ private bool getReadyToRunHelper(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CorI { AddCall("getReadyToRunHelper"); var result = _original.getReadyToRunHelper(ref pResolvedToken, id, callerHandle, ref pLookup); - mc.recGetReadyToRunHelper(P(ref pResolvedToken), id, callerHandle, P(ref pLookup), result); + fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) + fixed (CORINFO_CONST_LOOKUP* pLookupPtr = &pLookup) + mc.recGetReadyToRunHelper(pResolvedTokenPtr, id, callerHandle, pLookupPtr, result); return result; } @@ -930,7 +925,9 @@ private void getReadyToRunDelegateCtorHelper(ref CORINFO_RESOLVED_TOKEN pTargetM { AddCall("getReadyToRunDelegateCtorHelper"); _original.getReadyToRunDelegateCtorHelper(ref pTargetMethod, targetConstraint, delegateType, callerHandle, ref pLookup); - mc.recGetReadyToRunDelegateCtorHelper(P(ref pTargetMethod), (uint)targetConstraint, delegateType, callerHandle, P(ref pLookup)); + fixed (CORINFO_RESOLVED_TOKEN* pTargetMethodPtr = &pTargetMethod) + fixed (CORINFO_LOOKUP* pLookupPtr = &pLookup) + mc.recGetReadyToRunDelegateCtorHelper(pTargetMethodPtr, (uint)targetConstraint, delegateType, callerHandle, pLookupPtr); } private CorInfoInitClassResult initClass(CORINFO_FIELD_STRUCT_* field, CORINFO_METHOD_STRUCT_* method, CORINFO_CONTEXT_STRUCT* context) @@ -1065,7 +1062,9 @@ private CorInfoIsAccessAllowedResult canAccessClass(ref CORINFO_RESOLVED_TOKEN p { AddCall("canAccessClass"); var temp = _original.canAccessClass(ref pResolvedToken, callerHandle, ref pAccessHelper); - mc.recCanAccessClass(P(ref pResolvedToken), callerHandle, P(ref pAccessHelper), temp); + fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) + fixed (CORINFO_HELPER_DESC* pAccessHelperPtr = &pAccessHelper) + mc.recCanAccessClass(pResolvedTokenPtr, callerHandle, pAccessHelperPtr, temp); return temp; } @@ -1105,7 +1104,8 @@ private void getFieldInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_MET { AddCall("getFieldInfo"); _original.getFieldInfo(ref pResolvedToken, callerHandle, flags, pResult); - mc.recGetFieldInfo(P(ref pResolvedToken), callerHandle, flags, pResult); + fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) + mc.recGetFieldInfo(pResolvedTokenPtr, callerHandle, flags, pResult); } private uint getThreadLocalFieldInfo(CORINFO_FIELD_STRUCT_* field, bool isGCType) @@ -1150,7 +1150,9 @@ private void getBoundaries(CORINFO_METHOD_STRUCT_* ftn, ref uint cILOffsets, ref { AddCall("getBoundaries"); _original.getBoundaries(ftn, ref cILOffsets, ref pILOffsets, implicitBoundaries); - mc.recGetBoundaries(ftn, P(ref cILOffsets), P(ref pILOffsets), implicitBoundaries); + fixed (uint* cILOffsetsPtr = &cILOffsets) + fixed (uint** pILOffsetsPtr = &pILOffsets) + mc.recGetBoundaries(ftn, cILOffsetsPtr, pILOffsetsPtr, implicitBoundaries); } private void setBoundaries(CORINFO_METHOD_STRUCT_* ftn, uint cMap, OffsetMapping* pMap) @@ -1164,7 +1166,9 @@ private void getVars(CORINFO_METHOD_STRUCT_* ftn, ref uint cVars, ILVarInfo** va { AddCall("getVars"); _original.getVars(ftn, ref cVars, vars, ref extendOthers); - mc.recGetVars(ftn, P(ref cVars), vars, P(ref extendOthers)); + fixed (uint* cVarsPtr = &cVars) + fixed (bool* extendOthersPtr = &extendOthers) + mc.recGetVars(ftn, cVarsPtr, vars, extendOthersPtr); } private void setVars(CORINFO_METHOD_STRUCT_* ftn, uint cVars, NativeVarInfo* vars) @@ -1212,21 +1216,24 @@ private void getEEInfo(ref CORINFO_EE_INFO pEEInfoOut) { AddCall("getEEInfo"); _original.getEEInfo(ref pEEInfoOut); - mc.recGetEEInfo(P(ref pEEInfoOut)); + fixed (CORINFO_EE_INFO* pEEInfoOutPtr = &pEEInfoOut) + mc.recGetEEInfo(pEEInfoOutPtr); } private void getAsyncInfo(ref CORINFO_ASYNC_INFO pAsyncInfo) { AddCall("getAsyncInfo"); _original.getAsyncInfo(ref pAsyncInfo); - mc.recGetAsyncInfo(P(ref pAsyncInfo)); + fixed (CORINFO_ASYNC_INFO* pAsyncInfoPtr = &pAsyncInfo) + mc.recGetAsyncInfo(pAsyncInfoPtr); } private CORINFO_METHOD_STRUCT_* getAwaitReturnCall(CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_CONTEXT_STRUCT** contextHandle, ref CORINFO_LOOKUP instArg) { AddCall("getAwaitReturnCall"); var result = _original.getAwaitReturnCall(callerHandle, contextHandle, ref instArg); - mc.recGetAwaitReturnCall(callerHandle, contextHandle, P(ref instArg), result); + fixed (CORINFO_LOOKUP* instArgPtr = &instArg) + mc.recGetAwaitReturnCall(callerHandle, contextHandle, instArgPtr, result); return result; } @@ -1234,7 +1241,9 @@ private void getAsyncInfo(ref CORINFO_ASYNC_INFO pAsyncInfo) { AddCall("getAwaitAwaiterInContinuationCall"); var result = _original.getAwaitAwaiterInContinuationCall(callerHandle, ref pResolvedToken, isUnsafe, contextHandle, ref instArg); - mc.recGetAwaitAwaiterInContinuationCall(callerHandle, P(ref pResolvedToken), isUnsafe, contextHandle, P(ref instArg), result); + fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) + fixed (CORINFO_LOOKUP* instArgPtr = &instArg) + mc.recGetAwaitAwaiterInContinuationCall(callerHandle, pResolvedTokenPtr, isUnsafe, contextHandle, instArgPtr, result); return result; } @@ -1282,14 +1291,16 @@ private void getSwiftLowering(CORINFO_CLASS_STRUCT_* structHnd, ref CORINFO_SWIF { AddCall("getSwiftLowering"); _original.getSwiftLowering(structHnd, ref pLowering); - mc.recGetSwiftLowering(structHnd, P(ref pLowering)); + fixed (CORINFO_SWIFT_LOWERING* pLoweringPtr = &pLowering) + mc.recGetSwiftLowering(structHnd, pLoweringPtr); } private void getFpStructLowering(CORINFO_CLASS_STRUCT_* structHnd, ref CORINFO_FPSTRUCT_LOWERING pLowering) { AddCall("getFpStructLowering"); _original.getFpStructLowering(structHnd, ref pLowering); - mc.recGetFpStructLowering(structHnd, P(ref pLowering)); + fixed (CORINFO_FPSTRUCT_LOWERING* pLoweringPtr = &pLowering) + mc.recGetFpStructLowering(structHnd, pLoweringPtr); } private CorInfoWasmType getWasmLowering(CORINFO_CLASS_STRUCT_* structHnd) @@ -1312,14 +1323,16 @@ private void getWasmWellKnownGlobals(ref CORINFO_WASM_WELLKNOWN_GLOBALS pWellKno { AddCall("getWasmWellKnownGlobals"); _original.getWasmWellKnownGlobals(ref pWellKnownGlobalsOut); - mc.recGetWasmWellKnownGlobals(P(ref pWellKnownGlobalsOut)); + fixed (CORINFO_WASM_WELLKNOWN_GLOBALS* pWellKnownGlobalsOutPtr = &pWellKnownGlobalsOut) + mc.recGetWasmWellKnownGlobals(pWellKnownGlobalsOutPtr); } private uint getThreadTLSIndex(ref void* ppIndirection) { AddCall("getThreadTLSIndex"); var temp = _original.getThreadTLSIndex(ref ppIndirection); - mc.recGetThreadTLSIndex(P(ref ppIndirection), temp); + fixed (void** ppIndirectionPtr = &ppIndirection) + mc.recGetThreadTLSIndex(ppIndirectionPtr, temp); return temp; } @@ -1327,7 +1340,8 @@ private uint getThreadTLSIndex(ref void* ppIndirection) { AddCall("getAddrOfCaptureThreadGlobal"); var temp = _original.getAddrOfCaptureThreadGlobal(ref ppIndirection); - mc.recGetAddrOfCaptureThreadGlobal(P(ref ppIndirection), temp); + fixed (void** ppIndirectionPtr = &ppIndirection) + mc.recGetAddrOfCaptureThreadGlobal(ppIndirectionPtr, temp); return temp; } @@ -1335,21 +1349,24 @@ private void getFunctionEntryPoint(CORINFO_METHOD_STRUCT_* ftn, ref CORINFO_CONS { AddCall("getFunctionEntryPoint"); _original.getFunctionEntryPoint(ftn, ref pResult, accessFlags); - mc.recGetFunctionEntryPoint(ftn, P(ref pResult), accessFlags); + fixed (CORINFO_CONST_LOOKUP* pResultPtr = &pResult) + mc.recGetFunctionEntryPoint(ftn, pResultPtr, accessFlags); } private void getFunctionFixedEntryPoint(CORINFO_METHOD_STRUCT_* ftn, bool isUnsafeFunctionPointer, ref CORINFO_CONST_LOOKUP pResult) { AddCall("getFunctionFixedEntryPoint"); _original.getFunctionFixedEntryPoint(ftn, isUnsafeFunctionPointer, ref pResult); - mc.recGetFunctionFixedEntryPoint(ftn, P(ref pResult)); + fixed (CORINFO_CONST_LOOKUP* pResultPtr = &pResult) + mc.recGetFunctionFixedEntryPoint(ftn, pResultPtr); } private CORINFO_MODULE_STRUCT_* embedModuleHandle(CORINFO_MODULE_STRUCT_* handle, ref void* ppIndirection) { AddCall("embedModuleHandle"); var temp = _original.embedModuleHandle(handle, ref ppIndirection); - mc.recEmbedModuleHandle(handle, P(ref ppIndirection), temp); + fixed (void** ppIndirectionPtr = &ppIndirection) + mc.recEmbedModuleHandle(handle, ppIndirectionPtr, temp); return temp; } @@ -1357,7 +1374,8 @@ private void getFunctionFixedEntryPoint(CORINFO_METHOD_STRUCT_* ftn, bool isUnsa { AddCall("embedClassHandle"); var temp = _original.embedClassHandle(handle, ref ppIndirection); - mc.recEmbedClassHandle(handle, P(ref ppIndirection), temp); + fixed (void** ppIndirectionPtr = &ppIndirection) + mc.recEmbedClassHandle(handle, ppIndirectionPtr, temp); return temp; } @@ -1365,7 +1383,8 @@ private void getFunctionFixedEntryPoint(CORINFO_METHOD_STRUCT_* ftn, bool isUnsa { AddCall("embedMethodHandle"); var temp = _original.embedMethodHandle(handle, ref ppIndirection); - mc.recEmbedMethodHandle(handle, P(ref ppIndirection), temp); + fixed (void** ppIndirectionPtr = &ppIndirection) + mc.recEmbedMethodHandle(handle, ppIndirectionPtr, temp); return temp; } @@ -1373,7 +1392,8 @@ private void getFunctionFixedEntryPoint(CORINFO_METHOD_STRUCT_* ftn, bool isUnsa { AddCall("embedFieldHandle"); var temp = _original.embedFieldHandle(handle, ref ppIndirection); - mc.recEmbedFieldHandle(handle, P(ref ppIndirection), temp); + fixed (void** ppIndirectionPtr = &ppIndirection) + mc.recEmbedFieldHandle(handle, ppIndirectionPtr, temp); return temp; } @@ -1381,21 +1401,25 @@ private void embedGenericHandle(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool { AddCall("embedGenericHandle"); _original.embedGenericHandle(ref pResolvedToken, fEmbedParent, callerHandle, ref pResult); - mc.recEmbedGenericHandle(P(ref pResolvedToken), fEmbedParent, callerHandle, P(ref pResult)); + fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) + fixed (CORINFO_GENERICHANDLE_RESULT* pResultPtr = &pResult) + mc.recEmbedGenericHandle(pResolvedTokenPtr, fEmbedParent, callerHandle, pResultPtr); } private void getLocationOfThisType(CORINFO_METHOD_STRUCT_* context, ref CORINFO_LOOKUP_KIND pLookupKind) { AddCall("getLocationOfThisType"); _original.getLocationOfThisType(context, ref pLookupKind); - mc.recGetLocationOfThisType(context, P(ref pLookupKind)); + fixed (CORINFO_LOOKUP_KIND* pLookupKindPtr = &pLookupKind) + mc.recGetLocationOfThisType(context, pLookupKindPtr); } private void getAddressOfPInvokeTarget(CORINFO_METHOD_STRUCT_* method, ref CORINFO_CONST_LOOKUP pLookup) { AddCall("getAddressOfPInvokeTarget"); _original.getAddressOfPInvokeTarget(method, ref pLookup); - mc.recGetAddressOfPInvokeTarget(method, P(ref pLookup)); + fixed (CORINFO_CONST_LOOKUP* pLookupPtr = &pLookup) + mc.recGetAddressOfPInvokeTarget(method, pLookupPtr); } private void* GetCookieForInterpreterCalliSig(CORINFO_SIG_INFO* szMetaSig) @@ -1410,7 +1434,8 @@ private void getAddressOfPInvokeTarget(CORINFO_METHOD_STRUCT_* method, ref CORIN { AddCall("getJustMyCodeHandle"); var temp = _original.getJustMyCodeHandle(method, ref ppIndirection); - mc.recGetJustMyCodeHandle(method, P(ref ppIndirection), temp); + fixed (CORINFO_JUST_MY_CODE_HANDLE_** ppIndirectionPtr = &ppIndirection) + mc.recGetJustMyCodeHandle(method, ppIndirectionPtr, temp); return temp; } @@ -1418,7 +1443,10 @@ private void GetProfilingHandle(ref bool pbHookFunction, ref void* pProfilerHand { AddCall("GetProfilingHandle"); _original.GetProfilingHandle(ref pbHookFunction, ref pProfilerHandle, ref pbIndirectedHandles); - mc.recGetProfilingHandle(P(ref pbHookFunction), P(ref pProfilerHandle), P(ref pbIndirectedHandles)); + fixed (bool* pbHookFunctionPtr = &pbHookFunction) + fixed (void** pProfilerHandlePtr = &pProfilerHandle) + fixed (bool* pbIndirectedHandlesPtr = &pbIndirectedHandles) + mc.recGetProfilingHandle(pbHookFunctionPtr, pProfilerHandlePtr, pbIndirectedHandlesPtr); } private bool getStaticFieldContent(CORINFO_FIELD_STRUCT_* field, byte* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects) @@ -1449,7 +1477,8 @@ private IntPtr getVarArgsHandle(CORINFO_SIG_INFO* pSig, CORINFO_METHOD_STRUCT_* { AddCall("getVarArgsHandle"); var temp = _original.getVarArgsHandle(pSig, methHnd, ref ppIndirection); - mc.recGetVarArgsHandle(pSig, methHnd, P(ref ppIndirection), (void*)temp); + fixed (void** ppIndirectionPtr = &ppIndirection) + mc.recGetVarArgsHandle(pSig, methHnd, ppIndirectionPtr, (void*)temp); return temp; } @@ -1465,7 +1494,8 @@ private InfoAccessType emptyStringLiteral(ref void* ppValue) { AddCall("emptyStringLiteral"); var temp = _original.emptyStringLiteral(ref ppValue); - mc.recEmptyStringLiteral(P(ref ppValue), temp); + fixed (void** ppValuePtr = &ppValue) + mc.recEmptyStringLiteral(ppValuePtr, temp); return temp; } @@ -1473,7 +1503,8 @@ private uint getFieldThreadLocalStoreID(CORINFO_FIELD_STRUCT_* field, ref void* { AddCall("getFieldThreadLocalStoreID"); var temp = _original.getFieldThreadLocalStoreID(field, ref ppIndirection); - mc.recGetFieldThreadLocalStoreID(field, P(ref ppIndirection), temp); + fixed (void** ppIndirectionPtr = &ppIndirection) + mc.recGetFieldThreadLocalStoreID(field, ppIndirectionPtr, temp); return temp; } @@ -1481,7 +1512,8 @@ private uint getFieldThreadLocalStoreID(CORINFO_FIELD_STRUCT_* field, ref void* { AddCall("GetDelegateCtor"); var temp = _original.GetDelegateCtor(methHnd, clsHnd, targetMethodHnd, ref pCtorData); - mc.recGetDelegateCtor(methHnd, clsHnd, targetMethodHnd, P(ref pCtorData), temp); + fixed (DelegateCtorArgs* pCtorDataPtr = &pCtorData) + mc.recGetDelegateCtor(methHnd, clsHnd, targetMethodHnd, pCtorDataPtr, temp); return temp; } @@ -1495,7 +1527,8 @@ private void MethodCompileComplete(CORINFO_METHOD_STRUCT_* methHnd) { AddCall("getContinuationType"); var result = _original.getContinuationType(dataSize, ref objRefs, objRefsSize); - mc.recGetContinuationType(dataSize, P(ref objRefs), objRefsSize, result); + fixed (bool* objRefsPtr = &objRefs) + mc.recGetContinuationType(dataSize, objRefsPtr, objRefsSize, result); return result; } @@ -1511,7 +1544,8 @@ private bool convertPInvokeCalliToCall(ref CORINFO_RESOLVED_TOKEN pResolvedToken { AddCall("convertPInvokeCalliToCall"); var result = _original.convertPInvokeCalliToCall(ref pResolvedToken, fMustConvert); - mc.recConvertPInvokeCalliToCall(P(ref pResolvedToken), fMustConvert, result); + fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) + mc.recConvertPInvokeCalliToCall(pResolvedTokenPtr, fMustConvert, result); return result; } @@ -1562,7 +1596,8 @@ private void setEHinfo(uint EHnumber, ref CORINFO_EH_CLAUSE clause) { AddCall("setEHinfo"); _original.setEHinfo(EHnumber, ref clause); - cr.recSetEHinfo(EHnumber, P(ref clause)); + fixed (CORINFO_EH_CLAUSE* clausePtr = &clause) + cr.recSetEHinfo(EHnumber, clausePtr); } private bool logMsg(uint level, byte* fmt, IntPtr args) @@ -1620,7 +1655,8 @@ private uint getJitFlags(ref CORJIT_FLAGS jitFlags, uint sizeInBytes) { AddCall("getJitFlags"); var result = _original.getJitFlags(ref jitFlags, sizeInBytes); - mc.recGetJitFlags(P(ref jitFlags), sizeInBytes, result); + fixed (CORJIT_FLAGS* jitFlagsPtr = &jitFlags) + mc.recGetJitFlags(jitFlagsPtr, sizeInBytes, result); return result; } diff --git a/src/coreclr/tools/superpmi/managed/superpmi/CorInfoImpl.SuperPmi.cs b/src/coreclr/tools/superpmi/managed/superpmi/CorInfoImpl.SuperPmi.cs index c44ebbec97a7df..c5440acfd8b8cc 100644 --- a/src/coreclr/tools/superpmi/managed/superpmi/CorInfoImpl.SuperPmi.cs +++ b/src/coreclr/tools/superpmi/managed/superpmi/CorInfoImpl.SuperPmi.cs @@ -84,8 +84,6 @@ private static void ThrowRecordedException(uint innerExceptionCode) throw new SpmiException(ExceptionCodes.RECORDED_EXCEPTION, $"Recorded exception 0x{innerExceptionCode:x}"); } - private static T* P(ref T value) where T : unmanaged => (T*)Unsafe.AsPointer(ref value); - private static nuint AlignUp(nuint value, nuint alignment) => (value + (alignment - 1)) & ~(alignment - 1); private bool isIntrinsic(CORINFO_METHOD_STRUCT_* ftn) @@ -180,7 +178,8 @@ private void reportTailCallDecision(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_M private void getEHinfo(CORINFO_METHOD_STRUCT_* ftn, uint EHnumber, ref CORINFO_EH_CLAUSE clause) { AddCall("getEHinfo"); - mc.repGetEHinfo(ftn, EHnumber, P(ref clause)); + fixed (CORINFO_EH_CLAUSE* clausePtr = &clause) + mc.repGetEHinfo(ftn, EHnumber, clausePtr); } private CORINFO_CLASS_STRUCT_* getMethodClass(CORINFO_METHOD_STRUCT_* method) @@ -192,7 +191,10 @@ private void getEHinfo(CORINFO_METHOD_STRUCT_* ftn, uint EHnumber, ref CORINFO_E private void getMethodVTableOffset(CORINFO_METHOD_STRUCT_* method, ref uint offsetOfIndirection, ref uint offsetAfterIndirection, ref bool isRelative) { AddCall("getMethodVTableOffset"); - mc.repGetMethodVTableOffset(method, P(ref offsetOfIndirection), P(ref offsetAfterIndirection), P(ref isRelative)); + fixed (uint* offsetOfIndirectionPtr = &offsetOfIndirection) + fixed (uint* offsetAfterIndirectionPtr = &offsetAfterIndirection) + fixed (bool* isRelativePtr = &isRelative) + mc.repGetMethodVTableOffset(method, offsetOfIndirectionPtr, offsetAfterIndirectionPtr, isRelativePtr); } private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) @@ -204,7 +206,8 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) private CORINFO_METHOD_STRUCT_* getAsyncOtherVariant(CORINFO_METHOD_STRUCT_* ftn, ref bool variantIsThunk) { AddCall("getAsyncOtherVariant"); - return mc.repGetAsyncOtherVariant(ftn, P(ref variantIsThunk)); + fixed (bool* variantIsThunkPtr = &variantIsThunk) + return mc.repGetAsyncOtherVariant(ftn, variantIsThunkPtr); } private CORINFO_CLASS_STRUCT_* getDefaultComparerClass(CORINFO_CLASS_STRUCT_* elemType) @@ -228,7 +231,9 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) private void expandRawHandleIntrinsic(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_GENERICHANDLE_RESULT pResult) { AddCall("expandRawHandleIntrinsic"); - mc.repExpandRawHandleIntrinsic(P(ref pResolvedToken), callerHandle, P(ref pResult)); + fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) + fixed (CORINFO_GENERICHANDLE_RESULT* pResultPtr = &pResult) + mc.repExpandRawHandleIntrinsic(pResolvedTokenPtr, callerHandle, pResultPtr); } private bool isIntrinsicType(CORINFO_CLASS_STRUCT_* classHnd) @@ -240,7 +245,8 @@ private bool isIntrinsicType(CORINFO_CLASS_STRUCT_* classHnd) private CorInfoCallConvExtension getUnmanagedCallConv(CORINFO_METHOD_STRUCT_* method, CORINFO_SIG_INFO* callSiteSig, ref bool pSuppressGCTransition) { AddCall("getUnmanagedCallConv"); - return mc.repGetUnmanagedCallConv(method, callSiteSig, P(ref pSuppressGCTransition)); + fixed (bool* pSuppressGCTransitionPtr = &pSuppressGCTransition) + return mc.repGetUnmanagedCallConv(method, callSiteSig, pSuppressGCTransitionPtr); } private bool pInvokeMarshalingRequired(CORINFO_METHOD_STRUCT_* method, CORINFO_SIG_INFO* callSiteSig) @@ -271,13 +277,16 @@ private void setPatchpointInfo(PatchpointInfo* patchpointInfo) private PatchpointInfo* getOSRInfo(ref uint ilOffset) { AddCall("getOSRInfo"); - return mc.repGetOSRInfo(P(ref ilOffset)); + fixed (uint* ilOffsetPtr = &ilOffset) + return mc.repGetOSRInfo(ilOffsetPtr); } private void resolveToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken) { AddCall("resolveToken"); - mc.repResolveToken(P(ref pResolvedToken), out uint exceptionCode); + uint exceptionCode; + fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) + mc.repResolveToken(pResolvedTokenPtr, out exceptionCode); if (exceptionCode != 0) ThrowRecordedException(exceptionCode); } @@ -297,7 +306,8 @@ private void findCallSiteSig(CORINFO_MODULE_STRUCT_* module, uint methTOK, CORIN private CORINFO_CLASS_STRUCT_* getTokenTypeAsHandle(ref CORINFO_RESOLVED_TOKEN pResolvedToken) { AddCall("getTokenTypeAsHandle"); - return mc.repGetTokenTypeAsHandle(P(ref pResolvedToken)); + fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) + return mc.repGetTokenTypeAsHandle(pResolvedTokenPtr); } private int getStringLiteral(CORINFO_MODULE_STRUCT_* module, uint metaTOK, char* buffer, int bufferSize, int startIndex) @@ -390,7 +400,9 @@ private void LongLifetimeFree(void* obj) private bool getIsClassInitedFlagAddress(CORINFO_CLASS_STRUCT_* cls, ref CORINFO_CONST_LOOKUP addr, ref int offset) { AddCall("getIsClassInitedFlagAddress"); - return mc.repGetIsClassInitedFlagAddress(cls, P(ref addr), P(ref offset)); + fixed (CORINFO_CONST_LOOKUP* addrPtr = &addr) + fixed (int* offsetPtr = &offset) + return mc.repGetIsClassInitedFlagAddress(cls, addrPtr, offsetPtr); } private void* getClassThreadStaticDynamicInfo(CORINFO_CLASS_STRUCT_* clr) @@ -408,7 +420,8 @@ private bool getIsClassInitedFlagAddress(CORINFO_CLASS_STRUCT_* cls, ref CORINFO private bool getStaticBaseAddress(CORINFO_CLASS_STRUCT_* cls, bool isGc, ref CORINFO_CONST_LOOKUP addr) { AddCall("getStaticBaseAddress"); - return mc.repGetStaticBaseAddress(cls, isGc, P(ref addr)); + fixed (CORINFO_CONST_LOOKUP* addrPtr = &addr) + return mc.repGetStaticBaseAddress(cls, isGc, addrPtr); } private uint getClassSize(CORINFO_CLASS_STRUCT_* cls) @@ -468,7 +481,10 @@ private bool checkMethodModifier(CORINFO_METHOD_STRUCT_* hMethod, byte* modifier private CorInfoHelpFunc getNewHelper(CORINFO_CLASS_STRUCT_* classHandle, ref bool pHasSideEffects) { AddCall("getNewHelper"); - CorInfoHelpFunc result = mc.repGetNewHelper(classHandle, P(ref pHasSideEffects), out uint exceptionCode); + CorInfoHelpFunc result; + uint exceptionCode; + fixed (bool* pHasSideEffectsPtr = &pHasSideEffects) + result = mc.repGetNewHelper(classHandle, pHasSideEffectsPtr, out exceptionCode); if (exceptionCode != 0) ThrowRecordedException(exceptionCode); return result; @@ -483,7 +499,8 @@ private CorInfoHelpFunc getNewArrHelper(CORINFO_CLASS_STRUCT_* arrayCls) private CorInfoHelpFunc getCastingHelper(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool fThrowing) { AddCall("getCastingHelper"); - return mc.repGetCastingHelper(P(ref pResolvedToken), fThrowing); + fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) + return mc.repGetCastingHelper(pResolvedTokenPtr, fThrowing); } private CorInfoHelpFunc getSharedCCtorHelper(CORINFO_CLASS_STRUCT_* clsHnd) @@ -537,14 +554,18 @@ private bool getStringChar(CORINFO_OBJECT_STRUCT_* strObj, int index, ushort* va private bool getReadyToRunHelper(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CorInfoHelpFunc id, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_CONST_LOOKUP pLookup) { AddCall("getReadyToRunHelper"); - return mc.repGetReadyToRunHelper(P(ref pResolvedToken), id, callerHandle, P(ref pLookup)); + fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) + fixed (CORINFO_CONST_LOOKUP* pLookupPtr = &pLookup) + return mc.repGetReadyToRunHelper(pResolvedTokenPtr, id, callerHandle, pLookupPtr); } private void getReadyToRunDelegateCtorHelper(ref CORINFO_RESOLVED_TOKEN pTargetMethod, mdToken targetConstraint, CORINFO_CLASS_STRUCT_* delegateType, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_LOOKUP pLookup) { AddCall("getReadyToRunDelegateCtorHelper"); - mc.repGetReadyToRunDelegateCtorHelper(P(ref pTargetMethod), targetConstraint, delegateType, callerHandle, P(ref pLookup)); + fixed (CORINFO_RESOLVED_TOKEN* pTargetMethodPtr = &pTargetMethod) + fixed (CORINFO_LOOKUP* pLookupPtr = &pLookup) + mc.repGetReadyToRunDelegateCtorHelper(pTargetMethodPtr, targetConstraint, delegateType, callerHandle, pLookupPtr); } private CorInfoInitClassResult initClass(CORINFO_FIELD_STRUCT_* field, CORINFO_METHOD_STRUCT_* method, CORINFO_CONTEXT_STRUCT* context) @@ -658,7 +679,9 @@ private CorInfoArrayIntrinsic getArrayIntrinsicID(CORINFO_METHOD_STRUCT_* ftn) private CorInfoIsAccessAllowedResult canAccessClass(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_HELPER_DESC pAccessHelper) { AddCall("canAccessClass"); - return mc.repCanAccessClass(P(ref pResolvedToken), callerHandle, P(ref pAccessHelper)); + fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) + fixed (CORINFO_HELPER_DESC* pAccessHelperPtr = &pAccessHelper) + return mc.repCanAccessClass(pResolvedTokenPtr, callerHandle, pAccessHelperPtr); } private nuint printFieldName(CORINFO_FIELD_STRUCT_* field, byte* buffer, nuint bufferSize, nuint* pRequiredBufferSize) @@ -688,7 +711,8 @@ private uint getFieldOffset(CORINFO_FIELD_STRUCT_* field) private void getFieldInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult) { AddCall("getFieldInfo"); - mc.repGetFieldInfo(P(ref pResolvedToken), callerHandle, flags, pResult); + fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) + mc.repGetFieldInfo(pResolvedTokenPtr, callerHandle, flags, pResult); } private uint getThreadLocalFieldInfo(CORINFO_FIELD_STRUCT_* field, bool isGCtype) @@ -725,7 +749,8 @@ private void getBoundaries(CORINFO_METHOD_STRUCT_* ftn, ref uint cILOffsets, ref { AddCall("getBoundaries"); fixed (uint** ppILOffsets = &pILOffsets) - mc.repGetBoundaries(ftn, P(ref cILOffsets), ppILOffsets, implicitBoundaries); + fixed (uint* cILOffsetsPtr = &cILOffsets) + mc.repGetBoundaries(ftn, cILOffsetsPtr, ppILOffsets, implicitBoundaries); // The JIT frees the array with freeArray, so move the data to memory that complies with that. if (cILOffsets > 0) @@ -751,7 +776,9 @@ private void setBoundaries(CORINFO_METHOD_STRUCT_* ftn, uint cMap, OffsetMapping private void getVars(CORINFO_METHOD_STRUCT_* ftn, ref uint cVars, ILVarInfo** vars, ref bool extendOthers) { AddCall("getVars"); - mc.repGetVars(ftn, P(ref cVars), vars, P(ref extendOthers)); + fixed (uint* cVarsPtr = &cVars) + fixed (bool* extendOthersPtr = &extendOthers) + mc.repGetVars(ftn, cVarsPtr, vars, extendOthersPtr); // The JIT frees the array with freeArray, so move the data to memory that complies with that. if (cVars > 0) @@ -858,26 +885,31 @@ private CorInfoHFAElemType getHFAType(CORINFO_CLASS_STRUCT_* hClass) private void getEEInfo(ref CORINFO_EE_INFO pEEInfoOut) { AddCall("getEEInfo"); - mc.repGetEEInfo(P(ref pEEInfoOut)); + fixed (CORINFO_EE_INFO* pEEInfoOutPtr = &pEEInfoOut) + mc.repGetEEInfo(pEEInfoOutPtr); } private void getAsyncInfo(ref CORINFO_ASYNC_INFO pAsyncInfoOut) { AddCall("getAsyncInfo"); - mc.repGetAsyncInfo(P(ref pAsyncInfoOut)); + fixed (CORINFO_ASYNC_INFO* pAsyncInfoOutPtr = &pAsyncInfoOut) + mc.repGetAsyncInfo(pAsyncInfoOutPtr); } private CORINFO_METHOD_STRUCT_* getAwaitReturnCall(CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_CONTEXT_STRUCT** contextHandle, ref CORINFO_LOOKUP instArg) { AddCall("getAwaitReturnCall"); - return mc.repGetAwaitReturnCall(callerHandle, contextHandle, P(ref instArg)); + fixed (CORINFO_LOOKUP* instArgPtr = &instArg) + return mc.repGetAwaitReturnCall(callerHandle, contextHandle, instArgPtr); } private CORINFO_METHOD_STRUCT_* getAwaitAwaiterInContinuationCall(CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool isUnsafe, CORINFO_CONTEXT_STRUCT** contextHandle, ref CORINFO_LOOKUP instArg) { AddCall("getAwaitAwaiterInContinuationCall"); - return mc.repGetAwaitAwaiterInContinuationCall(callerHandle, P(ref pResolvedToken), isUnsafe, contextHandle, P(ref instArg)); + fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) + fixed (CORINFO_LOOKUP* instArgPtr = &instArg) + return mc.repGetAwaitAwaiterInContinuationCall(callerHandle, pResolvedTokenPtr, isUnsafe, contextHandle, instArgPtr); } private mdToken getMethodDefFromMethod(CORINFO_METHOD_STRUCT_* hMethod) @@ -913,13 +945,15 @@ private bool getSystemVAmd64PassStructInRegisterDescriptor(CORINFO_CLASS_STRUCT_ private void getSwiftLowering(CORINFO_CLASS_STRUCT_* structHnd, ref CORINFO_SWIFT_LOWERING pLowering) { AddCall("getSwiftLowering"); - mc.repGetSwiftLowering(structHnd, P(ref pLowering)); + fixed (CORINFO_SWIFT_LOWERING* pLoweringPtr = &pLowering) + mc.repGetSwiftLowering(structHnd, pLoweringPtr); } private void getFpStructLowering(CORINFO_CLASS_STRUCT_* structHnd, ref CORINFO_FPSTRUCT_LOWERING pLowering) { AddCall("getFpStructLowering"); - mc.repGetFpStructLowering(structHnd, P(ref pLowering)); + fixed (CORINFO_FPSTRUCT_LOWERING* pLoweringPtr = &pLowering) + mc.repGetFpStructLowering(structHnd, pLoweringPtr); } private CorInfoWasmType getWasmLowering(CORINFO_CLASS_STRUCT_* structHnd) @@ -937,7 +971,8 @@ private uint getAddressAlignment(void* address) private void getWasmWellKnownGlobals(ref CORINFO_WASM_WELLKNOWN_GLOBALS pWellKnownGlobalsOut) { AddCall("getWasmWellKnownGlobals"); - mc.repGetWasmWellKnownGlobals(P(ref pWellKnownGlobalsOut)); + fixed (CORINFO_WASM_WELLKNOWN_GLOBALS* pWellKnownGlobalsOutPtr = &pWellKnownGlobalsOut) + mc.repGetWasmWellKnownGlobals(pWellKnownGlobalsOutPtr); } private uint getThreadTLSIndex(ref void* ppIndirection) @@ -963,13 +998,15 @@ private void getHelperFtn(CorInfoHelpFunc ftnNum, CORINFO_CONST_LOOKUP* pNativeE private void getFunctionEntryPoint(CORINFO_METHOD_STRUCT_* ftn, ref CORINFO_CONST_LOOKUP pResult, CORINFO_ACCESS_FLAGS accessFlags) { AddCall("getFunctionEntryPoint"); - mc.repGetFunctionEntryPoint(ftn, P(ref pResult), accessFlags); + fixed (CORINFO_CONST_LOOKUP* pResultPtr = &pResult) + mc.repGetFunctionEntryPoint(ftn, pResultPtr, accessFlags); } private void getFunctionFixedEntryPoint(CORINFO_METHOD_STRUCT_* ftn, bool isUnsafeFunctionPointer, ref CORINFO_CONST_LOOKUP pResult) { AddCall("getFunctionFixedEntryPoint"); - mc.repGetFunctionFixedEntryPoint(ftn, isUnsafeFunctionPointer, P(ref pResult)); + fixed (CORINFO_CONST_LOOKUP* pResultPtr = &pResult) + mc.repGetFunctionFixedEntryPoint(ftn, isUnsafeFunctionPointer, pResultPtr); } private CORINFO_MODULE_STRUCT_* embedModuleHandle(CORINFO_MODULE_STRUCT_* handle, ref void* ppIndirection) @@ -1003,19 +1040,23 @@ private void getFunctionFixedEntryPoint(CORINFO_METHOD_STRUCT_* ftn, bool isUnsa private void embedGenericHandle(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool fEmbedParent, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_GENERICHANDLE_RESULT pResult) { AddCall("embedGenericHandle"); - mc.repEmbedGenericHandle(P(ref pResolvedToken), fEmbedParent, callerHandle, P(ref pResult)); + fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) + fixed (CORINFO_GENERICHANDLE_RESULT* pResultPtr = &pResult) + mc.repEmbedGenericHandle(pResolvedTokenPtr, fEmbedParent, callerHandle, pResultPtr); } private void getLocationOfThisType(CORINFO_METHOD_STRUCT_* context, ref CORINFO_LOOKUP_KIND pLookupKind) { AddCall("getLocationOfThisType"); - mc.repGetLocationOfThisType(context, P(ref pLookupKind)); + fixed (CORINFO_LOOKUP_KIND* pLookupKindPtr = &pLookupKind) + mc.repGetLocationOfThisType(context, pLookupKindPtr); } private void getAddressOfPInvokeTarget(CORINFO_METHOD_STRUCT_* method, ref CORINFO_CONST_LOOKUP pLookup) { AddCall("getAddressOfPInvokeTarget"); - mc.repGetAddressOfPInvokeTarget(method, P(ref pLookup)); + fixed (CORINFO_CONST_LOOKUP* pLookupPtr = &pLookup) + mc.repGetAddressOfPInvokeTarget(method, pLookupPtr); } private void* GetCookieForInterpreterCalliSig(CORINFO_SIG_INFO* szMetaSig) @@ -1035,14 +1076,18 @@ private void GetProfilingHandle(ref bool pbHookFunction, ref void* pProfilerHand { AddCall("GetProfilingHandle"); fixed (void** p = &pProfilerHandle) - mc.repGetProfilingHandle(P(ref pbHookFunction), p, P(ref pbIndirectedHandles)); + fixed (bool* pbHookFunctionPtr = &pbHookFunction) + fixed (bool* pbIndirectedHandlesPtr = &pbIndirectedHandles) + mc.repGetProfilingHandle(pbHookFunctionPtr, p, pbIndirectedHandlesPtr); } private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_CALLINFO_FLAGS flags, CORINFO_CALL_INFO* pResult) { AddCall("getCallInfo"); - mc.repGetCallInfo(P(ref pResolvedToken), pConstrainedResolvedToken, callerHandle, flags, pResult, out uint exceptionCode); + uint exceptionCode; + fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) + mc.repGetCallInfo(pResolvedTokenPtr, pConstrainedResolvedToken, callerHandle, flags, pResult, out exceptionCode); if (exceptionCode != 0) ThrowRecordedException(exceptionCode); } @@ -1096,7 +1141,8 @@ private uint getFieldThreadLocalStoreID(CORINFO_FIELD_STRUCT_* field, ref void* private CORINFO_METHOD_STRUCT_* GetDelegateCtor(CORINFO_METHOD_STRUCT_* methHnd, CORINFO_CLASS_STRUCT_* clsHnd, CORINFO_METHOD_STRUCT_* targetMethodHnd, ref DelegateCtorArgs pCtorData) { AddCall("GetDelegateCtor"); - return mc.repGetDelegateCtor(methHnd, clsHnd, targetMethodHnd, P(ref pCtorData)); + fixed (DelegateCtorArgs* pCtorDataPtr = &pCtorData) + return mc.repGetDelegateCtor(methHnd, clsHnd, targetMethodHnd, pCtorDataPtr); } private void MethodCompileComplete(CORINFO_METHOD_STRUCT_* methHnd) @@ -1109,13 +1155,16 @@ private void MethodCompileComplete(CORINFO_METHOD_STRUCT_* methHnd) private bool getTailCallHelpers(ref CORINFO_RESOLVED_TOKEN callToken, CORINFO_SIG_INFO* sig, CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, ref CORINFO_TAILCALL_HELPERS pResult) { AddCall("getTailCallHelpers"); - return mc.repGetTailCallHelpers(P(ref callToken), sig, flags, P(ref pResult)); + fixed (CORINFO_RESOLVED_TOKEN* callTokenPtr = &callToken) + fixed (CORINFO_TAILCALL_HELPERS* pResultPtr = &pResult) + return mc.repGetTailCallHelpers(callTokenPtr, sig, flags, pResultPtr); } private CORINFO_CLASS_STRUCT_* getContinuationType(nuint dataSize, ref bool objRefs, nuint objRefsSize) { AddCall("getContinuationType"); - return mc.repGetContinuationType(dataSize, P(ref objRefs), objRefsSize); + fixed (bool* objRefsPtr = &objRefs) + return mc.repGetContinuationType(dataSize, objRefsPtr, objRefsSize); } private CORINFO_METHOD_STRUCT_* getAsyncResumptionStub(ref void* entryPoint) @@ -1128,7 +1177,8 @@ private bool getTailCallHelpers(ref CORINFO_RESOLVED_TOKEN callToken, CORINFO_SI private bool convertPInvokeCalliToCall(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool mustConvert) { AddCall("convertPInvokeCalliToCall"); - return mc.repConvertPInvokeCalliToCall(P(ref pResolvedToken), mustConvert); + fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) + return mc.repConvertPInvokeCalliToCall(pResolvedTokenPtr, mustConvert); } private bool notifyInstructionSetUsage(InstructionSet instructionSet, bool supportEnabled, bool preserveNegativeDependency) @@ -1140,7 +1190,8 @@ private bool notifyInstructionSetUsage(InstructionSet instructionSet, bool suppo private void updateEntryPointForTailCall(ref CORINFO_CONST_LOOKUP entryPoint) { AddCall("updateEntryPointForTailCall"); - mc.repUpdateEntryPointForTailCall(P(ref entryPoint)); + fixed (CORINFO_CONST_LOOKUP* entryPointPtr = &entryPoint) + mc.repUpdateEntryPointForTailCall(entryPointPtr); } // Allocates the code and data blocks: the hot code aligned as requested, and all the RO data in one block. @@ -1225,7 +1276,8 @@ private void setEHcount(uint cEH) private void setEHinfo(uint EHnumber, ref CORINFO_EH_CLAUSE clause) { AddCall("setEHinfo"); - cr.recSetEHinfo(EHnumber, P(ref clause)); + fixed (CORINFO_EH_CLAUSE* clausePtr = &clause) + cr.recSetEHinfo(EHnumber, clausePtr); } private bool logMsg(uint level, byte* fmt, IntPtr args) @@ -1267,7 +1319,10 @@ private HRESULT getPgoInstrumentationResults(CORINFO_METHOD_STRUCT_* ftnHnd, ref { AddCall("getPgoInstrumentationResults"); fixed (PgoInstrumentationSchema** ppSchema = &pSchema) - return mc.repGetPgoInstrumentationResults(ftnHnd, ppSchema, P(ref pCountSchemaItems), pInstrumentationData, P(ref pPgoSource), P(ref pDynamicPgo)); + fixed (uint* pCountSchemaItemsPtr = &pCountSchemaItems) + fixed (PgoSource* pPgoSourcePtr = &pPgoSource) + fixed (bool* pDynamicPgoPtr = &pDynamicPgo) + return mc.repGetPgoInstrumentationResults(ftnHnd, ppSchema, pCountSchemaItemsPtr, pInstrumentationData, pPgoSourcePtr, pDynamicPgoPtr); } private HRESULT allocPgoInstrumentationBySchema(CORINFO_METHOD_STRUCT_* ftnHnd, PgoInstrumentationSchema* pSchema, uint countSchemaItems, byte** pInstrumentationData) @@ -1309,7 +1364,8 @@ private uint getExpectedTargetArchitecture() private uint getJitFlags(ref CORJIT_FLAGS flags, uint sizeInBytes) { AddCall("getJitFlags"); - return jitInstance.getJitFlags(P(ref flags), sizeInBytes); + fixed (CORJIT_FLAGS* flagsPtr = &flags) + return jitInstance.getJitFlags(flagsPtr, sizeInBytes); } private CORINFO_WASM_TYPE_SYMBOL_STRUCT_* getWasmTypeSymbol(CorInfoWasmType* types, nuint typesSize) From 493ba4992475addcf9f93fd2da967f67a0e2a0bd Mon Sep 17 00:00:00 2001 From: am11 <3840695+am11@users.noreply.github.com> Date: Mon, 9 Nov 2026 13:14:27 +0200 Subject: [PATCH 09/10] Pass the JIT-EE byrefs through the record and replay methods as byrefs Co-authored-by: Cursor --- .../SuperPmi.Shared/CompileResult.Replay.cs | 14 +- .../SuperPmi.Shared/MethodContext.Identity.cs | 12 +- .../SuperPmi.Shared/MethodContext.Record.cs | 410 ++++++++-------- .../SuperPmi.Shared/MethodContext.Replay.cs | 451 +++++++++--------- .../SuperPmi.Shared/SpmiRecordsHelper.cs | 124 ++--- .../CorInfoImpl.Collector.cs | 155 ++---- .../managed/superpmi/CorInfoImpl.SuperPmi.cs | 173 ++----- .../superpmi/managed/superpmi/JitInstance.cs | 10 +- 8 files changed, 614 insertions(+), 735 deletions(-) diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CompileResult.Replay.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CompileResult.Replay.cs index 354b48e87f7214..8327c9a252d2fc 100644 --- a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CompileResult.Replay.cs +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/CompileResult.Replay.cs @@ -282,17 +282,17 @@ public uint repSetEHcount() return index < 0 ? 0 : SetEHcount.GetItem(index); } - public void recSetEHinfo(uint EHnumber, CORINFO_EH_CLAUSE* clause) + public void recSetEHinfo(uint EHnumber, ref CORINFO_EH_CLAUSE clause) { SetEHinfo ??= new LightWeightMap(); SetEHinfo.Add(EHnumber, new Agnostic_CORINFO_EH_CLAUSE { - Flags = (uint)clause->Flags, - TryOffset = clause->TryOffset, - TryLength = clause->TryLength, - HandlerOffset = clause->HandlerOffset, - HandlerLength = clause->HandlerLength, - ClassToken = clause->ClassTokenOrOffset, + Flags = (uint)clause.Flags, + TryOffset = clause.TryOffset, + TryLength = clause.TryLength, + HandlerOffset = clause.HandlerOffset, + HandlerLength = clause.HandlerLength, + ClassToken = clause.ClassTokenOrOffset, }); } diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Identity.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Identity.cs index 833429c7d1c0e2..5abf2aa246ca2f 100644 --- a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Identity.cs +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Identity.cs @@ -37,7 +37,7 @@ public CORINFO_METHOD_INFO repCompileMethod(out uint flags, out CORINFO_OS os) { ulong* raw = stackalloc ulong[1 + InstructionFlagsFieldCount]; new Span(raw, 1 + InstructionFlagsFieldCount).Clear(); - repGetJitFlags((CORJIT_FLAGS*)raw, (uint)(sizeof(ulong) * (1 + InstructionFlagsFieldCount))); + repGetJitFlags(ref *((CORJIT_FLAGS*)raw), (uint)(sizeof(ulong) * (1 + InstructionFlagsFieldCount))); return (raw[0], new ReadOnlySpan(raw + 1, InstructionFlagsFieldCount).ToArray()); } @@ -69,12 +69,12 @@ public byte[] dumpMethodIdentityInfoToBuffer(bool ignoreMethodName = false, CORI private void AppendPgoCountersHash(ByteBuilder buff, CORINFO_METHOD_STRUCT_* ftn) { - PgoInstrumentationSchema* schema; - uint schemaCount; + PgoInstrumentationSchema* schema = null; + uint schemaCount = 0; byte* schemaData; - PgoSource pgoSource; - bool dynamicPgo; - if (repGetPgoInstrumentationResults(ftn, &schema, &schemaCount, &schemaData, &pgoSource, &dynamicPgo) < 0) + PgoSource pgoSource = default; + bool dynamicPgo = false; + if (repGetPgoInstrumentationResults(ftn, ref schema, ref schemaCount, &schemaData, ref pgoSource, ref dynamicPgo) < 0) return; ulong minOffset = ulong.MaxValue; diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Record.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Record.cs index 1762d8012e789b..29b1be452013e8 100644 --- a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Record.cs +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Record.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Internal.JitInterface; using Internal.Pgo; @@ -148,29 +149,29 @@ public void recGetClassAssemblyName(CORINFO_CLASS_STRUCT_* cls, byte* assemblyNa GetClassAssemblyName.Add(key, value); } - public void recGetVars(CORINFO_METHOD_STRUCT_* ftn, uint* cVars, ILVarInfo** vars_in, bool* extendOthers) + public void recGetVars(CORINFO_METHOD_STRUCT_* ftn, ref uint cVars, ILVarInfo** vars_in, ref bool extendOthers) { GetVars ??= new(); Agnostic_GetVars value = default; - value.cVars = (uint)*cVars; + value.cVars = (uint)cVars; value.vars_offset = - (uint)GetVars.AddBuffer(Bytes(*vars_in, (nuint)(sizeof(ILVarInfo) * (*cVars)))); - value.extendOthers = (*extendOthers ? 1u : 0u); + (uint)GetVars.AddBuffer(Bytes(*vars_in, (nuint)(sizeof(ILVarInfo) * (cVars)))); + value.extendOthers = (extendOthers ? 1u : 0u); ulong key = CastHandle(ftn); GetVars.Add(key, value); } - public void recGetBoundaries(CORINFO_METHOD_STRUCT_* ftn, uint* cILOffsets, uint** pILOffsets, BoundaryTypes* implicitBoundaries) + public void recGetBoundaries(CORINFO_METHOD_STRUCT_* ftn, ref uint cILOffsets, ref uint* pILOffsets, BoundaryTypes* implicitBoundaries) { GetBoundaries ??= new(); Agnostic_GetBoundaries value = default; - value.cILOffsets = (uint)*cILOffsets; + value.cILOffsets = (uint)cILOffsets; value.pILOffset_offset = - (uint)GetBoundaries.AddBuffer(Bytes(*pILOffsets, sizeof(uint) * (*cILOffsets))); + (uint)GetBoundaries.AddBuffer(Bytes(pILOffsets, sizeof(uint) * (cILOffsets))); value.implicitBoundaries = (uint)*implicitBoundaries; ulong key = CastHandle(ftn); @@ -234,12 +235,12 @@ public void recGetMethodNameFromMetadata(CORINFO_METHOD_STRUCT_* ftn, byte* meth GetMethodNameFromMetadata.Add(key, value); } - public void recGetJitFlags(CORJIT_FLAGS* jitFlags, uint sizeInBytes, uint result) + public void recGetJitFlags(ref CORJIT_FLAGS jitFlags, uint sizeInBytes, uint result) { GetJitFlags ??= new(); DD value = default; - value.A = (uint)GetJitFlags.AddBuffer(Bytes(jitFlags, sizeInBytes)); + value.A = (uint)GetJitFlags.AddBuffer(MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref jitFlags), (int)sizeInBytes)); value.B = result; // NOTE: getJitFlags() is expected to be idempotent per method, so the mapping key is always @@ -262,12 +263,12 @@ public void recCanInline(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUC CanInline.Add(key, value); } - public void recResolveToken(CORINFO_RESOLVED_TOKEN* pResolvedToken, uint exceptionCode) + public void recResolveToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken, uint exceptionCode) { ResolveToken ??= new(); Agnostic_CORINFO_RESOLVED_TOKENin key = default; - key = CreateAgnostic_CORINFO_RESOLVED_TOKENin(pResolvedToken); + key = CreateAgnostic_CORINFO_RESOLVED_TOKENin(ref pResolvedToken); ResolveTokenValue value = default; if (exceptionCode != 0) @@ -280,24 +281,24 @@ public void recResolveToken(CORINFO_RESOLVED_TOKEN* pResolvedToken, uint excepti } else { - value.tokenOut = StoreAgnostic_CORINFO_RESOLVED_TOKENout(pResolvedToken, ResolveToken); + value.tokenOut = StoreAgnostic_CORINFO_RESOLVED_TOKENout(ref pResolvedToken, ResolveToken); } value.exceptionCode = exceptionCode; ResolveToken.Add(key, value); } - public void recGetCallInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_CALLINFO_FLAGS flags, CORINFO_CALL_INFO* pResult, uint exceptionCode) + public void recGetCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_CALLINFO_FLAGS flags, CORINFO_CALL_INFO* pResult, uint exceptionCode) { GetCallInfo ??= new(); Agnostic_GetCallInfo key = default; - key.ResolvedToken = StoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, GetCallInfo); + key.ResolvedToken = StoreAgnostic_CORINFO_RESOLVED_TOKEN(ref pResolvedToken, GetCallInfo); if (pConstrainedResolvedToken != null) { key.ConstrainedResolvedToken = - StoreAgnostic_CORINFO_RESOLVED_TOKEN(pConstrainedResolvedToken, GetCallInfo); + StoreAgnostic_CORINFO_RESOLVED_TOKEN(ref *pConstrainedResolvedToken, GetCallInfo); } key.callerHandle = CastHandle(callerHandle); @@ -321,7 +322,7 @@ public void recGetCallInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_RESOL value.contextHandle = CastHandle(pResult->contextHandle); value.exactContextNeedsRuntimeLookup = (pResult->exactContextNeedsRuntimeLookup ? 1u : 0u); - value.stubLookup = StoreAgnostic_CORINFO_LOOKUP(&pResult->codePointerOrStubLookup); + value.stubLookup = StoreAgnostic_CORINFO_LOOKUP(ref pResult->codePointerOrStubLookup); value.instParamLookup.accessType = (uint)pResult->instParamLookup.accessType; value.instParamLookup.handle = CastHandle(pResult->instParamLookup.handle); @@ -332,18 +333,18 @@ public void recGetCallInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_RESOL GetCallInfo.Add(key, value); } - public void recExpandRawHandleIntrinsic(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_GENERICHANDLE_RESULT* pResult) + public void recExpandRawHandleIntrinsic(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_GENERICHANDLE_RESULT pResult) { ExpandRawHandleIntrinsic ??= new(); Agnostic_ExpandRawHandleIntrinsic key = default; - key.ResolvedToken = CreateAgnostic_CORINFO_RESOLVED_TOKENin(pResolvedToken); + key.ResolvedToken = CreateAgnostic_CORINFO_RESOLVED_TOKENin(ref pResolvedToken); key.hCallerHandle = CastHandle(callerHandle); Agnostic_CORINFO_GENERICHANDLE_RESULT value = default; - value.lookup = StoreAgnostic_CORINFO_LOOKUP(&pResult->lookup); - value.compileTimeHandle = CastHandle(pResult->compileTimeHandle); - value.handleType = (uint)pResult->handleType; + value.lookup = StoreAgnostic_CORINFO_LOOKUP(ref pResult.lookup); + value.compileTimeHandle = CastHandle(pResult.compileTimeHandle); + value.handleType = (uint)pResult.handleType; ExpandRawHandleIntrinsic.Add(key, value); } @@ -579,32 +580,32 @@ public void recGetObjectType(CORINFO_OBJECT_STRUCT_* objPtr, CORINFO_CLASS_STRUC GetObjectType.Add(key, value); } - public void recGetReadyToRunHelper(CORINFO_RESOLVED_TOKEN* pResolvedToken, CorInfoHelpFunc id, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_CONST_LOOKUP* pLookup, bool result) + public void recGetReadyToRunHelper(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CorInfoHelpFunc id, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_CONST_LOOKUP pLookup, bool result) { GetReadyToRunHelper ??= new(); GetReadyToRunHelper_TOKENin key = default; - key.ResolvedToken = StoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, GetReadyToRunHelper); + key.ResolvedToken = StoreAgnostic_CORINFO_RESOLVED_TOKEN(ref pResolvedToken, GetReadyToRunHelper); key.id = (uint)id; key.callerHandle = CastHandle(callerHandle); GetReadyToRunHelper_TOKENout value = default; - value.Lookup = StoreAgnostic_CORINFO_CONST_LOOKUP(pLookup); + value.Lookup = StoreAgnostic_CORINFO_CONST_LOOKUP(ref pLookup); value.result = result ? (byte)1 : (byte)0; GetReadyToRunHelper.Add(key, value); } - public void recGetReadyToRunDelegateCtorHelper(CORINFO_RESOLVED_TOKEN* pTargetMethod, uint targetConstraint, CORINFO_CLASS_STRUCT_* delegateType, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_LOOKUP* pLookup) + public void recGetReadyToRunDelegateCtorHelper(ref CORINFO_RESOLVED_TOKEN pTargetMethod, uint targetConstraint, CORINFO_CLASS_STRUCT_* delegateType, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_LOOKUP pLookup) { GetReadyToRunDelegateCtorHelper ??= new(); GetReadyToRunDelegateCtorHelper_TOKENIn key = default; key.TargetMethod = - StoreAgnostic_CORINFO_RESOLVED_TOKEN(pTargetMethod, GetReadyToRunDelegateCtorHelper); + StoreAgnostic_CORINFO_RESOLVED_TOKEN(ref pTargetMethod, GetReadyToRunDelegateCtorHelper); key.targetConstraint = targetConstraint; key.delegateType = CastHandle(delegateType); key.callerHandle = CastHandle(callerHandle); - Agnostic_CORINFO_LOOKUP value = StoreAgnostic_CORINFO_LOOKUP(pLookup); + Agnostic_CORINFO_LOOKUP value = StoreAgnostic_CORINFO_LOOKUP(ref pLookup); GetReadyToRunDelegateCtorHelper.Add(key, value); } @@ -615,25 +616,25 @@ public void recGetHelperFtn(CorInfoHelpFunc ftnNum, CORINFO_CONST_LOOKUP pNative uint key = (uint)ftnNum; Agnostic_GetHelperFtn value = default; - value.helperLookup = StoreAgnostic_CORINFO_CONST_LOOKUP(&pNativeEntrypoint); + value.helperLookup = StoreAgnostic_CORINFO_CONST_LOOKUP(ref pNativeEntrypoint); value.helperMethod = CastHandle(methodHandle); GetHelperFtn.Add(key, value); } - public void recGetJustMyCodeHandle(CORINFO_METHOD_STRUCT_* method, CORINFO_JUST_MY_CODE_HANDLE_** ppIndirection, CORINFO_JUST_MY_CODE_HANDLE_* result) + public void recGetJustMyCodeHandle(CORINFO_METHOD_STRUCT_* method, ref CORINFO_JUST_MY_CODE_HANDLE_* ppIndirection, CORINFO_JUST_MY_CODE_HANDLE_* result) { GetJustMyCodeHandle ??= new(); DLDL value = default; - value.A = CastPointer(*ppIndirection); + value.A = CastPointer(ppIndirection); value.B = CastHandle(result); ulong key = CastHandle(method); GetJustMyCodeHandle.Add(key, value); } - public void recGetFunctionEntryPoint(CORINFO_METHOD_STRUCT_* ftn, CORINFO_CONST_LOOKUP* pResult, CORINFO_ACCESS_FLAGS accessFlags) + public void recGetFunctionEntryPoint(CORINFO_METHOD_STRUCT_* ftn, ref CORINFO_CONST_LOOKUP pResult, CORINFO_ACCESS_FLAGS accessFlags) { GetFunctionEntryPoint ??= new(); @@ -642,8 +643,8 @@ public void recGetFunctionEntryPoint(CORINFO_METHOD_STRUCT_* ftn, CORINFO_CONST_ key.B = (uint)accessFlags; DLD value = default; - value.A = CastPointer(pResult->addr); // First union member - value.B = (uint)pResult->accessType; + value.A = CastPointer(pResult.addr); // First union member + value.B = (uint)pResult.accessType; GetFunctionEntryPoint.Add(key, value); } @@ -663,26 +664,26 @@ public void recConstructStringLiteral(CORINFO_MODULE_STRUCT_* moduleHandle, uint ConstructStringLiteral.Add(key, value); } - public void recConvertPInvokeCalliToCall(CORINFO_RESOLVED_TOKEN* pResolvedToken, bool fMustConvert, bool result) + public void recConvertPInvokeCalliToCall(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool fMustConvert, bool result) { ConvertPInvokeCalliToCall ??= new(); DLD key = default; - key.A = CastHandle(pResolvedToken->tokenScope); - key.B = (uint)pResolvedToken->token; + key.A = CastHandle(pResolvedToken.tokenScope); + key.B = (uint)pResolvedToken.token; DLDL value = default; - value.A = result ? CastHandle(pResolvedToken->hClass) : 0; - value.B = result ? CastHandle(pResolvedToken->hMethod) : 0; + value.A = result ? CastHandle(pResolvedToken.hClass) : 0; + value.B = result ? CastHandle(pResolvedToken.hMethod) : 0; ConvertPInvokeCalliToCall.Add(key, value); } - public void recEmptyStringLiteral(void** pValue, InfoAccessType result) + public void recEmptyStringLiteral(ref void* pValue, InfoAccessType result) { EmptyStringLiteral ??= new(); DLD temp2 = default; - temp2.A = CastPointer(*pValue); + temp2.A = CastPointer(pValue); temp2.B = (uint)result; EmptyStringLiteral.Append(temp2); @@ -856,24 +857,24 @@ public void recGetNewHelper(CORINFO_CLASS_STRUCT_* classHandle, bool hasSideEffe GetNewHelper.Add(key, value); } - public void recEmbedGenericHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken, bool fEmbedParent, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_GENERICHANDLE_RESULT* pResult) + public void recEmbedGenericHandle(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool fEmbedParent, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_GENERICHANDLE_RESULT pResult) { EmbedGenericHandle ??= new(); Agnostic_EmbedGenericHandle key = default; - key.ResolvedToken = StoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, EmbedGenericHandle); + key.ResolvedToken = StoreAgnostic_CORINFO_RESOLVED_TOKEN(ref pResolvedToken, EmbedGenericHandle); key.fEmbedParent = (fEmbedParent ? 1u : 0u); key.hCallerHandle = CastHandle(callerHandle); Agnostic_CORINFO_GENERICHANDLE_RESULT value = default; - value.lookup = StoreAgnostic_CORINFO_LOOKUP(&pResult->lookup); - value.compileTimeHandle = CastHandle(pResult->compileTimeHandle); - value.handleType = (uint)pResult->handleType; + value.lookup = StoreAgnostic_CORINFO_LOOKUP(ref pResult.lookup); + value.compileTimeHandle = CastHandle(pResult.compileTimeHandle); + value.handleType = (uint)pResult.handleType; EmbedGenericHandle.Add(key, value); } - public void recGetEHinfo(CORINFO_METHOD_STRUCT_* ftn, uint EHnumber, CORINFO_EH_CLAUSE* clause) + public void recGetEHinfo(CORINFO_METHOD_STRUCT_* ftn, uint EHnumber, ref CORINFO_EH_CLAUSE clause) { GetEHinfo ??= new(); @@ -882,24 +883,24 @@ public void recGetEHinfo(CORINFO_METHOD_STRUCT_* ftn, uint EHnumber, CORINFO_EH_ key.B = (uint)EHnumber; Agnostic_CORINFO_EH_CLAUSE value = default; - value.Flags = (uint)clause->Flags; - value.TryOffset = (uint)clause->TryOffset; - value.TryLength = (uint)clause->TryLength; - value.HandlerOffset = (uint)clause->HandlerOffset; - value.HandlerLength = (uint)clause->HandlerLength; - value.ClassToken = (uint)clause->ClassTokenOrOffset; + value.Flags = (uint)clause.Flags; + value.TryOffset = (uint)clause.TryOffset; + value.TryLength = (uint)clause.TryLength; + value.HandlerOffset = (uint)clause.HandlerOffset; + value.HandlerLength = (uint)clause.HandlerLength; + value.ClassToken = (uint)clause.ClassTokenOrOffset; GetEHinfo.Add(key, value); } - public void recGetMethodVTableOffset(CORINFO_METHOD_STRUCT_* method, uint* offsetOfIndirection, uint* offsetAfterIndirection, bool* isRelative) + public void recGetMethodVTableOffset(CORINFO_METHOD_STRUCT_* method, ref uint offsetOfIndirection, ref uint offsetAfterIndirection, ref bool isRelative) { GetMethodVTableOffset ??= new(); DDD value = default; - value.A = (uint)*offsetOfIndirection; - value.B = (uint)*offsetAfterIndirection; - value.C = *isRelative ? 1u : 0u; + value.A = (uint)offsetOfIndirection; + value.B = (uint)offsetAfterIndirection; + value.C = isRelative ? 1u : 0u; ulong key = CastHandle(method); GetMethodVTableOffset.Add(key, value); @@ -919,19 +920,19 @@ public void recResolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info, bool re key.pResolvedTokenVirtualMethodNonNull = info->pResolvedTokenVirtualMethod != null ? 1u : 0u; if (key.pResolvedTokenVirtualMethodNonNull != 0) - key.pResolvedTokenVirtualMethod = StoreAgnostic_CORINFO_RESOLVED_TOKEN(info->pResolvedTokenVirtualMethod, ResolveToken); + key.pResolvedTokenVirtualMethod = StoreAgnostic_CORINFO_RESOLVED_TOKEN(ref *info->pResolvedTokenVirtualMethod, ResolveToken); Agnostic_ResolveVirtualMethodResult result = default; result.returnValue = returnValue ? (byte)1 : (byte)0; result.devirtualizedMethod = CastHandle(info->devirtualizedMethod); result.tokenLookupContext = CastHandle(info->tokenLookupContext); result.detail = (uint)info->detail; - result.instParamLookup = StoreAgnostic_CORINFO_LOOKUP(&info->instParamLookup); + result.instParamLookup = StoreAgnostic_CORINFO_LOOKUP(ref info->instParamLookup); if (returnValue) { - result.resolvedTokenDevirtualizedMethod = StoreAgnostic_CORINFO_RESOLVED_TOKEN(&info->resolvedTokenDevirtualizedMethod, ResolveToken); - result.resolvedTokenDevirtualizedUnboxedMethod = StoreAgnostic_CORINFO_RESOLVED_TOKEN(&info->resolvedTokenDevirtualizedUnboxedMethod, ResolveToken); + result.resolvedTokenDevirtualizedMethod = StoreAgnostic_CORINFO_RESOLVED_TOKEN(ref info->resolvedTokenDevirtualizedMethod, ResolveToken); + result.resolvedTokenDevirtualizedUnboxedMethod = StoreAgnostic_CORINFO_RESOLVED_TOKEN(ref info->resolvedTokenDevirtualizedUnboxedMethod, ResolveToken); } else { @@ -983,24 +984,24 @@ public void recGetSZArrayHelperEnumeratorClass(CORINFO_CLASS_STRUCT_* cls, CORIN GetSZArrayHelperEnumeratorClass.Add(key, value); } - public void recGetTokenTypeAsHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_CLASS_STRUCT_* result) + public void recGetTokenTypeAsHandle(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_CLASS_STRUCT_* result) { GetTokenTypeAsHandle ??= new(); GetTokenTypeAsHandleValue key = default; - key.hMethod = CastHandle(pResolvedToken->hMethod); - key.hField = CastHandle(pResolvedToken->hField); + key.hMethod = CastHandle(pResolvedToken.hMethod); + key.hField = CastHandle(pResolvedToken.hField); ulong value = CastHandle(result); GetTokenTypeAsHandle.Add(key, value); } - public void recGetFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult) + public void recGetFieldInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult) { GetFieldInfo ??= new(); Agnostic_GetFieldInfo key = default; - key.ResolvedToken = StoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, GetFieldInfo); + key.ResolvedToken = StoreAgnostic_CORINFO_RESOLVED_TOKEN(ref pResolvedToken, GetFieldInfo); key.callerHandle = CastHandle(callerHandle); key.flags = (uint)flags; @@ -1013,7 +1014,7 @@ public void recGetFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METH value.structType = CastHandle(pResult->structType); value.accessAllowed = (uint)pResult->accessAllowed; value.accessCalloutHelper = StoreAgnostic_CORINFO_HELPER_DESC(pResult->accessCalloutHelper); - value.fieldLookup = StoreAgnostic_CORINFO_CONST_LOOKUP(&pResult->fieldLookup); + value.fieldLookup = StoreAgnostic_CORINFO_CONST_LOOKUP(ref pResult->fieldLookup); GetFieldInfo.Add(key, value); } @@ -1033,7 +1034,7 @@ public void recGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* Agnostic_GetThreadLocalStaticBlocksInfo value = default; - value.tlsIndex = StoreAgnostic_CORINFO_CONST_LOOKUP(&pInfo->tlsIndex); + value.tlsIndex = StoreAgnostic_CORINFO_CONST_LOOKUP(ref pInfo->tlsIndex); value.tlsGetAddrFtnPtr = CastPointer(pInfo->tlsGetAddrFtnPtr); value.tlsIndexObject = CastPointer(pInfo->tlsIndexObject); value.threadVarsSection = CastPointer(pInfo->threadVarsSection); @@ -1052,26 +1053,26 @@ public void recGetThreadLocalStaticInfo_NativeAOT(CORINFO_THREAD_STATIC_INFO_NAT GetThreadLocalStaticInfo_NativeAOT ??= new(); Agnostic_GetThreadStaticInfo_NativeAOT value = default; - value.tlsRootObject = StoreAgnostic_CORINFO_CONST_LOOKUP(&pInfo->tlsRootObject); - value.tlsIndexObject = StoreAgnostic_CORINFO_CONST_LOOKUP(&pInfo->tlsIndexObject); + value.tlsRootObject = StoreAgnostic_CORINFO_CONST_LOOKUP(ref pInfo->tlsRootObject); + value.tlsIndexObject = StoreAgnostic_CORINFO_CONST_LOOKUP(ref pInfo->tlsIndexObject); value.offsetOfThreadLocalStoragePointer = pInfo->offsetOfThreadLocalStoragePointer; - value.threadStaticBaseSlow = StoreAgnostic_CORINFO_CONST_LOOKUP(&pInfo->threadStaticBaseSlow); - value.tlsGetAddrFtnPtr = StoreAgnostic_CORINFO_CONST_LOOKUP(&pInfo->tlsGetAddrFtnPtr); + value.threadStaticBaseSlow = StoreAgnostic_CORINFO_CONST_LOOKUP(ref pInfo->threadStaticBaseSlow); + value.tlsGetAddrFtnPtr = StoreAgnostic_CORINFO_CONST_LOOKUP(ref pInfo->tlsGetAddrFtnPtr); ulong key = 1; GetThreadLocalStaticInfo_NativeAOT.Add(key, value); } - public void recEmbedMethodHandle(CORINFO_METHOD_STRUCT_* handle, void** ppIndirection, CORINFO_METHOD_STRUCT_* result) + public void recEmbedMethodHandle(CORINFO_METHOD_STRUCT_* handle, ref void* ppIndirection, CORINFO_METHOD_STRUCT_* result) { EmbedMethodHandle ??= new(); DLDL value = default; - if (ppIndirection == null) + if (IsNullRef(ref ppIndirection)) value.A = 0; else - value.A = CastPointer(*ppIndirection); + value.A = CastPointer(ppIndirection); value.B = CastHandle(result); ulong key = CastHandle(handle); @@ -1160,40 +1161,40 @@ public void recGetClassAlignmentRequirement(CORINFO_CLASS_STRUCT_* cls, bool fDo GetClassAlignmentRequirement.Add(key, value); } - public void recCanAccessClass(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_HELPER_DESC* pAccessHelper, CorInfoIsAccessAllowedResult result) + public void recCanAccessClass(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_HELPER_DESC pAccessHelper, CorInfoIsAccessAllowedResult result) { CanAccessClass ??= new(); Agnostic_CanAccessClassIn key = default; - key.ResolvedToken = StoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, CanAccessClass); + key.ResolvedToken = StoreAgnostic_CORINFO_RESOLVED_TOKEN(ref pResolvedToken, CanAccessClass); key.callerHandle = CastHandle(callerHandle); Agnostic_CanAccessClassOut value = default; - value.AccessHelper = StoreAgnostic_CORINFO_HELPER_DESC(*pAccessHelper); + value.AccessHelper = StoreAgnostic_CORINFO_HELPER_DESC(pAccessHelper); value.result = (uint)result; CanAccessClass.Add(key, value); } - public void recGetCastingHelper(CORINFO_RESOLVED_TOKEN* pResolvedToken, bool fThrowing, CorInfoHelpFunc result) + public void recGetCastingHelper(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool fThrowing, CorInfoHelpFunc result) { GetCastingHelper ??= new(); Agnostic_GetCastingHelper key = default; - key.hClass = CastHandle(pResolvedToken->hClass); + key.hClass = CastHandle(pResolvedToken.hClass); key.fThrowing = (fThrowing ? 1u : 0u); uint value = (uint)result; GetCastingHelper.Add(key, value); } - public void recEmbedModuleHandle(CORINFO_MODULE_STRUCT_* handle, void** ppIndirection, CORINFO_MODULE_STRUCT_* result) + public void recEmbedModuleHandle(CORINFO_MODULE_STRUCT_* handle, ref void* ppIndirection, CORINFO_MODULE_STRUCT_* result) { EmbedModuleHandle ??= new(); DLDL value = default; - if (ppIndirection != null) - value.A = CastPointer(*ppIndirection); + if (!IsNullRef(ref ppIndirection)) + value.A = CastPointer(ppIndirection); else value.A = 0; value.B = CastHandle(result); @@ -1202,13 +1203,13 @@ public void recEmbedModuleHandle(CORINFO_MODULE_STRUCT_* handle, void** ppIndire EmbedModuleHandle.Add(key, value); } - public void recEmbedClassHandle(CORINFO_CLASS_STRUCT_* handle, void** ppIndirection, CORINFO_CLASS_STRUCT_* result) + public void recEmbedClassHandle(CORINFO_CLASS_STRUCT_* handle, ref void* ppIndirection, CORINFO_CLASS_STRUCT_* result) { EmbedClassHandle ??= new(); DLDL value = default; - if (ppIndirection != null) - value.A = CastPointer(*ppIndirection); + if (!IsNullRef(ref ppIndirection)) + value.A = CastPointer(ppIndirection); else value.A = 0; value.B = CastHandle(result); @@ -1271,87 +1272,87 @@ public void recFindSig(CORINFO_MODULE_STRUCT_* moduleHandle, uint sigTOK, CORINF FindSig.Add(key, value); } - public void recGetEEInfo(CORINFO_EE_INFO* pEEInfoOut) + public void recGetEEInfo(ref CORINFO_EE_INFO pEEInfoOut) { GetEEInfo ??= new(); Agnostic_CORINFO_EE_INFO value = default; - value.inlinedCallFrameInfo.size = (uint)pEEInfoOut->inlinedCallFrameInfo.size; - value.inlinedCallFrameInfo.sizeWithSecretStubArg = (uint)pEEInfoOut->inlinedCallFrameInfo.sizeWithSecretStubArg; - value.inlinedCallFrameInfo.offsetOfFrameLink = (uint)pEEInfoOut->inlinedCallFrameInfo.offsetOfFrameLink; - value.inlinedCallFrameInfo.offsetOfCallSiteSP = (uint)pEEInfoOut->inlinedCallFrameInfo.offsetOfCallSiteSP; - value.inlinedCallFrameInfo.offsetOfCalleeSavedFP = (uint)pEEInfoOut->inlinedCallFrameInfo.offsetOfCalleeSavedFP; - value.inlinedCallFrameInfo.offsetOfCallTarget = (uint)pEEInfoOut->inlinedCallFrameInfo.offsetOfCallTarget; - value.inlinedCallFrameInfo.offsetOfReturnAddress = (uint)pEEInfoOut->inlinedCallFrameInfo.offsetOfReturnAddress; - value.inlinedCallFrameInfo.offsetOfSecretStubArg = (uint)pEEInfoOut->inlinedCallFrameInfo.offsetOfSecretStubArg; - value.inlinedCallFrameInfo.offsetOfSPAfterProlog = (uint)pEEInfoOut->inlinedCallFrameInfo.offsetOfSPAfterProlog; - value.offsetOfThreadFrame = (uint)pEEInfoOut->offsetOfThreadFrame; - value.offsetOfGCState = (uint)pEEInfoOut->offsetOfGCState; - value.offsetOfDelegateInstance = (uint)pEEInfoOut->offsetOfDelegateInstance; - value.offsetOfDelegateFirstTarget = (uint)pEEInfoOut->offsetOfDelegateFirstTarget; - value.sizeOfReversePInvokeFrame = (uint)pEEInfoOut->sizeOfReversePInvokeFrame; - value.osPageSize = (uint)pEEInfoOut->osPageSize; - value.maxUncheckedOffsetForNullObject = (uint)pEEInfoOut->maxUncheckedOffsetForNullObject; - value.targetAbi = (uint)pEEInfoOut->targetAbi; - value.osType = (uint)pEEInfoOut->osType; + value.inlinedCallFrameInfo.size = (uint)pEEInfoOut.inlinedCallFrameInfo.size; + value.inlinedCallFrameInfo.sizeWithSecretStubArg = (uint)pEEInfoOut.inlinedCallFrameInfo.sizeWithSecretStubArg; + value.inlinedCallFrameInfo.offsetOfFrameLink = (uint)pEEInfoOut.inlinedCallFrameInfo.offsetOfFrameLink; + value.inlinedCallFrameInfo.offsetOfCallSiteSP = (uint)pEEInfoOut.inlinedCallFrameInfo.offsetOfCallSiteSP; + value.inlinedCallFrameInfo.offsetOfCalleeSavedFP = (uint)pEEInfoOut.inlinedCallFrameInfo.offsetOfCalleeSavedFP; + value.inlinedCallFrameInfo.offsetOfCallTarget = (uint)pEEInfoOut.inlinedCallFrameInfo.offsetOfCallTarget; + value.inlinedCallFrameInfo.offsetOfReturnAddress = (uint)pEEInfoOut.inlinedCallFrameInfo.offsetOfReturnAddress; + value.inlinedCallFrameInfo.offsetOfSecretStubArg = (uint)pEEInfoOut.inlinedCallFrameInfo.offsetOfSecretStubArg; + value.inlinedCallFrameInfo.offsetOfSPAfterProlog = (uint)pEEInfoOut.inlinedCallFrameInfo.offsetOfSPAfterProlog; + value.offsetOfThreadFrame = (uint)pEEInfoOut.offsetOfThreadFrame; + value.offsetOfGCState = (uint)pEEInfoOut.offsetOfGCState; + value.offsetOfDelegateInstance = (uint)pEEInfoOut.offsetOfDelegateInstance; + value.offsetOfDelegateFirstTarget = (uint)pEEInfoOut.offsetOfDelegateFirstTarget; + value.sizeOfReversePInvokeFrame = (uint)pEEInfoOut.sizeOfReversePInvokeFrame; + value.osPageSize = (uint)pEEInfoOut.osPageSize; + value.maxUncheckedOffsetForNullObject = (uint)pEEInfoOut.maxUncheckedOffsetForNullObject; + value.targetAbi = (uint)pEEInfoOut.targetAbi; + value.osType = (uint)pEEInfoOut.osType; GetEEInfo.Add(0, value); } - public void recGetAsyncInfo(CORINFO_ASYNC_INFO* pAsyncInfo) + public void recGetAsyncInfo(ref CORINFO_ASYNC_INFO pAsyncInfo) { GetAsyncInfo ??= new(); Agnostic_CORINFO_ASYNC_INFO value = default; - value.continuationClsHnd = CastHandle(pAsyncInfo->continuationClsHnd); - value.continuationNextFldHnd = CastHandle(pAsyncInfo->continuationNextFldHnd); - value.continuationResumeInfoFldHnd = CastHandle(pAsyncInfo->continuationResumeInfoFldHnd); - value.continuationStateFldHnd = CastHandle(pAsyncInfo->continuationStateFldHnd); - value.continuationFlagsFldHnd = CastHandle(pAsyncInfo->continuationFlagsFldHnd); - value.captureExecutionContextMethHnd = CastHandle(pAsyncInfo->captureExecutionContextMethHnd); - value.captureContinuationContextMethHnd = CastHandle(pAsyncInfo->captureContinuationContextMethHnd); - 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); + value.continuationClsHnd = CastHandle(pAsyncInfo.continuationClsHnd); + value.continuationNextFldHnd = CastHandle(pAsyncInfo.continuationNextFldHnd); + value.continuationResumeInfoFldHnd = CastHandle(pAsyncInfo.continuationResumeInfoFldHnd); + value.continuationStateFldHnd = CastHandle(pAsyncInfo.continuationStateFldHnd); + value.continuationFlagsFldHnd = CastHandle(pAsyncInfo.continuationFlagsFldHnd); + value.captureExecutionContextMethHnd = CastHandle(pAsyncInfo.captureExecutionContextMethHnd); + value.captureContinuationContextMethHnd = CastHandle(pAsyncInfo.captureContinuationContextMethHnd); + 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); GetAsyncInfo.Add(0, value); } - public void recGetWasmWellKnownGlobals(CORINFO_WASM_WELLKNOWN_GLOBALS* pBaseGlobals) + public void recGetWasmWellKnownGlobals(ref CORINFO_WASM_WELLKNOWN_GLOBALS pBaseGlobals) { GetWasmWellKnownGlobals ??= new(); Agnostic_CORINFO_WASM_WELLKNOWN_GLOBALS value = default; - value.stackPointer = CastHandle(pBaseGlobals->stackPointer); - value.imageBase = CastHandle(pBaseGlobals->imageBase); - value.tableBase = CastHandle(pBaseGlobals->tableBase); - value.asyncContinuation = CastHandle(pBaseGlobals->asyncContinuation); + value.stackPointer = CastHandle(pBaseGlobals.stackPointer); + value.imageBase = CastHandle(pBaseGlobals.imageBase); + value.tableBase = CastHandle(pBaseGlobals.tableBase); + value.asyncContinuation = CastHandle(pBaseGlobals.asyncContinuation); GetWasmWellKnownGlobals.Add(0, value); } - public void recGetAwaitReturnCall(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_CONTEXT_STRUCT** contextHandle, CORINFO_LOOKUP* instArg, CORINFO_METHOD_STRUCT_* methHnd) + public void recGetAwaitReturnCall(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_CONTEXT_STRUCT** contextHandle, ref CORINFO_LOOKUP instArg, CORINFO_METHOD_STRUCT_* methHnd) { GetAwaitReturnCall ??= new(); Agnostic_GetAwaitReturnCallResult value = default; value.methodHnd = CastHandle(methHnd); value.contextHandle = CastHandle(*contextHandle); - value.instArg = StoreAgnostic_CORINFO_LOOKUP(instArg); + value.instArg = StoreAgnostic_CORINFO_LOOKUP(ref instArg); GetAwaitReturnCall.Add(CastHandle(callerHnd), value); } - public void recGetAwaitAwaiterInContinuationCall(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_RESOLVED_TOKEN* pResolvedToken, bool isUnsafe, CORINFO_CONTEXT_STRUCT** contextHandle, CORINFO_LOOKUP* instArg, CORINFO_METHOD_STRUCT_* methHnd) + public void recGetAwaitAwaiterInContinuationCall(CORINFO_METHOD_STRUCT_* callerHnd, ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool isUnsafe, CORINFO_CONTEXT_STRUCT** contextHandle, ref CORINFO_LOOKUP instArg, CORINFO_METHOD_STRUCT_* methHnd) { if (GetAwaitAwaiterInContinuationCall == null) { @@ -1362,13 +1363,13 @@ public void recGetAwaitAwaiterInContinuationCall(CORINFO_METHOD_STRUCT_* callerH Agnostic_GetAwaitAwaiterInContinuationCall key = default; key.callerHnd = CastHandle(callerHnd); key.ResolvedToken = - StoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, GetAwaitAwaiterInContinuationCall); + StoreAgnostic_CORINFO_RESOLVED_TOKEN(ref pResolvedToken, GetAwaitAwaiterInContinuationCall); key.isUnsafe = isUnsafe ? 1u : 0u; Agnostic_GetAwaitReturnCallResult value = default; value.methodHnd = CastHandle(methHnd); value.contextHandle = CastHandle(*contextHandle); - value.instArg = StoreAgnostic_CORINFO_LOOKUP(instArg); + value.instArg = StoreAgnostic_CORINFO_LOOKUP(ref instArg); GetAwaitAwaiterInContinuationCall.Add(key, value); } @@ -1392,14 +1393,14 @@ public void recGetGSCookie(nint* pCookieVal, nint** ppCookieVal) GetGSCookie.Add(0, value); } - public void recGetOSRInfo(PatchpointInfo* patchpointInfo, uint* ilOffset) + public void recGetOSRInfo(PatchpointInfo* patchpointInfo, ref uint ilOffset) { GetOSRInfo ??= new(); Agnostic_GetOSRInfo value = default; value.index = GetOSRInfo.AddBuffer(Bytes(patchpointInfo, PatchpointInfoSize(patchpointInfo))); - value.ilOffset = *ilOffset; + value.ilOffset = ilOffset; // use 0 for key uint key = 0; @@ -1426,27 +1427,27 @@ public void recGetClassModuleIdForStatics(CORINFO_CLASS_STRUCT_* cls, CORINFO_MO GetClassModuleIdForStatics.Add(key, value); } - public void recGetIsClassInitedFlagAddress(CORINFO_CLASS_STRUCT_* cls, CORINFO_CONST_LOOKUP* addr, int* offset, bool result) + public void recGetIsClassInitedFlagAddress(CORINFO_CLASS_STRUCT_* cls, ref CORINFO_CONST_LOOKUP addr, ref int offset, bool result) { GetIsClassInitedFlagAddress ??= new(); Agnostic_GetIsClassInitedFlagAddress value = default; - value.addr.handle = CastHandle(addr->addr); - value.addr.accessType = (uint)addr->accessType; - value.offset = (uint)*offset; + value.addr.handle = CastHandle(addr.addr); + value.addr.accessType = (uint)addr.accessType; + value.offset = (uint)offset; value.result = (result ? 1u : 0u); ulong key = CastHandle(cls); GetIsClassInitedFlagAddress.Add(key, value); } - public void recGetStaticBaseAddress(CORINFO_CLASS_STRUCT_* cls, bool isGc, CORINFO_CONST_LOOKUP* addr, bool result) + public void recGetStaticBaseAddress(CORINFO_CLASS_STRUCT_* cls, bool isGc, ref CORINFO_CONST_LOOKUP addr, bool result) { GetStaticBaseAddress ??= new(); Agnostic_GetStaticBaseAddress value = default; - value.addr.handle = CastHandle(addr->addr); - value.addr.accessType = (uint)addr->accessType; + value.addr.handle = CastHandle(addr.addr); + value.addr.accessType = (uint)addr.accessType; value.result = result ? 1u : 0u; DLD key = default; @@ -1456,14 +1457,14 @@ public void recGetStaticBaseAddress(CORINFO_CLASS_STRUCT_* cls, bool isGc, CORIN GetStaticBaseAddress.Add(key, value); } - public void recGetThreadTLSIndex(void** ppIndirection, uint result) + public void recGetThreadTLSIndex(ref void* ppIndirection, uint result) { GetThreadTLSIndex ??= new(); DLD value = default; - if (ppIndirection != null) - value.A = CastPointer(*ppIndirection); + if (!IsNullRef(ref ppIndirection)) + value.A = CastPointer(ppIndirection); else value.A = 0; value.B = (uint)result; @@ -1471,14 +1472,14 @@ public void recGetThreadTLSIndex(void** ppIndirection, uint result) GetThreadTLSIndex.Add(0, value); } - public void recGetAddrOfCaptureThreadGlobal(void** ppIndirection, int* result) + public void recGetAddrOfCaptureThreadGlobal(ref void* ppIndirection, int* result) { GetAddrOfCaptureThreadGlobal ??= new(); DLDL value = default; - if (ppIndirection != null) - value.A = CastPointer(*ppIndirection); + if (!IsNullRef(ref ppIndirection)) + value.A = CastPointer(ppIndirection); else value.A = 0; value.B = CastPointer(result); @@ -1512,17 +1513,17 @@ public void recGetClassThreadStaticDynamicInfo(CORINFO_CLASS_STRUCT_* cls, void* GetClassThreadStaticDynamicInfo.Add(key, value); } - public void recGetLocationOfThisType(CORINFO_METHOD_STRUCT_* context, CORINFO_LOOKUP_KIND* result) + public void recGetLocationOfThisType(CORINFO_METHOD_STRUCT_* context, ref CORINFO_LOOKUP_KIND result) { GetLocationOfThisType ??= new(); - Agnostic_CORINFO_LOOKUP_KIND value = CreateAgnostic_CORINFO_LOOKUP_KIND(result); + Agnostic_CORINFO_LOOKUP_KIND value = CreateAgnostic_CORINFO_LOOKUP_KIND(ref result); ulong key = CastHandle(context); GetLocationOfThisType.Add(key, value); } - public void recGetDelegateCtor(CORINFO_METHOD_STRUCT_* methHnd, CORINFO_CLASS_STRUCT_* clsHnd, CORINFO_METHOD_STRUCT_* targetMethodHnd, DelegateCtorArgs* pCtorData, CORINFO_METHOD_STRUCT_* result) + public void recGetDelegateCtor(CORINFO_METHOD_STRUCT_* methHnd, CORINFO_CLASS_STRUCT_* clsHnd, CORINFO_METHOD_STRUCT_* targetMethodHnd, ref DelegateCtorArgs pCtorData, CORINFO_METHOD_STRUCT_* result) { GetDelegateCtor ??= new(); @@ -1532,20 +1533,20 @@ public void recGetDelegateCtor(CORINFO_METHOD_STRUCT_* methHnd, CORINFO_CLASS_ST key.targetMethodHnd = CastHandle(targetMethodHnd); Agnostic_GetDelegateCtorOut value = default; - value.CtorData.pMethod = CastPointer(pCtorData->pMethod); - value.CtorData.pArg3 = CastPointer(pCtorData->pArg3); - value.CtorData.pArg4 = CastPointer(pCtorData->pArg4); - value.CtorData.pArg5 = CastPointer(pCtorData->pArg5); + value.CtorData.pMethod = CastPointer(pCtorData.pMethod); + value.CtorData.pArg3 = CastPointer(pCtorData.pArg3); + value.CtorData.pArg4 = CastPointer(pCtorData.pArg4); + value.CtorData.pArg5 = CastPointer(pCtorData.pArg5); value.result = CastHandle(result); GetDelegateCtor.Add(key, value); } - public void recGetFunctionFixedEntryPoint(CORINFO_METHOD_STRUCT_* ftn, CORINFO_CONST_LOOKUP* pResult) + public void recGetFunctionFixedEntryPoint(CORINFO_METHOD_STRUCT_* ftn, ref CORINFO_CONST_LOOKUP pResult) { GetFunctionFixedEntryPoint ??= new(); - Agnostic_CORINFO_CONST_LOOKUP value = StoreAgnostic_CORINFO_CONST_LOOKUP(pResult); + Agnostic_CORINFO_CONST_LOOKUP value = StoreAgnostic_CORINFO_CONST_LOOKUP(ref pResult); ulong key = CastHandle(ftn); GetFunctionFixedEntryPoint.Add(key, value); @@ -1715,13 +1716,13 @@ public void recGetArrayInitializationData(CORINFO_FIELD_STRUCT_* field, uint siz GetArrayInitializationData.Add(key, value); } - public void recGetAddressOfPInvokeTarget(CORINFO_METHOD_STRUCT_* method, CORINFO_CONST_LOOKUP* pLookup) + public void recGetAddressOfPInvokeTarget(CORINFO_METHOD_STRUCT_* method, ref CORINFO_CONST_LOOKUP pLookup) { GetAddressOfPInvokeTarget ??= new(); DLD value = default; - value.A = CastPointer(pLookup->addr); - value.B = (uint)pLookup->accessType; + value.A = CastPointer(pLookup.addr); + value.B = (uint)pLookup.accessType; ulong key = CastHandle(method); GetAddressOfPInvokeTarget.Add(key, value); @@ -1776,7 +1777,7 @@ public void recFindCallSiteSig(CORINFO_MODULE_STRUCT_* module, uint methTOK, COR FindCallSiteSig.Add(key, value); } - public void recGetVarArgsHandle(CORINFO_SIG_INFO* pSig, CORINFO_METHOD_STRUCT_* methHnd, void** ppIndirection, void* result) + public void recGetVarArgsHandle(CORINFO_SIG_INFO* pSig, CORINFO_METHOD_STRUCT_* methHnd, ref void* ppIndirection, void* result) { GetVarArgsHandle ??= new(); @@ -1788,8 +1789,8 @@ public void recGetVarArgsHandle(CORINFO_SIG_INFO* pSig, CORINFO_METHOD_STRUCT_* key.methHnd = CastHandle(methHnd); DLDL value = default; - if (ppIndirection != null) - value.A = CastPointer(*ppIndirection); + if (!IsNullRef(ref ppIndirection)) + value.A = CastPointer(ppIndirection); else value.A = 0; value.B = CastHandle(result); @@ -1797,14 +1798,14 @@ public void recGetVarArgsHandle(CORINFO_SIG_INFO* pSig, CORINFO_METHOD_STRUCT_* GetVarArgsHandle.Add(key, value); } - public void recGetFieldThreadLocalStoreID(CORINFO_FIELD_STRUCT_* field, void** ppIndirection, uint result) + public void recGetFieldThreadLocalStoreID(CORINFO_FIELD_STRUCT_* field, ref void* ppIndirection, uint result) { GetFieldThreadLocalStoreID ??= new(); DLD value = default; - if (ppIndirection != null) - value.A = CastPointer(*ppIndirection); + if (!IsNullRef(ref ppIndirection)) + value.A = CastPointer(ppIndirection); else value.A = 0; value.B = (uint)result; @@ -1863,18 +1864,18 @@ public void recAllocPgoInstrumentationBySchema(CORINFO_METHOD_STRUCT_* ftnHnd, P AllocPgoInstrumentationBySchema.Add(key, value); } - public void recGetPgoInstrumentationResults(CORINFO_METHOD_STRUCT_* ftnHnd, PgoInstrumentationSchema** pSchema, uint* pCountSchemaItems, byte** pInstrumentationData, PgoSource* pPgoSource, bool* pDynamicPgo, int result) + public void recGetPgoInstrumentationResults(CORINFO_METHOD_STRUCT_* ftnHnd, ref PgoInstrumentationSchema* pSchema, ref uint pCountSchemaItems, byte** pInstrumentationData, ref PgoSource pPgoSource, ref bool pDynamicPgo, int result) { GetPgoInstrumentationResults ??= new(); Agnostic_GetPgoInstrumentationResults value = default; - value.countSchemaItems = *pCountSchemaItems; + value.countSchemaItems = pCountSchemaItems; - PgoInstrumentationSchema* pInSchema = *pSchema; - var agnosticSchema = new Agnostic_PgoInstrumentationSchema[*pCountSchemaItems]; + PgoInstrumentationSchema* pInSchema = pSchema; + var agnosticSchema = new Agnostic_PgoInstrumentationSchema[pCountSchemaItems]; nuint maxOffset = 0; - for (uint i = 0; i < (*pCountSchemaItems); i++) + for (uint i = 0; i < (pCountSchemaItems); i++) { agnosticSchema[i].Offset = (ulong)pInSchema[i].Offset; agnosticSchema[i].InstrumentationKind = (uint)pInSchema[i].InstrumentationKind; @@ -1890,8 +1891,8 @@ public void recGetPgoInstrumentationResults(CORINFO_METHOD_STRUCT_* ftnHnd, PgoI value.data_index = GetPgoInstrumentationResults.AddBuffer(Bytes(*pInstrumentationData, (uint)maxOffset)); value.dataByteCount = (uint)maxOffset; value.result = (uint)result; - value.pgoSource = (uint)*pPgoSource; - value.dynamicPgo = (*pDynamicPgo ? 1u : 0u); + value.pgoSource = (uint)pPgoSource; + value.dynamicPgo = (pDynamicPgo ? 1u : 0u); ulong key = CastHandle(ftnHnd); GetPgoInstrumentationResults.Add(key, value); @@ -1977,24 +1978,24 @@ public void recErrorList(byte* error) ErrorList.Append(temp); } - public void recGetProfilingHandle(bool* pbHookFunction, void** pProfilerHandle, bool* pbIndirectedHandles) + public void recGetProfilingHandle(ref bool pbHookFunction, ref void* pProfilerHandle, ref bool pbIndirectedHandles) { GetProfilingHandle ??= new(); Agnostic_GetProfilingHandle value = default; - value.bHookFunction = (*pbHookFunction ? 1u : 0u); - value.ProfilerHandle = CastPointer(*pProfilerHandle); - value.bIndirectedHandles = (*pbIndirectedHandles ? 1u : 0u); + value.bHookFunction = (pbHookFunction ? 1u : 0u); + value.ProfilerHandle = CastPointer(pProfilerHandle); + value.bIndirectedHandles = (pbIndirectedHandles ? 1u : 0u); GetProfilingHandle.Add(0, value); } - public void recEmbedFieldHandle(CORINFO_FIELD_STRUCT_* handle, void** ppIndirection, CORINFO_FIELD_STRUCT_* result) + public void recEmbedFieldHandle(CORINFO_FIELD_STRUCT_* handle, ref void* ppIndirection, CORINFO_FIELD_STRUCT_* result) { EmbedFieldHandle ??= new(); DLDL value = default; - if (ppIndirection != null) - value.A = CastPointer(*ppIndirection); + if (!IsNullRef(ref ppIndirection)) + value.A = CastPointer(ppIndirection); else value.A = 0; value.B = CastHandle(result); @@ -2047,42 +2048,42 @@ public void recGetSystemVAmd64PassStructInRegisterDescriptor(CORINFO_CLASS_STRUC GetSystemVAmd64PassStructInRegisterDescriptor.Add(key, value); } - public void recGetSwiftLowering(CORINFO_CLASS_STRUCT_* structHnd, CORINFO_SWIFT_LOWERING* pLowering) + public void recGetSwiftLowering(CORINFO_CLASS_STRUCT_* structHnd, ref CORINFO_SWIFT_LOWERING pLowering) { GetSwiftLowering ??= new(); ulong key = CastHandle(structHnd); Agnostic_GetSwiftLowering value = default; - value.byReference = pLowering->byReference ? 1u : 0u; - if (!pLowering->byReference) + value.byReference = pLowering.byReference ? 1u : 0u; + if (!pLowering.byReference) { - value.numLoweredElements = (uint)pLowering->numLoweredElements; - for (int i = 0; i < pLowering->numLoweredElements; i++) + value.numLoweredElements = (uint)pLowering.numLoweredElements; + for (int i = 0; i < pLowering.numLoweredElements; i++) { - value.loweredElements[i] = (uint)pLowering->LoweredElements[i]; - value.offsets[i] = pLowering->Offsets[i]; + value.loweredElements[i] = (uint)pLowering.LoweredElements[i]; + value.offsets[i] = pLowering.Offsets[i]; } } GetSwiftLowering.Add(key, value); } - public void recGetFpStructLowering(CORINFO_CLASS_STRUCT_* structHnd, CORINFO_FPSTRUCT_LOWERING* pLowering) + public void recGetFpStructLowering(CORINFO_CLASS_STRUCT_* structHnd, ref CORINFO_FPSTRUCT_LOWERING pLowering) { GetFpStructLowering ??= new(); ulong key = CastHandle(structHnd); Agnostic_GetFpStructLowering value = default; - value.byIntegerCallConv = pLowering->byIntegerCallConv ? 1u : 0u; - if (!pLowering->byIntegerCallConv) + value.byIntegerCallConv = pLowering.byIntegerCallConv ? 1u : 0u; + if (!pLowering.byIntegerCallConv) { - value.numLoweredElements = (uint)pLowering->numLoweredElements; - for (int i = 0; i < pLowering->numLoweredElements; i++) + value.numLoweredElements = (uint)pLowering.numLoweredElements; + for (int i = 0; i < pLowering.numLoweredElements; i++) { - value.loweredElements[i] = (uint)pLowering->LoweredElements[i]; - value.offsets[i] = pLowering->Offsets[i]; + value.loweredElements[i] = (uint)pLowering.LoweredElements[i]; + value.offsets[i] = pLowering.Offsets[i]; } } @@ -2252,23 +2253,24 @@ public void recPrintMethodName(CORINFO_METHOD_STRUCT_* meth, byte* buffer, nuint recPrint(PrintMethodName ??= new(), CastHandle(meth), buffer, bufferSize, pRequiredBufferSize, bytesWritten); } - public void recGetTailCallHelpers(CORINFO_RESOLVED_TOKEN* callToken, CORINFO_SIG_INFO* sig, CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, CORINFO_TAILCALL_HELPERS* pResult) + public void recGetTailCallHelpers(ref CORINFO_RESOLVED_TOKEN callToken, CORINFO_SIG_INFO* sig, CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, bool result, + ref CORINFO_TAILCALL_HELPERS pResult) { GetTailCallHelpers ??= new(); Agnostic_GetTailCallHelpers key = default; - key.callToken = StoreAgnostic_CORINFO_RESOLVED_TOKEN(callToken, GetTailCallHelpers); + key.callToken = StoreAgnostic_CORINFO_RESOLVED_TOKEN(ref callToken, GetTailCallHelpers); key.sig = StoreSig(*sig, GetTailCallHelpers); key.flags = (uint)flags; Agnostic_CORINFO_TAILCALL_HELPERS value = default; - value.result = pResult != null ? (byte)1 : (byte)0; - if (pResult != null) + value.result = result ? (byte)1 : (byte)0; + if (result) { - value.flags = (uint)pResult->flags; - value.hStoreArgs = CastHandle(pResult->hStoreArgs); - value.hCallTarget = CastHandle(pResult->hCallTarget); - value.hDispatcher = CastHandle(pResult->hDispatcher); + value.flags = (uint)pResult.flags; + value.hStoreArgs = CastHandle(pResult.hStoreArgs); + value.hCallTarget = CastHandle(pResult.hCallTarget); + value.hDispatcher = CastHandle(pResult.hDispatcher); } GetTailCallHelpers.Add(key, value); @@ -2284,7 +2286,7 @@ public void recGetAsyncResumptionStub(CORINFO_METHOD_STRUCT_* hnd, void* entryPo GetAsyncResumptionStub.Add(0, result); } - public void recGetContinuationType(nuint dataSize, bool* objRefs, nuint objRefsSize, CORINFO_CLASS_STRUCT_* result) + public void recGetContinuationType(nuint dataSize, ref bool objRefs, nuint objRefsSize, CORINFO_CLASS_STRUCT_* result) { if (GetContinuationType == null) { @@ -2293,7 +2295,7 @@ public void recGetContinuationType(nuint dataSize, bool* objRefs, nuint objRefsS Agnostic_GetContinuationTypeIn key = default; key.dataSize = (ulong)dataSize; - key.objRefs = GetContinuationType.AddBuffer(Bytes(objRefs, (uint)objRefsSize)); + key.objRefs = GetContinuationType.AddBuffer(MemoryMarshal.AsBytes(MemoryMarshal.CreateReadOnlySpan(ref objRefs, (int)objRefsSize))); key.objRefsSize = (uint)objRefsSize; ulong value = CastHandle(result); @@ -2305,8 +2307,8 @@ public void recUpdateEntryPointForTailCall(CORINFO_CONST_LOOKUP origEntryPoint, { UpdateEntryPointForTailCall ??= new(); - Agnostic_CORINFO_CONST_LOOKUP key = StoreAgnostic_CORINFO_CONST_LOOKUP(&origEntryPoint); - Agnostic_CORINFO_CONST_LOOKUP value = StoreAgnostic_CORINFO_CONST_LOOKUP(&newEntryPoint); + Agnostic_CORINFO_CONST_LOOKUP key = StoreAgnostic_CORINFO_CONST_LOOKUP(ref origEntryPoint); + Agnostic_CORINFO_CONST_LOOKUP value = StoreAgnostic_CORINFO_CONST_LOOKUP(ref newEntryPoint); UpdateEntryPointForTailCall.Add(key, value); } diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Replay.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Replay.cs index 5953a2be9f3847..cdbc4d9ab63a3e 100644 --- a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Replay.cs +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/MethodContext.Replay.cs @@ -100,11 +100,11 @@ private void Restore_CORINFO_METHOD_INFO(CORINFO_METHOD_INFO* info, in Agnostic_ info->locals = Restore_CORINFO_SIG_INFO(value.locals, buffers, SigInstHandleMap, cr.MemoryTracker); } - private static void Restore_CORINFO_GENERICHANDLE_RESULT(CORINFO_GENERICHANDLE_RESULT* pResult, in Agnostic_CORINFO_GENERICHANDLE_RESULT value) + private static void Restore_CORINFO_GENERICHANDLE_RESULT(ref CORINFO_GENERICHANDLE_RESULT pResult, in Agnostic_CORINFO_GENERICHANDLE_RESULT value) { - pResult->lookup = RestoreCORINFO_LOOKUP(value.lookup); - pResult->compileTimeHandle = (CORINFO_GENERIC_STRUCT_*)value.compileTimeHandle; - pResult->handleType = (CorInfoGenericHandleType)value.handleType; + pResult.lookup = RestoreCORINFO_LOOKUP(value.lookup); + pResult.compileTimeHandle = (CORINFO_GENERIC_STRUCT_*)value.compileTimeHandle; + pResult.handleType = (CorInfoGenericHandleType)value.handleType; } private static CORINFO_RESOLVED_TOKEN TokenWithInValues(in Agnostic_CORINFO_RESOLVED_TOKENin inValue) => new() @@ -153,27 +153,27 @@ public uint repGetMethodAttribs(CORINFO_METHOD_STRUCT_* methodHandle) public byte* repGetClassAssemblyName(CORINFO_CLASS_STRUCT_* cls) => GetClassAssemblyName.GetBufferPointer(LookupByHandle(GetClassAssemblyName, cls)); - public void repGetVars(CORINFO_METHOD_STRUCT_* ftn, uint* cVars, ILVarInfo** vars_in, bool* extendOthers) + public void repGetVars(CORINFO_METHOD_STRUCT_* ftn, ref uint cVars, ILVarInfo** vars_in, ref bool extendOthers) { if (GetVars == null) { - *cVars = 0; + cVars = 0; return; } Agnostic_GetVars value = GetVars.Get(CastHandle(ftn)); - *cVars = value.cVars; - if (*cVars > 0) + cVars = value.cVars; + if (cVars > 0) *vars_in = (ILVarInfo*)GetVars.GetBufferPointer(value.vars_offset); - *extendOthers = value.extendOthers != 0; + extendOthers = value.extendOthers != 0; } - public void repGetBoundaries(CORINFO_METHOD_STRUCT_* ftn, uint* cILOffsets, uint** pILOffsets, BoundaryTypes* implicitBoundaries) + public void repGetBoundaries(CORINFO_METHOD_STRUCT_* ftn, ref uint cILOffsets, ref uint* pILOffsets, BoundaryTypes* implicitBoundaries) { Agnostic_GetBoundaries value = LookupByHandle(GetBoundaries, ftn); - *cILOffsets = value.cILOffsets; - if (*cILOffsets > 0) - *pILOffsets = (uint*)GetBoundaries.GetBufferPointer(value.pILOffset_offset); + cILOffsets = value.cILOffsets; + if (cILOffsets > 0) + pILOffsets = (uint*)GetBoundaries.GetBufferPointer(value.pILOffset_offset); *implicitBoundaries = (BoundaryTypes)value.implicitBoundaries; } @@ -210,11 +210,12 @@ public CorInfoInitClassResult repInitClass(CORINFO_FIELD_STRUCT_* field, CORINFO return result; } - public uint repGetJitFlags(CORJIT_FLAGS* jitFlags, uint sizeInBytes) + public uint repGetJitFlags(ref CORJIT_FLAGS jitFlags, uint sizeInBytes) { DD value = LookupByKeyOrMiss(GetJitFlags, 0u); ErrorHandling.AssertCode(sizeInBytes >= value.B, ExceptionCodes.ASSERT, "sizeInBytes >= value.B"); - Buffer.MemoryCopy(GetJitFlags.GetBufferPointer(value.A), jitFlags, sizeInBytes, value.B); + GetJitFlags.GetBuffer(value.A).Slice(0, (int)value.B).CopyTo( + MemoryMarshal.CreateSpan(ref Unsafe.As(ref jitFlags), (int)sizeInBytes)); return value.B; } @@ -232,27 +233,27 @@ public CorInfoInline repCanInline(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_MET return (CorInfoInline)value.result; } - public void repResolveToken(CORINFO_RESOLVED_TOKEN* pResolvedToken, out uint exceptionCode) + public void repResolveToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken, out uint exceptionCode) { - Agnostic_CORINFO_RESOLVED_TOKENin key = CreateAgnostic_CORINFO_RESOLVED_TOKENin(pResolvedToken); - ResolveTokenValue value = LookupByKeyOrMiss(ResolveToken, key, ": token {0:x}", (uint)pResolvedToken->token); - Restore_CORINFO_RESOLVED_TOKENout(pResolvedToken, value.tokenOut, ResolveToken); + Agnostic_CORINFO_RESOLVED_TOKENin key = CreateAgnostic_CORINFO_RESOLVED_TOKENin(ref pResolvedToken); + ResolveTokenValue value = LookupByKeyOrMiss(ResolveToken, key, ": token {0:x}", (uint)pResolvedToken.token); + Restore_CORINFO_RESOLVED_TOKENout(ref pResolvedToken, value.tokenOut, ResolveToken); exceptionCode = value.exceptionCode; } - public void repGetCallInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, + public void repGetCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_CALLINFO_FLAGS flags, CORINFO_CALL_INFO* pResult, out uint exceptionCode) { AssertMapExists(GetCallInfo); var key = new Agnostic_GetCallInfo { - ResolvedToken = RestoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, GetCallInfo), + ResolvedToken = RestoreAgnostic_CORINFO_RESOLVED_TOKEN(ref pResolvedToken, GetCallInfo), callerHandle = CastHandle(callerHandle), flags = (uint)flags, }; if (pConstrainedResolvedToken != null) - key.ConstrainedResolvedToken = RestoreAgnostic_CORINFO_RESOLVED_TOKEN(pConstrainedResolvedToken, GetCallInfo); + key.ConstrainedResolvedToken = RestoreAgnostic_CORINFO_RESOLVED_TOKEN(ref *pConstrainedResolvedToken, GetCallInfo); Agnostic_CORINFO_CALL_INFO value = LookupByKeyOrMiss(GetCallInfo, key, ": key {0:x8}, {1:x16}", key.ResolvedToken.inValue.token, key.ResolvedToken.outValue.hClass); @@ -305,7 +306,7 @@ public void repGetCallInfoFromMethodHandle(CORINFO_METHOD_STRUCT_* methodHandle, continue; CORINFO_RESOLVED_TOKEN resolvedToken = TokenWithInValues(key.ResolvedToken.inValue); - repResolveToken(&resolvedToken, out _); + repResolveToken(ref resolvedToken, out _); // If the original call passed a null constrainedResolvedToken, it can only be replayed with // a null one too, not with the address of a local (but meaningless) token. @@ -315,10 +316,10 @@ public void repGetCallInfoFromMethodHandle(CORINFO_METHOD_STRUCT_* methodHandle, { constrainedResolvedToken = TokenWithInValues(key.ConstrainedResolvedToken.inValue); pConstrainedResolvedToken = &constrainedResolvedToken; - repResolveToken(pConstrainedResolvedToken, out _); + repResolveToken(ref *pConstrainedResolvedToken, out _); } - repGetCallInfo(&resolvedToken, pConstrainedResolvedToken, (CORINFO_METHOD_STRUCT_*)key.callerHandle, + repGetCallInfo(ref resolvedToken, pConstrainedResolvedToken, (CORINFO_METHOD_STRUCT_*)key.callerHandle, (CORINFO_CALLINFO_FLAGS)key.flags, pResult, out _); return; } @@ -327,15 +328,15 @@ public void repGetCallInfoFromMethodHandle(CORINFO_METHOD_STRUCT_* methodHandle, ErrorHandling.LogException(ExceptionCodes.MC, $"Didn't find key {CastHandle(methodHandle):X16}."); } - public void repExpandRawHandleIntrinsic(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_GENERICHANDLE_RESULT* pResult) + public void repExpandRawHandleIntrinsic(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_GENERICHANDLE_RESULT pResult) { var key = new Agnostic_ExpandRawHandleIntrinsic { - ResolvedToken = CreateAgnostic_CORINFO_RESOLVED_TOKENin(pResolvedToken), + ResolvedToken = CreateAgnostic_CORINFO_RESOLVED_TOKENin(ref pResolvedToken), hCallerHandle = CastHandle(callerHandle), }; - Agnostic_CORINFO_GENERICHANDLE_RESULT value = LookupByKeyOrMiss(ExpandRawHandleIntrinsic, key, ": key {0:x}", (uint)pResolvedToken->token); - Restore_CORINFO_GENERICHANDLE_RESULT(pResult, value); + Agnostic_CORINFO_GENERICHANDLE_RESULT value = LookupByKeyOrMiss(ExpandRawHandleIntrinsic, key, ": key {0:x}", (uint)pResolvedToken.token); + Restore_CORINFO_GENERICHANDLE_RESULT(ref pResult, value); } public bool repIsIntrinsicType(CORINFO_CLASS_STRUCT_* cls) => LookupByHandle(IsIntrinsicType, cls) != 0; @@ -398,34 +399,34 @@ public bool repGetStringChar(CORINFO_OBJECT_STRUCT_* strObj, int index, ushort* public CORINFO_CLASS_STRUCT_* repGetObjectType(CORINFO_OBJECT_STRUCT_* objPtr) => (CORINFO_CLASS_STRUCT_*)LookupByHandle(GetObjectType, objPtr); - public bool repGetReadyToRunHelper(CORINFO_RESOLVED_TOKEN* pResolvedToken, CorInfoHelpFunc id, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_CONST_LOOKUP* pLookup) + public bool repGetReadyToRunHelper(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CorInfoHelpFunc id, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_CONST_LOOKUP pLookup) { AssertMapExists(GetReadyToRunHelper); var key = new GetReadyToRunHelper_TOKENin { - ResolvedToken = RestoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, GetReadyToRunHelper), + ResolvedToken = RestoreAgnostic_CORINFO_RESOLVED_TOKEN(ref pResolvedToken, GetReadyToRunHelper), id = (uint)id, callerHandle = CastHandle(callerHandle), }; GetReadyToRunHelper_TOKENout value = LookupByKeyOrMiss(GetReadyToRunHelper, key); - *pLookup = RestoreCORINFO_CONST_LOOKUP(value.Lookup); + pLookup = RestoreCORINFO_CONST_LOOKUP(value.Lookup); return value.result != 0; } - public void repGetReadyToRunDelegateCtorHelper(CORINFO_RESOLVED_TOKEN* pTargetMethod, mdToken targetConstraint, CORINFO_CLASS_STRUCT_* delegateType, - CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_LOOKUP* pLookup) + public void repGetReadyToRunDelegateCtorHelper(ref CORINFO_RESOLVED_TOKEN pTargetMethod, mdToken targetConstraint, CORINFO_CLASS_STRUCT_* delegateType, + CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_LOOKUP pLookup) { AssertMapExists(GetReadyToRunDelegateCtorHelper); var key = new GetReadyToRunDelegateCtorHelper_TOKENIn { - TargetMethod = RestoreAgnostic_CORINFO_RESOLVED_TOKEN(pTargetMethod, GetReadyToRunDelegateCtorHelper), + TargetMethod = RestoreAgnostic_CORINFO_RESOLVED_TOKEN(ref pTargetMethod, GetReadyToRunDelegateCtorHelper), targetConstraint = (uint)targetConstraint, delegateType = CastHandle(delegateType), callerHandle = CastHandle(callerHandle), }; - *pLookup = RestoreCORINFO_LOOKUP(LookupByKeyOrMiss(GetReadyToRunDelegateCtorHelper, key)); + pLookup = RestoreCORINFO_LOOKUP(LookupByKeyOrMiss(GetReadyToRunDelegateCtorHelper, key)); } public void repGetHelperFtn(CorInfoHelpFunc ftnNum, CORINFO_CONST_LOOKUP* pNativeEntrypoint, CORINFO_METHOD_STRUCT_** pMethodHandle) @@ -459,14 +460,14 @@ public bool fndGetHelperFtn(void* functionAddress, out CorInfoHelpFunc result) return false; } - public CORINFO_JUST_MY_CODE_HANDLE_* repGetJustMyCodeHandle(CORINFO_METHOD_STRUCT_* method, CORINFO_JUST_MY_CODE_HANDLE_** ppIndirection) + public CORINFO_JUST_MY_CODE_HANDLE_* repGetJustMyCodeHandle(CORINFO_METHOD_STRUCT_* method, ref CORINFO_JUST_MY_CODE_HANDLE_* ppIndirection) { DLDL value = LookupByHandle(GetJustMyCodeHandle, method); - *ppIndirection = (CORINFO_JUST_MY_CODE_HANDLE_*)value.A; + ppIndirection = (CORINFO_JUST_MY_CODE_HANDLE_*)value.A; return (CORINFO_JUST_MY_CODE_HANDLE_*)value.B; } - public void repGetFunctionEntryPoint(CORINFO_METHOD_STRUCT_* ftn, CORINFO_CONST_LOOKUP* pResult, CORINFO_ACCESS_FLAGS accessFlags) + public void repGetFunctionEntryPoint(CORINFO_METHOD_STRUCT_* ftn, ref CORINFO_CONST_LOOKUP pResult, CORINFO_ACCESS_FLAGS accessFlags) { var key = new DLD { A = CastHandle(ftn), B = (uint)accessFlags }; @@ -480,15 +481,15 @@ public void repGetFunctionEntryPoint(CORINFO_METHOD_STRUCT_* ftn, CORINFO_CONST_ else { Logger.LogDebug("Sparse - repGetFunctionEntryPoint fabricated result for request."); - pResult->accessType = InfoAccessType.IAT_PVALUE; - pResult->addr = (void*)(CastHandle(ftn) + 0x1c); + pResult.accessType = InfoAccessType.IAT_PVALUE; + pResult.addr = (void*)(CastHandle(ftn) + 0x1c); return; } } DLD value = GetFunctionEntryPoint.Get(key); - pResult->accessType = (InfoAccessType)value.B; - pResult->addr = (void*)value.A; + pResult.accessType = (InfoAccessType)value.B; + pResult.addr = (void*)value.A; } public bool fndGetFunctionEntryPoint(DLD value, out CORINFO_METHOD_STRUCT_* result) @@ -511,30 +512,30 @@ public bool fndGetFunctionEntryPoint(DLD value, out CORINFO_METHOD_STRUCT_* resu return false; } - public InfoAccessType repConstructStringLiteral(CORINFO_MODULE_STRUCT_* moduleHandle, mdToken metaTok, void** ppValue) + public InfoAccessType repConstructStringLiteral(CORINFO_MODULE_STRUCT_* moduleHandle, mdToken metaTok, ref void* ppValue) { var key = new DLD { A = CastHandle(moduleHandle), B = (uint)metaTok }; DLD value = LookupByKeyOrMiss(ConstructStringLiteral, key, ": key {0:X16}", CastHandle(moduleHandle)); - *ppValue = (void*)value.A; + ppValue = (void*)value.A; return (InfoAccessType)value.B; } - public bool repConvertPInvokeCalliToCall(CORINFO_RESOLVED_TOKEN* pResolvedToken, bool fMustConvert) + public bool repConvertPInvokeCalliToCall(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool fMustConvert) { AssertMapExists(ConvertPInvokeCalliToCall); - var key = new DLD { A = CastHandle(pResolvedToken->tokenScope), B = (uint)pResolvedToken->token }; + var key = new DLD { A = CastHandle(pResolvedToken.tokenScope), B = (uint)pResolvedToken.token }; DLDL value = LookupByKeyOrMiss(ConvertPInvokeCalliToCall, key); - pResolvedToken->hClass = (CORINFO_CLASS_STRUCT_*)value.A; - pResolvedToken->hMethod = (CORINFO_METHOD_STRUCT_*)value.B; + pResolvedToken.hClass = (CORINFO_CLASS_STRUCT_*)value.A; + pResolvedToken.hMethod = (CORINFO_METHOD_STRUCT_*)value.B; return value.B != 0; } - public InfoAccessType repEmptyStringLiteral(void** ppValue) + public InfoAccessType repEmptyStringLiteral(ref void* ppValue) { // TODO-Cleanup: sketchy if someone calls this twice DLD temp2 = LookupByKeyOrMiss(EmptyStringLiteral, 0u); - *ppValue = (void*)temp2.A; + ppValue = (void*)temp2.A; return (InfoAccessType)temp2.B; } @@ -620,48 +621,48 @@ public bool repHaveSameMethodDefinition(CORINFO_METHOD_STRUCT_* methHnd1, CORINF public CORINFO_CLASS_STRUCT_* repGetTypeDefinition(CORINFO_CLASS_STRUCT_* cls) => (CORINFO_CLASS_STRUCT_*)LookupByHandle(GetTypeDefinition, cls); - public CorInfoHelpFunc repGetNewHelper(CORINFO_CLASS_STRUCT_* classHandle, bool* pHasSideEffects, out uint exceptionCode) + public CorInfoHelpFunc repGetNewHelper(CORINFO_CLASS_STRUCT_* classHandle, ref bool pHasSideEffects, out uint exceptionCode) { DDD value = LookupByHandle(GetNewHelper, classHandle); - if (pHasSideEffects != null) - *pHasSideEffects = value.A != 0; + if (!Unsafe.IsNullRef(ref pHasSideEffects)) + pHasSideEffects = value.A != 0; exceptionCode = value.C; return (CorInfoHelpFunc)value.B; } - public void repEmbedGenericHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken, bool fEmbedParent, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_GENERICHANDLE_RESULT* pResult) + public void repEmbedGenericHandle(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool fEmbedParent, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_GENERICHANDLE_RESULT pResult) { AssertMapExists(EmbedGenericHandle); var key = new Agnostic_EmbedGenericHandle { - ResolvedToken = RestoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, EmbedGenericHandle), + ResolvedToken = RestoreAgnostic_CORINFO_RESOLVED_TOKEN(ref pResolvedToken, EmbedGenericHandle), fEmbedParent = fEmbedParent ? 1u : 0u, hCallerHandle = CastHandle(callerHandle), }; - Restore_CORINFO_GENERICHANDLE_RESULT(pResult, LookupByKeyOrMiss(EmbedGenericHandle, key)); + Restore_CORINFO_GENERICHANDLE_RESULT(ref pResult, LookupByKeyOrMiss(EmbedGenericHandle, key)); } - public void repGetEHinfo(CORINFO_METHOD_STRUCT_* ftn, uint EHnumber, CORINFO_EH_CLAUSE* clause) + public void repGetEHinfo(CORINFO_METHOD_STRUCT_* ftn, uint EHnumber, ref CORINFO_EH_CLAUSE clause) { AssertMapExists(GetEHinfo, ": key {0:X16}", CastHandle(ftn)); var key = new DLD { A = CastHandle(ftn), B = EHnumber }; Agnostic_CORINFO_EH_CLAUSE value = LookupByKeyOrMiss(GetEHinfo, key, ": key {0:X16}", CastHandle(ftn)); - clause->Flags = (CORINFO_EH_CLAUSE_FLAGS)value.Flags; - clause->TryOffset = value.TryOffset; - clause->TryLength = value.TryLength; - clause->HandlerOffset = value.HandlerOffset; - clause->HandlerLength = value.HandlerLength; - clause->ClassTokenOrOffset = value.ClassToken; + clause.Flags = (CORINFO_EH_CLAUSE_FLAGS)value.Flags; + clause.TryOffset = value.TryOffset; + clause.TryLength = value.TryLength; + clause.HandlerOffset = value.HandlerOffset; + clause.HandlerLength = value.HandlerLength; + clause.ClassTokenOrOffset = value.ClassToken; } - public void repGetMethodVTableOffset(CORINFO_METHOD_STRUCT_* method, uint* offsetOfIndirection, uint* offsetAfterIndirection, bool* isRelative) + public void repGetMethodVTableOffset(CORINFO_METHOD_STRUCT_* method, ref uint offsetOfIndirection, ref uint offsetAfterIndirection, ref bool isRelative) { DDD value = LookupByHandle(GetMethodVTableOffset, method); - *offsetOfIndirection = value.A; - *offsetAfterIndirection = value.B; - *isRelative = value.C != 0; + offsetOfIndirection = value.A; + offsetAfterIndirection = value.B; + isRelative = value.C != 0; } public bool repResolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) @@ -674,7 +675,7 @@ public bool repResolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) pResolvedTokenVirtualMethodNonNull = info->pResolvedTokenVirtualMethod != null ? 1u : 0u, }; if (key.pResolvedTokenVirtualMethodNonNull != 0) - key.pResolvedTokenVirtualMethod = StoreAgnostic_CORINFO_RESOLVED_TOKEN(info->pResolvedTokenVirtualMethod, ResolveToken); + key.pResolvedTokenVirtualMethod = StoreAgnostic_CORINFO_RESOLVED_TOKEN(ref *info->pResolvedTokenVirtualMethod, ResolveToken); Agnostic_ResolveVirtualMethodResult result = LookupByKeyOrMiss(ResolveVirtualMethod, key, ": {0:X16}-{1:X16}-{2:X16}-{3:X8}", key.virtualMethod, key.objClass, key.context, key.pResolvedTokenVirtualMethodNonNull); @@ -691,10 +692,10 @@ public bool repResolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) return result.returnValue != 0; } - public CORINFO_METHOD_STRUCT_* repGetAsyncOtherVariant(CORINFO_METHOD_STRUCT_* ftn, bool* variantIsThunk) + public CORINFO_METHOD_STRUCT_* repGetAsyncOtherVariant(CORINFO_METHOD_STRUCT_* ftn, ref bool variantIsThunk) { DLD value = LookupByHandle(GetAsyncOtherVariant, ftn); - *variantIsThunk = value.B != 0; + variantIsThunk = value.B != 0; return (CORINFO_METHOD_STRUCT_*)value.A; } @@ -704,19 +705,19 @@ public bool repResolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) public CORINFO_CLASS_STRUCT_* repGetSZArrayHelperEnumeratorClass(CORINFO_CLASS_STRUCT_* cls) => (CORINFO_CLASS_STRUCT_*)LookupByHandle(GetSZArrayHelperEnumeratorClass, cls); - public CORINFO_CLASS_STRUCT_* repGetTokenTypeAsHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken) + public CORINFO_CLASS_STRUCT_* repGetTokenTypeAsHandle(ref CORINFO_RESOLVED_TOKEN pResolvedToken) { - var key = new GetTokenTypeAsHandleValue { hMethod = CastHandle(pResolvedToken->hMethod), hField = CastHandle(pResolvedToken->hField) }; + var key = new GetTokenTypeAsHandleValue { hMethod = CastHandle(pResolvedToken.hMethod), hField = CastHandle(pResolvedToken.hField) }; return (CORINFO_CLASS_STRUCT_*)LookupByKeyOrMiss(GetTokenTypeAsHandle, key); } - public void repGetFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult) + public void repGetFieldInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult) { - AssertMapExists(GetFieldInfo, ": key {0:x}", (uint)pResolvedToken->token); + AssertMapExists(GetFieldInfo, ": key {0:x}", (uint)pResolvedToken.token); var key = new Agnostic_GetFieldInfo { - ResolvedToken = RestoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, GetFieldInfo), + ResolvedToken = RestoreAgnostic_CORINFO_RESOLVED_TOKEN(ref pResolvedToken, GetFieldInfo), callerHandle = CastHandle(callerHandle), flags = (uint)flags, }; @@ -738,7 +739,7 @@ public void repGetFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METH if (keyIndex != -1) Logger.LogDebug("Sparse - repGetFieldInfo found value with inverted CORINFO_ACCESS_INLINECHECK"); else - ErrorHandling.LogException(ExceptionCodes.MC, $"repGetFieldInfo: didn't find {(uint)pResolvedToken->token:x}"); + ErrorHandling.LogException(ExceptionCodes.MC, $"repGetFieldInfo: didn't find {(uint)pResolvedToken.token:x}"); } } @@ -785,11 +786,11 @@ public void repGetThreadLocalStaticInfo_NativeAOT(CORINFO_THREAD_STATIC_INFO_NAT pInfo->tlsGetAddrFtnPtr = RestoreCORINFO_CONST_LOOKUP(value.tlsGetAddrFtnPtr); } - public CORINFO_METHOD_STRUCT_* repEmbedMethodHandle(CORINFO_METHOD_STRUCT_* handle, void** ppIndirection) + public CORINFO_METHOD_STRUCT_* repEmbedMethodHandle(CORINFO_METHOD_STRUCT_* handle, ref void* ppIndirection) { DLDL value = LookupByHandle(EmbedMethodHandle, handle); - if (ppIndirection != null) - *ppIndirection = (void*)value.A; + if (!IsNullRef(ref ppIndirection)) + ppIndirection = (void*)value.A; return (CORINFO_METHOD_STRUCT_*)value.B; } @@ -840,35 +841,35 @@ public uint repGetClassAlignmentRequirement(CORINFO_CLASS_STRUCT_* cls, bool fDo return LookupByKeyOrMiss(GetClassAlignmentRequirement, key, ": key {0:X16}", key.A); } - public CorInfoIsAccessAllowedResult repCanAccessClass(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_HELPER_DESC* pAccessHelper) + public CorInfoIsAccessAllowedResult repCanAccessClass(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_HELPER_DESC pAccessHelper) { - AssertMapExists(CanAccessClass, ": key {0:X16}", CastHandle(pResolvedToken->hClass)); + AssertMapExists(CanAccessClass, ": key {0:X16}", CastHandle(pResolvedToken.hClass)); var key = new Agnostic_CanAccessClassIn { - ResolvedToken = RestoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, CanAccessClass), + ResolvedToken = RestoreAgnostic_CORINFO_RESOLVED_TOKEN(ref pResolvedToken, CanAccessClass), callerHandle = CastHandle(callerHandle), }; - Agnostic_CanAccessClassOut value = LookupByKeyOrMiss(CanAccessClass, key, ": key {0:X16}", CastHandle(pResolvedToken->hClass)); - *pAccessHelper = RestoreCORINFO_HELPER_DESC(value.AccessHelper); + Agnostic_CanAccessClassOut value = LookupByKeyOrMiss(CanAccessClass, key, ": key {0:X16}", CastHandle(pResolvedToken.hClass)); + pAccessHelper = RestoreCORINFO_HELPER_DESC(value.AccessHelper); return (CorInfoIsAccessAllowedResult)value.result; } - public CorInfoHelpFunc repGetCastingHelper(CORINFO_RESOLVED_TOKEN* pResolvedToken, bool fThrowing) + public CorInfoHelpFunc repGetCastingHelper(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool fThrowing) { - var key = new Agnostic_GetCastingHelper { hClass = CastHandle(pResolvedToken->hClass), fThrowing = fThrowing ? 1u : 0u }; + var key = new Agnostic_GetCastingHelper { hClass = CastHandle(pResolvedToken.hClass), fThrowing = fThrowing ? 1u : 0u }; return (CorInfoHelpFunc)LookupByKeyOrMiss(GetCastingHelper, key, ": key {0:X16}", key.hClass); } - public CORINFO_MODULE_STRUCT_* repEmbedModuleHandle(CORINFO_MODULE_STRUCT_* handle, void** ppIndirection) + public CORINFO_MODULE_STRUCT_* repEmbedModuleHandle(CORINFO_MODULE_STRUCT_* handle, ref void* ppIndirection) { DLDL value = LookupByHandle(EmbedModuleHandle, handle); - if (ppIndirection != null) - *ppIndirection = (void*)value.A; + if (!IsNullRef(ref ppIndirection)) + ppIndirection = (void*)value.A; return (CORINFO_MODULE_STRUCT_*)value.B; } - public CORINFO_CLASS_STRUCT_* repEmbedClassHandle(CORINFO_CLASS_STRUCT_* handle, void** ppIndirection) + public CORINFO_CLASS_STRUCT_* repEmbedClassHandle(CORINFO_CLASS_STRUCT_* handle, ref void* ppIndirection) { ulong key = CastHandle(handle); if (key == CONTINUATION_TYPE_PSEUDO_CLASS_HANDLE) @@ -877,16 +878,16 @@ public CorInfoHelpFunc repGetCastingHelper(CORINFO_RESOLVED_TOKEN* pResolvedToke { // Some other embedded handle required an indirection, so do the same for the pseudo handle // (avoids spurious improvements in R2R scenarios). - *ppIndirection = (void*)CONTINUATION_TYPE_PSEUDO_CLASS_HANDLE; + ppIndirection = (void*)CONTINUATION_TYPE_PSEUDO_CLASS_HANDLE; return null; } - *ppIndirection = null; + ppIndirection = null; return handle; } DLDL value = LookupByKeyOrMiss(EmbedClassHandle, key, ": key {0:X16}", key); - *ppIndirection = (void*)value.A; + ppIndirection = (void*)value.A; return (CORINFO_CLASS_STRUCT_*)value.B; } @@ -905,7 +906,7 @@ public bool repPInvokeMarshalingRequired(CORINFO_METHOD_STRUCT_* method, CORINFO return LookupByKeyOrMiss(PInvokeMarshalingRequired, key) != 0; } - public CorInfoCallConvExtension repGetUnmanagedCallConv(CORINFO_METHOD_STRUCT_* method, CORINFO_SIG_INFO* callSiteSig, bool* pSuppressGCTransition) + public CorInfoCallConvExtension repGetUnmanagedCallConv(CORINFO_METHOD_STRUCT_* method, CORINFO_SIG_INFO* callSiteSig, ref bool pSuppressGCTransition) { if (GetUnmanagedCallConv == null) { @@ -922,7 +923,7 @@ public CorInfoCallConvExtension repGetUnmanagedCallConv(CORINFO_METHOD_STRUCT_* } DD value = LookupByKeyOrMiss(GetUnmanagedCallConv, key); - *pSuppressGCTransition = value.B != 0; + pSuppressGCTransition = value.B != 0; return (CorInfoCallConvExtension)value.A; } @@ -933,79 +934,79 @@ public void repFindSig(CORINFO_MODULE_STRUCT_* moduleHandle, uint sigTOK, CORINF *sig = Restore_CORINFO_SIG_INFO(value, FindSig, SigInstHandleMap, cr.MemoryTracker); } - public void repGetEEInfo(CORINFO_EE_INFO* pEEInfoOut) + public void repGetEEInfo(ref CORINFO_EE_INFO pEEInfoOut) { Agnostic_CORINFO_EE_INFO value = LookupByKeyOrMiss(GetEEInfo, 0u); - pEEInfoOut->inlinedCallFrameInfo.size = value.inlinedCallFrameInfo.size; - pEEInfoOut->inlinedCallFrameInfo.sizeWithSecretStubArg = value.inlinedCallFrameInfo.sizeWithSecretStubArg; - pEEInfoOut->inlinedCallFrameInfo.offsetOfFrameLink = value.inlinedCallFrameInfo.offsetOfFrameLink; - pEEInfoOut->inlinedCallFrameInfo.offsetOfCallSiteSP = value.inlinedCallFrameInfo.offsetOfCallSiteSP; - pEEInfoOut->inlinedCallFrameInfo.offsetOfCalleeSavedFP = value.inlinedCallFrameInfo.offsetOfCalleeSavedFP; - pEEInfoOut->inlinedCallFrameInfo.offsetOfCallTarget = value.inlinedCallFrameInfo.offsetOfCallTarget; - pEEInfoOut->inlinedCallFrameInfo.offsetOfReturnAddress = value.inlinedCallFrameInfo.offsetOfReturnAddress; - pEEInfoOut->inlinedCallFrameInfo.offsetOfSecretStubArg = value.inlinedCallFrameInfo.offsetOfSecretStubArg; - pEEInfoOut->inlinedCallFrameInfo.offsetOfSPAfterProlog = value.inlinedCallFrameInfo.offsetOfSPAfterProlog; - pEEInfoOut->offsetOfThreadFrame = value.offsetOfThreadFrame; - pEEInfoOut->offsetOfGCState = value.offsetOfGCState; - pEEInfoOut->offsetOfDelegateInstance = value.offsetOfDelegateInstance; - pEEInfoOut->offsetOfDelegateFirstTarget = value.offsetOfDelegateFirstTarget; - pEEInfoOut->sizeOfReversePInvokeFrame = value.sizeOfReversePInvokeFrame; - pEEInfoOut->osPageSize = value.osPageSize; - pEEInfoOut->maxUncheckedOffsetForNullObject = value.maxUncheckedOffsetForNullObject; - pEEInfoOut->targetAbi = (CORINFO_RUNTIME_ABI)value.targetAbi; - pEEInfoOut->osType = (CORINFO_OS)value.osType; - } - - public void repGetAsyncInfo(CORINFO_ASYNC_INFO* pAsyncInfoOut) + pEEInfoOut.inlinedCallFrameInfo.size = value.inlinedCallFrameInfo.size; + pEEInfoOut.inlinedCallFrameInfo.sizeWithSecretStubArg = value.inlinedCallFrameInfo.sizeWithSecretStubArg; + pEEInfoOut.inlinedCallFrameInfo.offsetOfFrameLink = value.inlinedCallFrameInfo.offsetOfFrameLink; + pEEInfoOut.inlinedCallFrameInfo.offsetOfCallSiteSP = value.inlinedCallFrameInfo.offsetOfCallSiteSP; + pEEInfoOut.inlinedCallFrameInfo.offsetOfCalleeSavedFP = value.inlinedCallFrameInfo.offsetOfCalleeSavedFP; + pEEInfoOut.inlinedCallFrameInfo.offsetOfCallTarget = value.inlinedCallFrameInfo.offsetOfCallTarget; + pEEInfoOut.inlinedCallFrameInfo.offsetOfReturnAddress = value.inlinedCallFrameInfo.offsetOfReturnAddress; + pEEInfoOut.inlinedCallFrameInfo.offsetOfSecretStubArg = value.inlinedCallFrameInfo.offsetOfSecretStubArg; + pEEInfoOut.inlinedCallFrameInfo.offsetOfSPAfterProlog = value.inlinedCallFrameInfo.offsetOfSPAfterProlog; + pEEInfoOut.offsetOfThreadFrame = value.offsetOfThreadFrame; + pEEInfoOut.offsetOfGCState = value.offsetOfGCState; + pEEInfoOut.offsetOfDelegateInstance = value.offsetOfDelegateInstance; + pEEInfoOut.offsetOfDelegateFirstTarget = value.offsetOfDelegateFirstTarget; + pEEInfoOut.sizeOfReversePInvokeFrame = value.sizeOfReversePInvokeFrame; + pEEInfoOut.osPageSize = value.osPageSize; + pEEInfoOut.maxUncheckedOffsetForNullObject = value.maxUncheckedOffsetForNullObject; + pEEInfoOut.targetAbi = (CORINFO_RUNTIME_ABI)value.targetAbi; + pEEInfoOut.osType = (CORINFO_OS)value.osType; + } + + public void repGetAsyncInfo(ref CORINFO_ASYNC_INFO pAsyncInfoOut) { Agnostic_CORINFO_ASYNC_INFO value = LookupByKeyOrMiss(GetAsyncInfo, 0u); - pAsyncInfoOut->continuationClsHnd = (CORINFO_CLASS_STRUCT_*)value.continuationClsHnd; - pAsyncInfoOut->continuationNextFldHnd = (CORINFO_FIELD_STRUCT_*)value.continuationNextFldHnd; - pAsyncInfoOut->continuationResumeInfoFldHnd = (CORINFO_FIELD_STRUCT_*)value.continuationResumeInfoFldHnd; - pAsyncInfoOut->continuationStateFldHnd = (CORINFO_FIELD_STRUCT_*)value.continuationStateFldHnd; - pAsyncInfoOut->continuationFlagsFldHnd = (CORINFO_FIELD_STRUCT_*)value.continuationFlagsFldHnd; - pAsyncInfoOut->captureExecutionContextMethHnd = (CORINFO_METHOD_STRUCT_*)value.captureExecutionContextMethHnd; - pAsyncInfoOut->captureContinuationContextMethHnd = (CORINFO_METHOD_STRUCT_*)value.captureContinuationContextMethHnd; - pAsyncInfoOut->captureContextsMethHnd = (CORINFO_METHOD_STRUCT_*)value.captureContextsMethHnd; - pAsyncInfoOut->restoreContextsMethHnd = (CORINFO_METHOD_STRUCT_*)value.restoreContextsMethHnd; - pAsyncInfoOut->restoreContextsOnSuspensionMethHnd = (CORINFO_METHOD_STRUCT_*)value.restoreContextsOnSuspensionMethHnd; - pAsyncInfoOut->restoreInlinedFrameContextsMethHnd = (CORINFO_METHOD_STRUCT_*)value.restoreInlinedFrameContextsMethHnd; - pAsyncInfoOut->captureInlinedFrameTransitionWithContinuationContextMethHnd = (CORINFO_METHOD_STRUCT_*)value.captureInlinedFrameTransitionWithContinuationContextMethHnd; - pAsyncInfoOut->captureInlinedFrameTransitionNoContinuationContextMethHnd = (CORINFO_METHOD_STRUCT_*)value.captureInlinedFrameTransitionNoContinuationContextMethHnd; - pAsyncInfoOut->captureInlinedFrameTransitionContinueOnThreadPoolMethHnd = (CORINFO_METHOD_STRUCT_*)value.captureInlinedFrameTransitionContinueOnThreadPoolMethHnd; - pAsyncInfoOut->finishSuspensionNoContinuationContextMethHnd = (CORINFO_METHOD_STRUCT_*)value.finishSuspensionNoContinuationContextMethHnd; - pAsyncInfoOut->finishSuspensionWithContinuationContextMethHnd = (CORINFO_METHOD_STRUCT_*)value.finishSuspensionWithContinuationContextMethHnd; - } - - public void repGetWasmWellKnownGlobals(CORINFO_WASM_WELLKNOWN_GLOBALS* pWellKnownGlobalsOut) + pAsyncInfoOut.continuationClsHnd = (CORINFO_CLASS_STRUCT_*)value.continuationClsHnd; + pAsyncInfoOut.continuationNextFldHnd = (CORINFO_FIELD_STRUCT_*)value.continuationNextFldHnd; + pAsyncInfoOut.continuationResumeInfoFldHnd = (CORINFO_FIELD_STRUCT_*)value.continuationResumeInfoFldHnd; + pAsyncInfoOut.continuationStateFldHnd = (CORINFO_FIELD_STRUCT_*)value.continuationStateFldHnd; + pAsyncInfoOut.continuationFlagsFldHnd = (CORINFO_FIELD_STRUCT_*)value.continuationFlagsFldHnd; + pAsyncInfoOut.captureExecutionContextMethHnd = (CORINFO_METHOD_STRUCT_*)value.captureExecutionContextMethHnd; + pAsyncInfoOut.captureContinuationContextMethHnd = (CORINFO_METHOD_STRUCT_*)value.captureContinuationContextMethHnd; + pAsyncInfoOut.captureContextsMethHnd = (CORINFO_METHOD_STRUCT_*)value.captureContextsMethHnd; + pAsyncInfoOut.restoreContextsMethHnd = (CORINFO_METHOD_STRUCT_*)value.restoreContextsMethHnd; + pAsyncInfoOut.restoreContextsOnSuspensionMethHnd = (CORINFO_METHOD_STRUCT_*)value.restoreContextsOnSuspensionMethHnd; + pAsyncInfoOut.restoreInlinedFrameContextsMethHnd = (CORINFO_METHOD_STRUCT_*)value.restoreInlinedFrameContextsMethHnd; + pAsyncInfoOut.captureInlinedFrameTransitionWithContinuationContextMethHnd = (CORINFO_METHOD_STRUCT_*)value.captureInlinedFrameTransitionWithContinuationContextMethHnd; + pAsyncInfoOut.captureInlinedFrameTransitionNoContinuationContextMethHnd = (CORINFO_METHOD_STRUCT_*)value.captureInlinedFrameTransitionNoContinuationContextMethHnd; + pAsyncInfoOut.captureInlinedFrameTransitionContinueOnThreadPoolMethHnd = (CORINFO_METHOD_STRUCT_*)value.captureInlinedFrameTransitionContinueOnThreadPoolMethHnd; + pAsyncInfoOut.finishSuspensionNoContinuationContextMethHnd = (CORINFO_METHOD_STRUCT_*)value.finishSuspensionNoContinuationContextMethHnd; + pAsyncInfoOut.finishSuspensionWithContinuationContextMethHnd = (CORINFO_METHOD_STRUCT_*)value.finishSuspensionWithContinuationContextMethHnd; + } + + public void repGetWasmWellKnownGlobals(ref CORINFO_WASM_WELLKNOWN_GLOBALS pWellKnownGlobalsOut) { Agnostic_CORINFO_WASM_WELLKNOWN_GLOBALS value = LookupByKeyOrMiss(GetWasmWellKnownGlobals, 0u); - pWellKnownGlobalsOut->stackPointer = (CORINFO_WASM_GLOBAL_SYMBOL_STRUCT_*)value.stackPointer; - pWellKnownGlobalsOut->imageBase = (CORINFO_WASM_GLOBAL_SYMBOL_STRUCT_*)value.imageBase; - pWellKnownGlobalsOut->tableBase = (CORINFO_WASM_GLOBAL_SYMBOL_STRUCT_*)value.tableBase; - pWellKnownGlobalsOut->asyncContinuation = (CORINFO_WASM_GLOBAL_SYMBOL_STRUCT_*)value.asyncContinuation; + pWellKnownGlobalsOut.stackPointer = (CORINFO_WASM_GLOBAL_SYMBOL_STRUCT_*)value.stackPointer; + pWellKnownGlobalsOut.imageBase = (CORINFO_WASM_GLOBAL_SYMBOL_STRUCT_*)value.imageBase; + pWellKnownGlobalsOut.tableBase = (CORINFO_WASM_GLOBAL_SYMBOL_STRUCT_*)value.tableBase; + pWellKnownGlobalsOut.asyncContinuation = (CORINFO_WASM_GLOBAL_SYMBOL_STRUCT_*)value.asyncContinuation; } - public CORINFO_METHOD_STRUCT_* repGetAwaitReturnCall(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_CONTEXT_STRUCT** contextHandle, CORINFO_LOOKUP* instArg) + public CORINFO_METHOD_STRUCT_* repGetAwaitReturnCall(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_CONTEXT_STRUCT** contextHandle, ref CORINFO_LOOKUP instArg) { Agnostic_GetAwaitReturnCallResult result = LookupByKeyOrMiss(GetAwaitReturnCall, CastHandle(callerHnd)); *contextHandle = (CORINFO_CONTEXT_STRUCT*)result.contextHandle; - *instArg = RestoreCORINFO_LOOKUP(result.instArg); + instArg = RestoreCORINFO_LOOKUP(result.instArg); return (CORINFO_METHOD_STRUCT_*)result.methodHnd; } - public CORINFO_METHOD_STRUCT_* repGetAwaitAwaiterInContinuationCall(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_RESOLVED_TOKEN* pResolvedToken, bool isUnsafe, - CORINFO_CONTEXT_STRUCT** contextHandle, CORINFO_LOOKUP* instArg) + public CORINFO_METHOD_STRUCT_* repGetAwaitAwaiterInContinuationCall(CORINFO_METHOD_STRUCT_* callerHnd, ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool isUnsafe, + CORINFO_CONTEXT_STRUCT** contextHandle, ref CORINFO_LOOKUP instArg) { var key = new Agnostic_GetAwaitAwaiterInContinuationCall { callerHnd = CastHandle(callerHnd), - ResolvedToken = RestoreAgnostic_CORINFO_RESOLVED_TOKEN(pResolvedToken, GetAwaitAwaiterInContinuationCall), + ResolvedToken = RestoreAgnostic_CORINFO_RESOLVED_TOKEN(ref pResolvedToken, GetAwaitAwaiterInContinuationCall), isUnsafe = isUnsafe ? 1u : 0u, }; Agnostic_GetAwaitReturnCallResult value = LookupByKeyOrMiss(GetAwaitAwaiterInContinuationCall, key); *contextHandle = (CORINFO_CONTEXT_STRUCT*)value.contextHandle; - *instArg = RestoreCORINFO_LOOKUP(value.instArg); + instArg = RestoreCORINFO_LOOKUP(value.instArg); return (CORINFO_METHOD_STRUCT_*)value.methodHnd; } @@ -1028,53 +1029,53 @@ public void repGetGSCookie(nint* pCookieVal, nint** ppCookieVal) *ppCookieVal = (nint*)value.B; } - public PatchpointInfo* repGetOSRInfo(uint* ilOffset) + public PatchpointInfo* repGetOSRInfo(ref uint ilOffset) { uint key = 0; Agnostic_GetOSRInfo value = LookupByKeyOrMiss(GetOSRInfo, key); - *ilOffset = value.ilOffset; + ilOffset = value.ilOffset; return (PatchpointInfo*)GetOSRInfo.GetBufferPointer(value.index); } - public bool repGetIsClassInitedFlagAddress(CORINFO_CLASS_STRUCT_* cls, CORINFO_CONST_LOOKUP* addr, int* offset) + public bool repGetIsClassInitedFlagAddress(CORINFO_CLASS_STRUCT_* cls, ref CORINFO_CONST_LOOKUP addr, ref int offset) { Agnostic_GetIsClassInitedFlagAddress value = LookupByHandle(GetIsClassInitedFlagAddress, cls); - *offset = (int)value.offset; - addr->accessType = (InfoAccessType)value.addr.accessType; - addr->addr = (void*)value.addr.handle; + offset = (int)value.offset; + addr.accessType = (InfoAccessType)value.addr.accessType; + addr.addr = (void*)value.addr.handle; return value.result != 0; } - public bool repGetStaticBaseAddress(CORINFO_CLASS_STRUCT_* cls, bool isGc, CORINFO_CONST_LOOKUP* addr) + public bool repGetStaticBaseAddress(CORINFO_CLASS_STRUCT_* cls, bool isGc, ref CORINFO_CONST_LOOKUP addr) { var key = new DLD { A = CastHandle(cls), B = isGc ? 1u : 0u }; Agnostic_GetStaticBaseAddress value = LookupByKeyOrMiss(GetStaticBaseAddress, key, ": key {0:X16}", key.A); - addr->accessType = (InfoAccessType)value.addr.accessType; - addr->addr = (void*)value.addr.handle; + addr.accessType = (InfoAccessType)value.addr.accessType; + addr.addr = (void*)value.addr.handle; return value.result != 0; } - public uint repGetThreadTLSIndex(void** ppIndirection) + public uint repGetThreadTLSIndex(ref void* ppIndirection) { DLD value = LookupByKeyOrMiss(GetThreadTLSIndex, 0u); - if (ppIndirection != null) - *ppIndirection = (void*)value.A; + if (!IsNullRef(ref ppIndirection)) + ppIndirection = (void*)value.A; return value.B; } - public int* repGetAddrOfCaptureThreadGlobal(void** ppIndirection) + public int* repGetAddrOfCaptureThreadGlobal(ref void* ppIndirection) { if (GetAddrOfCaptureThreadGlobal == null || GetAddrOfCaptureThreadGlobal.GetIndex(0) == -1) { Logger.LogDebug("Sparse - repGetAddrOfCaptureThreadGlobal returning nullptr and 0xCAFE0001"); - if (ppIndirection != null) - *ppIndirection = null; + if (!IsNullRef(ref ppIndirection)) + ppIndirection = null; return (int*)0xCAFE0001; } DLDL value = GetAddrOfCaptureThreadGlobal.Get(0); - if (ppIndirection != null) - *ppIndirection = (void*)value.A; + if (!IsNullRef(ref ppIndirection)) + ppIndirection = (void*)value.A; return (int*)value.B; } @@ -1082,24 +1083,24 @@ public uint repGetThreadTLSIndex(void** ppIndirection) public void* repGetClassThreadStaticDynamicInfo(CORINFO_CLASS_STRUCT_* cls) => (void*)LookupByHandle(GetClassThreadStaticDynamicInfo, cls).A; - public void repGetLocationOfThisType(CORINFO_METHOD_STRUCT_* context, CORINFO_LOOKUP_KIND* pLookupKind) - => *pLookupKind = RestoreCORINFO_LOOKUP_KIND(LookupByHandle(GetLocationOfThisType, context)); + public void repGetLocationOfThisType(CORINFO_METHOD_STRUCT_* context, ref CORINFO_LOOKUP_KIND pLookupKind) + => pLookupKind = RestoreCORINFO_LOOKUP_KIND(LookupByHandle(GetLocationOfThisType, context)); public CORINFO_METHOD_STRUCT_* repGetDelegateCtor(CORINFO_METHOD_STRUCT_* methHnd, CORINFO_CLASS_STRUCT_* clsHnd, CORINFO_METHOD_STRUCT_* targetMethodHnd, - DelegateCtorArgs* pCtorData) + ref DelegateCtorArgs pCtorData) { var key = new Agnostic_GetDelegateCtorIn { methHnd = CastHandle(methHnd), clsHnd = CastHandle(clsHnd), targetMethodHnd = CastHandle(targetMethodHnd) }; Agnostic_GetDelegateCtorOut value = LookupByKeyOrMiss(GetDelegateCtor, key, ": key {0:X16}", key.methHnd); - pCtorData->pMethod = (void*)value.CtorData.pMethod; - pCtorData->pArg3 = (void*)value.CtorData.pArg3; - pCtorData->pArg4 = (void*)value.CtorData.pArg4; - pCtorData->pArg5 = (void*)value.CtorData.pArg5; + pCtorData.pMethod = (void*)value.CtorData.pMethod; + pCtorData.pArg3 = (void*)value.CtorData.pArg3; + pCtorData.pArg4 = (void*)value.CtorData.pArg4; + pCtorData.pArg5 = (void*)value.CtorData.pArg5; return (CORINFO_METHOD_STRUCT_*)value.result; } // The isUnsafeFunctionPointer has no impact on the resulting value; it only produces side effects in the runtime. - public void repGetFunctionFixedEntryPoint(CORINFO_METHOD_STRUCT_* ftn, bool isUnsafeFunctionPointer, CORINFO_CONST_LOOKUP* pResult) - => *pResult = RestoreCORINFO_CONST_LOOKUP(LookupByHandle(GetFunctionFixedEntryPoint, ftn)); + public void repGetFunctionFixedEntryPoint(CORINFO_METHOD_STRUCT_* ftn, bool isUnsafeFunctionPointer, ref CORINFO_CONST_LOOKUP pResult) + => pResult = RestoreCORINFO_CONST_LOOKUP(LookupByHandle(GetFunctionFixedEntryPoint, ftn)); public CORINFO_FIELD_STRUCT_* repGetFieldInClass(CORINFO_CLASS_STRUCT_* clsHnd, int num) { @@ -1175,11 +1176,11 @@ public CorInfoType repGetChildType(CORINFO_CLASS_STRUCT_* clsHnd, CORINFO_CLASS_ return (void*)LookupByKeyOrMiss(GetArrayInitializationData, key); } - public void repGetAddressOfPInvokeTarget(CORINFO_METHOD_STRUCT_* method, CORINFO_CONST_LOOKUP* pLookup) + public void repGetAddressOfPInvokeTarget(CORINFO_METHOD_STRUCT_* method, ref CORINFO_CONST_LOOKUP pLookup) { DLD value = LookupByHandle(GetAddressOfPInvokeTarget, method); - pLookup->addr = (void*)value.A; - pLookup->accessType = (InfoAccessType)value.B; + pLookup.addr = (void*)value.A; + pLookup.accessType = (InfoAccessType)value.B; } public uint repGetMethodHash(CORINFO_METHOD_STRUCT_* ftn) @@ -1207,7 +1208,7 @@ public void repFindCallSiteSig(CORINFO_MODULE_STRUCT_* module, uint methTOK, COR *sig = Restore_CORINFO_SIG_INFO(value, FindCallSiteSig, SigInstHandleMap, cr.MemoryTracker); } - public nint repGetVarArgsHandle(CORINFO_SIG_INFO* pSig, CORINFO_METHOD_STRUCT_* methHnd, void** ppIndirection) + public nint repGetVarArgsHandle(CORINFO_SIG_INFO* pSig, CORINFO_METHOD_STRUCT_* methHnd, ref void* ppIndirection) { var key = new GetVarArgsHandleValue { @@ -1218,16 +1219,16 @@ public nint repGetVarArgsHandle(CORINFO_SIG_INFO* pSig, CORINFO_METHOD_STRUCT_* methHnd = CastHandle(methHnd), }; DLDL value = LookupByKeyOrMiss(GetVarArgsHandle, key); - if (ppIndirection != null) - *ppIndirection = (void*)value.A; + if (!IsNullRef(ref ppIndirection)) + ppIndirection = (void*)value.A; return (nint)value.B; } - public uint repGetFieldThreadLocalStoreID(CORINFO_FIELD_STRUCT_* field, void** ppIndirection) + public uint repGetFieldThreadLocalStoreID(CORINFO_FIELD_STRUCT_* field, ref void* ppIndirection) { DLD value = LookupByHandle(GetFieldThreadLocalStoreID, field); - if (ppIndirection != null) - *ppIndirection = (void*)value.A; + if (!IsNullRef(ref ppIndirection)) + ppIndirection = (void*)value.A; return value.B; } @@ -1310,15 +1311,15 @@ private bool repAllocPgoInstrumentationBySchemaRecorded(CORINFO_METHOD_STRUCT_* return true; } - public HRESULT repGetPgoInstrumentationResults(CORINFO_METHOD_STRUCT_* ftnHnd, PgoInstrumentationSchema** pSchema, uint* pCountSchemaItems, - byte** pInstrumentationData, PgoSource* pPgoSource, bool* pDynamicPgo) + public HRESULT repGetPgoInstrumentationResults(CORINFO_METHOD_STRUCT_* ftnHnd, ref PgoInstrumentationSchema* pSchema, ref uint pCountSchemaItems, + byte** pInstrumentationData, ref PgoSource pPgoSource, ref bool pDynamicPgo) { Agnostic_GetPgoInstrumentationResults tempValue = LookupByHandle(GetPgoInstrumentationResults, ftnHnd); - *pCountSchemaItems = tempValue.countSchemaItems; + pCountSchemaItems = tempValue.countSchemaItems; *pInstrumentationData = GetPgoInstrumentationResults.GetBufferPointer(tempValue.data_index); - *pPgoSource = (PgoSource)tempValue.pgoSource; - *pDynamicPgo = tempValue.dynamicPgo != 0; + pPgoSource = (PgoSource)tempValue.pgoSource; + pDynamicPgo = tempValue.dynamicPgo != 0; var pOutSchema = (PgoInstrumentationSchema*)AllocJitTempBuffer(tempValue.countSchemaItems * (nuint)sizeof(PgoInstrumentationSchema)); byte* pAgnosticSchema = GetPgoInstrumentationResults.GetBufferPointer(tempValue.schema_index); @@ -1335,7 +1336,7 @@ public HRESULT repGetPgoInstrumentationResults(CORINFO_METHOD_STRUCT_* ftnHnd, P }; } - *pSchema = pOutSchema; + pSchema = pOutSchema; return (HRESULT)tempValue.result; } @@ -1373,19 +1374,19 @@ public TypeCompareState repIsEnum(CORINFO_CLASS_STRUCT_* cls, CORINFO_CLASS_STRU return (void*)LookupByKeyOrMiss(GetCookieForInterpreterCalliSig, key).A; } - public void repGetProfilingHandle(bool* pbHookFunction, void** pProfilerHandle, bool* pbIndirectedHandles) + public void repGetProfilingHandle(ref bool pbHookFunction, ref void* pProfilerHandle, ref bool pbIndirectedHandles) { Agnostic_GetProfilingHandle value = LookupByKeyOrMiss(GetProfilingHandle, 0u); - *pbHookFunction = value.bHookFunction != 0; - *pProfilerHandle = (void*)value.ProfilerHandle; - *pbIndirectedHandles = value.bIndirectedHandles != 0; + pbHookFunction = value.bHookFunction != 0; + pProfilerHandle = (void*)value.ProfilerHandle; + pbIndirectedHandles = value.bIndirectedHandles != 0; } - public CORINFO_FIELD_STRUCT_* repEmbedFieldHandle(CORINFO_FIELD_STRUCT_* handle, void** ppIndirection) + public CORINFO_FIELD_STRUCT_* repEmbedFieldHandle(CORINFO_FIELD_STRUCT_* handle, ref void* ppIndirection) { DLDL value = LookupByHandle(EmbedFieldHandle, handle); - if (ppIndirection != null) - *ppIndirection = (void*)value.A; + if (!IsNullRef(ref ppIndirection)) + ppIndirection = (void*)value.A; return (CORINFO_FIELD_STRUCT_*)value.B; } @@ -1415,27 +1416,27 @@ public bool repGetSystemVAmd64PassStructInRegisterDescriptor(CORINFO_CLASS_STRUC return value.result != 0; } - public void repGetSwiftLowering(CORINFO_CLASS_STRUCT_* structHnd, CORINFO_SWIFT_LOWERING* pLowering) + public void repGetSwiftLowering(CORINFO_CLASS_STRUCT_* structHnd, ref CORINFO_SWIFT_LOWERING pLowering) { Agnostic_GetSwiftLowering value = LookupByHandle(GetSwiftLowering, structHnd); - pLowering->byReference = value.byReference != 0; - pLowering->numLoweredElements = (nint)value.numLoweredElements; - for (int i = 0; i < pLowering->numLoweredElements; i++) + pLowering.byReference = value.byReference != 0; + pLowering.numLoweredElements = (nint)value.numLoweredElements; + for (int i = 0; i < pLowering.numLoweredElements; i++) { - pLowering->LoweredElements[i] = (CorInfoType)value.loweredElements[i]; - pLowering->Offsets[i] = value.offsets[i]; + pLowering.LoweredElements[i] = (CorInfoType)value.loweredElements[i]; + pLowering.Offsets[i] = value.offsets[i]; } } - public void repGetFpStructLowering(CORINFO_CLASS_STRUCT_* structHnd, CORINFO_FPSTRUCT_LOWERING* pLowering) + public void repGetFpStructLowering(CORINFO_CLASS_STRUCT_* structHnd, ref CORINFO_FPSTRUCT_LOWERING pLowering) { Agnostic_GetFpStructLowering value = LookupByHandle(GetFpStructLowering, structHnd); - pLowering->byIntegerCallConv = value.byIntegerCallConv != 0; - pLowering->numLoweredElements = (nint)value.numLoweredElements; - for (int i = 0; i < pLowering->numLoweredElements; i++) + pLowering.byIntegerCallConv = value.byIntegerCallConv != 0; + pLowering.numLoweredElements = (nint)value.numLoweredElements; + for (int i = 0; i < pLowering.numLoweredElements; i++) { - pLowering->LoweredElements[i] = (CorInfoType)value.loweredElements[i]; - pLowering->Offsets[i] = value.offsets[i]; + pLowering.LoweredElements[i] = (CorInfoType)value.loweredElements[i]; + pLowering.Offsets[i] = value.offsets[i]; } } @@ -1544,13 +1545,13 @@ public nuint repPrintFieldName(CORINFO_FIELD_STRUCT_* fld, byte* buffer, nuint b public nuint repPrintMethodName(CORINFO_METHOD_STRUCT_* meth, byte* buffer, nuint bufferSize, nuint* pRequiredBufferSize) => repPrint("PrintMethodName", PrintMethodName, CastHandle(meth), buffer, bufferSize, pRequiredBufferSize); - public bool repGetTailCallHelpers(CORINFO_RESOLVED_TOKEN* callToken, CORINFO_SIG_INFO* sig, CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, CORINFO_TAILCALL_HELPERS* pResult) + public bool repGetTailCallHelpers(ref CORINFO_RESOLVED_TOKEN callToken, CORINFO_SIG_INFO* sig, CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, ref CORINFO_TAILCALL_HELPERS pResult) { AssertMapExists(GetTailCallHelpers); var key = new Agnostic_GetTailCallHelpers { - callToken = RestoreAgnostic_CORINFO_RESOLVED_TOKEN(callToken, GetTailCallHelpers), + callToken = RestoreAgnostic_CORINFO_RESOLVED_TOKEN(ref callToken, GetTailCallHelpers), sig = RestoreAgnostic_CORINFO_SIG_INFO(*sig, GetTailCallHelpers, SigInstHandleMap), flags = (uint)flags, }; @@ -1558,28 +1559,28 @@ public bool repGetTailCallHelpers(CORINFO_RESOLVED_TOKEN* callToken, CORINFO_SIG if (value.result == 0) return false; - pResult->flags = (CORINFO_TAILCALL_HELPERS_FLAGS)value.flags; - pResult->hStoreArgs = (CORINFO_METHOD_STRUCT_*)value.hStoreArgs; - pResult->hCallTarget = (CORINFO_METHOD_STRUCT_*)value.hCallTarget; - pResult->hDispatcher = (CORINFO_METHOD_STRUCT_*)value.hDispatcher; + pResult.flags = (CORINFO_TAILCALL_HELPERS_FLAGS)value.flags; + pResult.hStoreArgs = (CORINFO_METHOD_STRUCT_*)value.hStoreArgs; + pResult.hCallTarget = (CORINFO_METHOD_STRUCT_*)value.hCallTarget; + pResult.hDispatcher = (CORINFO_METHOD_STRUCT_*)value.hDispatcher; return true; } - public CORINFO_METHOD_STRUCT_* repGetAsyncResumptionStub(void** entryPoint) + public CORINFO_METHOD_STRUCT_* repGetAsyncResumptionStub(ref void* entryPoint) { DLDL value = LookupByKeyOrMiss(GetAsyncResumptionStub, 0u); - *entryPoint = (void*)value.B; + entryPoint = (void*)value.B; return (CORINFO_METHOD_STRUCT_*)value.A; } - public CORINFO_CLASS_STRUCT_* repGetContinuationType(nuint dataSize, bool* objRefs, nuint objRefsSize) + public CORINFO_CLASS_STRUCT_* repGetContinuationType(nuint dataSize, ref bool objRefs, nuint objRefsSize) { AssertMapExists(GetContinuationType); var key = new Agnostic_GetContinuationTypeIn { dataSize = dataSize, - objRefs = (uint)GetContinuationType.Contains(Bytes(objRefs, objRefsSize)), + objRefs = (uint)GetContinuationType.Contains(MemoryMarshal.AsBytes(MemoryMarshal.CreateReadOnlySpan(ref objRefs, (int)objRefsSize))), objRefsSize = (uint)objRefsSize, }; @@ -1589,12 +1590,12 @@ public bool repGetTailCallHelpers(CORINFO_RESOLVED_TOKEN* callToken, CORINFO_SIG return (CORINFO_CLASS_STRUCT_*)(index == -1 ? CONTINUATION_TYPE_PSEUDO_CLASS_HANDLE : GetContinuationType.GetItem(index)); } - public void repUpdateEntryPointForTailCall(CORINFO_CONST_LOOKUP* entryPoint) + public void repUpdateEntryPointForTailCall(ref CORINFO_CONST_LOOKUP entryPoint) { AssertMapExists(UpdateEntryPointForTailCall); - Agnostic_CORINFO_CONST_LOOKUP key = StoreAgnostic_CORINFO_CONST_LOOKUP(entryPoint); - *entryPoint = RestoreCORINFO_CONST_LOOKUP(LookupByKeyOrMiss(UpdateEntryPointForTailCall, key)); + Agnostic_CORINFO_CONST_LOOKUP key = StoreAgnostic_CORINFO_CONST_LOOKUP(ref entryPoint); + entryPoint = RestoreCORINFO_CONST_LOOKUP(LookupByKeyOrMiss(UpdateEntryPointForTailCall, key)); } public mdToken repGetMethodDefFromMethod(CORINFO_METHOD_STRUCT_* hMethod) @@ -1756,12 +1757,12 @@ public bool hasPgoData(out bool hasEdgeProfile, out bool hasClassProfile, out bo if (GetPgoInstrumentationResults == null || GetPgoInstrumentationResults.GetIndex(CastHandle(info.ftn)) == -1) return false; - PgoInstrumentationSchema* schema; - uint schemaCount; + PgoInstrumentationSchema* schema = null; + uint schemaCount = 0; byte* schemaData; - PgoSource source; - bool dynamicPgo; - HRESULT pgoHR = repGetPgoInstrumentationResults(info.ftn, &schema, &schemaCount, &schemaData, &source, &dynamicPgo); + PgoSource source = default; + bool dynamicPgo = false; + HRESULT pgoHR = repGetPgoInstrumentationResults(info.ftn, ref schema, ref schemaCount, &schemaData, ref source, ref dynamicPgo); pgoSource = source; if (pgoHR < 0) return false; diff --git a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/SpmiRecordsHelper.cs b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/SpmiRecordsHelper.cs index a03d4a6792e6fe..551c52e716f1ef 100644 --- a/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/SpmiRecordsHelper.cs +++ b/src/coreclr/tools/superpmi/managed/SuperPmi.Shared/SpmiRecordsHelper.cs @@ -12,67 +12,75 @@ namespace SuperPmi; // JIT-EE types. public static unsafe class SpmiRecordsHelper { + // Unsafe.IsNullRef for a byref to a pointer, which can't be a type argument. The JIT passes no location for + // some of these. + public static bool IsNullRef(ref void* value) + { + fixed (void** p = &value) + return p == null; + } + private const int CORINFO_MAXINDIRECTIONS = 4; private const int CORINFO_ACCESS_ALLOWED_MAX_ARGS = 4; public static ulong CastHandle(void* h) => (ulong)h; - public static Agnostic_CORINFO_RESOLVED_TOKENin CreateAgnostic_CORINFO_RESOLVED_TOKENin(CORINFO_RESOLVED_TOKEN* pResolvedToken) + public static Agnostic_CORINFO_RESOLVED_TOKENin CreateAgnostic_CORINFO_RESOLVED_TOKENin(ref CORINFO_RESOLVED_TOKEN pResolvedToken) { var tokenIn = new Agnostic_CORINFO_RESOLVED_TOKENin(); - if (pResolvedToken != null) + if (!Unsafe.IsNullRef(ref pResolvedToken)) { - tokenIn.tokenContext = CastHandle(pResolvedToken->tokenContext); - tokenIn.tokenScope = CastHandle(pResolvedToken->tokenScope); - tokenIn.token = (uint)pResolvedToken->token; - tokenIn.tokenType = (uint)pResolvedToken->tokenType; + tokenIn.tokenContext = CastHandle(pResolvedToken.tokenContext); + tokenIn.tokenScope = CastHandle(pResolvedToken.tokenScope); + tokenIn.token = (uint)pResolvedToken.token; + tokenIn.tokenType = (uint)pResolvedToken.tokenType; } return tokenIn; } - public static Agnostic_CORINFO_RESOLVED_TOKENout CreateAgnostic_CORINFO_RESOLVED_TOKENout_without_buffers(CORINFO_RESOLVED_TOKEN* pResolvedToken) + public static Agnostic_CORINFO_RESOLVED_TOKENout CreateAgnostic_CORINFO_RESOLVED_TOKENout_without_buffers(ref CORINFO_RESOLVED_TOKEN pResolvedToken) { var tokenOut = new Agnostic_CORINFO_RESOLVED_TOKENout(); - if (pResolvedToken != null) + if (!Unsafe.IsNullRef(ref pResolvedToken)) { - tokenOut.hClass = CastHandle(pResolvedToken->hClass); - tokenOut.hMethod = CastHandle(pResolvedToken->hMethod); - tokenOut.hField = CastHandle(pResolvedToken->hField); - tokenOut.cbTypeSpec = pResolvedToken->cbTypeSpec; - tokenOut.cbMethodSpec = pResolvedToken->cbMethodSpec; + tokenOut.hClass = CastHandle(pResolvedToken.hClass); + tokenOut.hMethod = CastHandle(pResolvedToken.hMethod); + tokenOut.hField = CastHandle(pResolvedToken.hField); + tokenOut.cbTypeSpec = pResolvedToken.cbTypeSpec; + tokenOut.cbMethodSpec = pResolvedToken.cbMethodSpec; } tokenOut.pTypeSpec_Index = uint.MaxValue; tokenOut.pMethodSpec_Index = uint.MaxValue; return tokenOut; } - public static Agnostic_CORINFO_RESOLVED_TOKENout StoreAgnostic_CORINFO_RESOLVED_TOKENout(CORINFO_RESOLVED_TOKEN* pResolvedToken, LightWeightMapBuffer buffers) + public static Agnostic_CORINFO_RESOLVED_TOKENout StoreAgnostic_CORINFO_RESOLVED_TOKENout(ref CORINFO_RESOLVED_TOKEN pResolvedToken, LightWeightMapBuffer buffers) { - Agnostic_CORINFO_RESOLVED_TOKENout tokenOut = CreateAgnostic_CORINFO_RESOLVED_TOKENout_without_buffers(pResolvedToken); - if (pResolvedToken != null) + Agnostic_CORINFO_RESOLVED_TOKENout tokenOut = CreateAgnostic_CORINFO_RESOLVED_TOKENout_without_buffers(ref pResolvedToken); + if (!Unsafe.IsNullRef(ref pResolvedToken)) { - tokenOut.pTypeSpec_Index = buffers.AddBuffer(Bytes(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec)); - tokenOut.pMethodSpec_Index = buffers.AddBuffer(Bytes(pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec)); + tokenOut.pTypeSpec_Index = buffers.AddBuffer(Bytes(pResolvedToken.pTypeSpec, pResolvedToken.cbTypeSpec)); + tokenOut.pMethodSpec_Index = buffers.AddBuffer(Bytes(pResolvedToken.pMethodSpec, pResolvedToken.cbMethodSpec)); } return tokenOut; } - public static Agnostic_CORINFO_RESOLVED_TOKENout RestoreAgnostic_CORINFO_RESOLVED_TOKENout(CORINFO_RESOLVED_TOKEN* pResolvedToken, LightWeightMapBuffer buffers) + public static Agnostic_CORINFO_RESOLVED_TOKENout RestoreAgnostic_CORINFO_RESOLVED_TOKENout(ref CORINFO_RESOLVED_TOKEN pResolvedToken, LightWeightMapBuffer buffers) { - Agnostic_CORINFO_RESOLVED_TOKENout tokenOut = CreateAgnostic_CORINFO_RESOLVED_TOKENout_without_buffers(pResolvedToken); - if (pResolvedToken != null) + Agnostic_CORINFO_RESOLVED_TOKENout tokenOut = CreateAgnostic_CORINFO_RESOLVED_TOKENout_without_buffers(ref pResolvedToken); + if (!Unsafe.IsNullRef(ref pResolvedToken)) { - tokenOut.pTypeSpec_Index = (uint)buffers.Contains(Bytes(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec)); - tokenOut.pMethodSpec_Index = (uint)buffers.Contains(Bytes(pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec)); + tokenOut.pTypeSpec_Index = (uint)buffers.Contains(Bytes(pResolvedToken.pTypeSpec, pResolvedToken.cbTypeSpec)); + tokenOut.pMethodSpec_Index = (uint)buffers.Contains(Bytes(pResolvedToken.pMethodSpec, pResolvedToken.cbMethodSpec)); } return tokenOut; } - public static Agnostic_CORINFO_RESOLVED_TOKEN StoreAgnostic_CORINFO_RESOLVED_TOKEN(CORINFO_RESOLVED_TOKEN* pResolvedToken, LightWeightMapBuffer buffers) - => new() { inValue = CreateAgnostic_CORINFO_RESOLVED_TOKENin(pResolvedToken), outValue = StoreAgnostic_CORINFO_RESOLVED_TOKENout(pResolvedToken, buffers) }; + public static Agnostic_CORINFO_RESOLVED_TOKEN StoreAgnostic_CORINFO_RESOLVED_TOKEN(ref CORINFO_RESOLVED_TOKEN pResolvedToken, LightWeightMapBuffer buffers) + => new() { inValue = CreateAgnostic_CORINFO_RESOLVED_TOKENin(ref pResolvedToken), outValue = StoreAgnostic_CORINFO_RESOLVED_TOKENout(ref pResolvedToken, buffers) }; - public static Agnostic_CORINFO_RESOLVED_TOKEN RestoreAgnostic_CORINFO_RESOLVED_TOKEN(CORINFO_RESOLVED_TOKEN* pResolvedToken, LightWeightMapBuffer buffers) - => new() { inValue = CreateAgnostic_CORINFO_RESOLVED_TOKENin(pResolvedToken), outValue = RestoreAgnostic_CORINFO_RESOLVED_TOKENout(pResolvedToken, buffers) }; + public static Agnostic_CORINFO_RESOLVED_TOKEN RestoreAgnostic_CORINFO_RESOLVED_TOKEN(ref CORINFO_RESOLVED_TOKEN pResolvedToken, LightWeightMapBuffer buffers) + => new() { inValue = CreateAgnostic_CORINFO_RESOLVED_TOKENin(ref pResolvedToken), outValue = RestoreAgnostic_CORINFO_RESOLVED_TOKENout(ref pResolvedToken, buffers) }; public static CORINFO_RESOLVED_TOKEN Restore_CORINFO_RESOLVED_TOKEN(in Agnostic_CORINFO_RESOLVED_TOKEN pResolvedTokenAgnostic, LightWeightMapBuffer buffers) { @@ -83,23 +91,23 @@ public static CORINFO_RESOLVED_TOKEN Restore_CORINFO_RESOLVED_TOKEN(in Agnostic_ token = (mdToken)pResolvedTokenAgnostic.inValue.token, tokenType = (CorInfoTokenKind)pResolvedTokenAgnostic.inValue.tokenType, }; - Restore_CORINFO_RESOLVED_TOKENout(&token, pResolvedTokenAgnostic.outValue, buffers); + Restore_CORINFO_RESOLVED_TOKENout(ref token, pResolvedTokenAgnostic.outValue, buffers); return token; } // Restores the out values of the token; the in values are left as they are. - public static void Restore_CORINFO_RESOLVED_TOKENout(CORINFO_RESOLVED_TOKEN* pResolvedToken, in Agnostic_CORINFO_RESOLVED_TOKENout tokenOut, LightWeightMapBuffer buffers) + public static void Restore_CORINFO_RESOLVED_TOKENout(ref CORINFO_RESOLVED_TOKEN pResolvedToken, in Agnostic_CORINFO_RESOLVED_TOKENout tokenOut, LightWeightMapBuffer buffers) { - if (pResolvedToken == null) + if (Unsafe.IsNullRef(ref pResolvedToken)) return; - pResolvedToken->hClass = (CORINFO_CLASS_STRUCT_*)tokenOut.hClass; - pResolvedToken->hMethod = (CORINFO_METHOD_STRUCT_*)tokenOut.hMethod; - pResolvedToken->hField = (CORINFO_FIELD_STRUCT_*)tokenOut.hField; - pResolvedToken->pTypeSpec = buffers.GetBufferPointer(tokenOut.pTypeSpec_Index); - pResolvedToken->cbTypeSpec = tokenOut.cbTypeSpec; - pResolvedToken->pMethodSpec = buffers.GetBufferPointer(tokenOut.pMethodSpec_Index); - pResolvedToken->cbMethodSpec = tokenOut.cbMethodSpec; + pResolvedToken.hClass = (CORINFO_CLASS_STRUCT_*)tokenOut.hClass; + pResolvedToken.hMethod = (CORINFO_METHOD_STRUCT_*)tokenOut.hMethod; + pResolvedToken.hField = (CORINFO_FIELD_STRUCT_*)tokenOut.hField; + pResolvedToken.pTypeSpec = buffers.GetBufferPointer(tokenOut.pTypeSpec_Index); + pResolvedToken.cbTypeSpec = tokenOut.cbTypeSpec; + pResolvedToken.pMethodSpec = buffers.GetBufferPointer(tokenOut.pMethodSpec_Index); + pResolvedToken.cbMethodSpec = tokenOut.cbMethodSpec; } public static Agnostic_CORINFO_SIG_INFO CreateAgnostic_CORINFO_SIG_INFO_without_buffers(in CORINFO_SIG_INFO sigInfo) => new() @@ -239,11 +247,11 @@ public static CORINFO_SIG_INFO Restore_CORINFO_SIG_INFO(in Agnostic_CORINFO_SIG_ }, }; - public static Agnostic_CORINFO_LOOKUP_KIND CreateAgnostic_CORINFO_LOOKUP_KIND(CORINFO_LOOKUP_KIND* pGenericLookupKind) - => pGenericLookupKind == null ? default : new() + public static Agnostic_CORINFO_LOOKUP_KIND CreateAgnostic_CORINFO_LOOKUP_KIND(ref CORINFO_LOOKUP_KIND pGenericLookupKind) + => Unsafe.IsNullRef(ref pGenericLookupKind) ? default : new() { - needsRuntimeLookup = pGenericLookupKind->needsRuntimeLookup ? 1u : 0u, - runtimeLookupKind = (uint)pGenericLookupKind->runtimeLookupKind, + needsRuntimeLookup = pGenericLookupKind.needsRuntimeLookup ? 1u : 0u, + runtimeLookupKind = (uint)pGenericLookupKind.runtimeLookupKind, }; public static CORINFO_LOOKUP_KIND RestoreCORINFO_LOOKUP_KIND(in Agnostic_CORINFO_LOOKUP_KIND lookupKind) => new() @@ -252,27 +260,27 @@ public static Agnostic_CORINFO_LOOKUP_KIND CreateAgnostic_CORINFO_LOOKUP_KIND(CO runtimeLookupKind = (CORINFO_RUNTIME_LOOKUP_KIND)lookupKind.runtimeLookupKind, }; - public static Agnostic_CORINFO_CONST_LOOKUP StoreAgnostic_CORINFO_CONST_LOOKUP(CORINFO_CONST_LOOKUP* pLookup) - => new() { accessType = (uint)pLookup->accessType, handle = CastHandle(pLookup->handle) }; + public static Agnostic_CORINFO_CONST_LOOKUP StoreAgnostic_CORINFO_CONST_LOOKUP(ref CORINFO_CONST_LOOKUP pLookup) + => new() { accessType = (uint)pLookup.accessType, handle = CastHandle(pLookup.handle) }; public static CORINFO_CONST_LOOKUP RestoreCORINFO_CONST_LOOKUP(in Agnostic_CORINFO_CONST_LOOKUP lookup) => new() { accessType = (InfoAccessType)lookup.accessType, handle = (CORINFO_GENERIC_STRUCT_*)lookup.handle }; - public static Agnostic_CORINFO_RUNTIME_LOOKUP StoreAgnostic_CORINFO_RUNTIME_LOOKUP(CORINFO_RUNTIME_LOOKUP* pLookup) + public static Agnostic_CORINFO_RUNTIME_LOOKUP StoreAgnostic_CORINFO_RUNTIME_LOOKUP(ref CORINFO_RUNTIME_LOOKUP pLookup) { var runtimeLookup = new Agnostic_CORINFO_RUNTIME_LOOKUP { - signature = CastHandle(pLookup->signature), - helper = (uint)pLookup->helper, - indirections = pLookup->indirections, - testForNull = pLookup->_testForNull, - sizeOffset = pLookup->sizeOffset, - indirectFirstOffset = pLookup->_indirectFirstOffset, - indirectSecondOffset = pLookup->_indirectSecondOffset, - helperEntryPoint = StoreAgnostic_CORINFO_CONST_LOOKUP(&pLookup->helperEntryPoint), + signature = CastHandle(pLookup.signature), + helper = (uint)pLookup.helper, + indirections = pLookup.indirections, + testForNull = pLookup._testForNull, + sizeOffset = pLookup.sizeOffset, + indirectFirstOffset = pLookup._indirectFirstOffset, + indirectSecondOffset = pLookup._indirectSecondOffset, + helperEntryPoint = StoreAgnostic_CORINFO_CONST_LOOKUP(ref pLookup.helperEntryPoint), }; for (int i = 0; i < CORINFO_MAXINDIRECTIONS; i++) - runtimeLookup.offsets[i] = (nuint)Unsafe.Add(ref pLookup->offset0, i); + runtimeLookup.offsets[i] = (nuint)Unsafe.Add(ref pLookup.offset0, i); return runtimeLookup; } @@ -294,13 +302,13 @@ public static CORINFO_RUNTIME_LOOKUP RestoreCORINFO_RUNTIME_LOOKUP(in Agnostic_C return runtimeLookup; } - public static Agnostic_CORINFO_LOOKUP StoreAgnostic_CORINFO_LOOKUP(CORINFO_LOOKUP* pLookup) + public static Agnostic_CORINFO_LOOKUP StoreAgnostic_CORINFO_LOOKUP(ref CORINFO_LOOKUP pLookup) { - var lookup = new Agnostic_CORINFO_LOOKUP { lookupKind = CreateAgnostic_CORINFO_LOOKUP_KIND(&pLookup->lookupKind) }; - if (pLookup->lookupKind.needsRuntimeLookup) - lookup.runtimeLookup = StoreAgnostic_CORINFO_RUNTIME_LOOKUP(&pLookup->runtimeLookup); + var lookup = new Agnostic_CORINFO_LOOKUP { lookupKind = CreateAgnostic_CORINFO_LOOKUP_KIND(ref pLookup.lookupKind) }; + if (pLookup.lookupKind.needsRuntimeLookup) + lookup.runtimeLookup = StoreAgnostic_CORINFO_RUNTIME_LOOKUP(ref pLookup.runtimeLookup); else - lookup.constLookup = StoreAgnostic_CORINFO_CONST_LOOKUP((CORINFO_CONST_LOOKUP*)&pLookup->runtimeLookup); + lookup.constLookup = StoreAgnostic_CORINFO_CONST_LOOKUP(ref Unsafe.As(ref pLookup.runtimeLookup)); return lookup; } diff --git a/src/coreclr/tools/superpmi/managed/superpmi-shim-collector/CorInfoImpl.Collector.cs b/src/coreclr/tools/superpmi/managed/superpmi-shim-collector/CorInfoImpl.Collector.cs index 424b7251aa5bbb..a81b3fc02c43f3 100644 --- a/src/coreclr/tools/superpmi/managed/superpmi-shim-collector/CorInfoImpl.Collector.cs +++ b/src/coreclr/tools/superpmi/managed/superpmi-shim-collector/CorInfoImpl.Collector.cs @@ -145,8 +145,7 @@ private void resolveToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken) } finally { - fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) - mc.recResolveToken(pResolvedTokenPtr, exceptionCode); + mc.recResolveToken(ref pResolvedToken, exceptionCode); } } @@ -289,8 +288,7 @@ private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESO } finally { - fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) - mc.recGetCallInfo(pResolvedTokenPtr, pConstrainedResolvedToken, callerHandle, flags, pResult, exceptionCode); + mc.recGetCallInfo(ref pResolvedToken, pConstrainedResolvedToken, callerHandle, flags, pResult, exceptionCode); } } @@ -298,9 +296,7 @@ private bool getTailCallHelpers(ref CORINFO_RESOLVED_TOKEN callToken, CORINFO_SI { AddCall("getTailCallHelpers"); bool result = _original.getTailCallHelpers(ref callToken, sig, flags, ref pResult); - fixed (CORINFO_RESOLVED_TOKEN* callTokenPtr = &callToken) - fixed (CORINFO_TAILCALL_HELPERS* pResultPtr = &pResult) - mc.recGetTailCallHelpers(callTokenPtr, sig, flags, result ? pResultPtr : null); + mc.recGetTailCallHelpers(ref callToken, sig, flags, result, ref pResult); return result; } @@ -374,11 +370,7 @@ private HRESULT getPgoInstrumentationResults(CORINFO_METHOD_STRUCT_* ftnHnd, ref { AddCall("getPgoInstrumentationResults"); HRESULT temp = _original.getPgoInstrumentationResults(ftnHnd, ref pSchema, ref pCountSchemaItems, pInstrumentationData, ref pPgoSource, ref pDynamicPgo); - fixed (PgoInstrumentationSchema** pSchemaPtr = &pSchema) - fixed (uint* pCountSchemaItemsPtr = &pCountSchemaItems) - fixed (PgoSource* pPgoSourcePtr = &pPgoSource) - fixed (bool* pDynamicPgoPtr = &pDynamicPgo) - mc.recGetPgoInstrumentationResults(ftnHnd, pSchemaPtr, pCountSchemaItemsPtr, pInstrumentationData, pPgoSourcePtr, pDynamicPgoPtr, (int)temp); + mc.recGetPgoInstrumentationResults(ftnHnd, ref pSchema, ref pCountSchemaItems, pInstrumentationData, ref pPgoSource, ref pDynamicPgo, (int)temp); return temp; } @@ -474,8 +466,7 @@ private void getEHinfo(CORINFO_METHOD_STRUCT_* ftn, uint EHnumber, ref CORINFO_E { AddCall("getEHinfo"); _original.getEHinfo(ftn, EHnumber, ref clause); - fixed (CORINFO_EH_CLAUSE* clausePtr = &clause) - mc.recGetEHinfo(ftn, EHnumber, clausePtr); + mc.recGetEHinfo(ftn, EHnumber, ref clause); } private CORINFO_CLASS_STRUCT_* getMethodClass(CORINFO_METHOD_STRUCT_* method) @@ -490,10 +481,7 @@ private void getMethodVTableOffset(CORINFO_METHOD_STRUCT_* method, ref uint offs { AddCall("getMethodVTableOffset"); _original.getMethodVTableOffset(method, ref offsetOfIndirection, ref offsetAfterIndirection, ref isRelative); - fixed (uint* offsetOfIndirectionPtr = &offsetOfIndirection) - fixed (uint* offsetAfterIndirectionPtr = &offsetAfterIndirection) - fixed (bool* isRelativePtr = &isRelative) - mc.recGetMethodVTableOffset(method, offsetOfIndirectionPtr, offsetAfterIndirectionPtr, isRelativePtr); + mc.recGetMethodVTableOffset(method, ref offsetOfIndirection, ref offsetAfterIndirection, ref isRelative); } private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) @@ -540,9 +528,7 @@ private void expandRawHandleIntrinsic(ref CORINFO_RESOLVED_TOKEN pResolvedToken, { AddCall("expandRawHandleIntrinsic"); _original.expandRawHandleIntrinsic(ref pResolvedToken, callerHandle, ref pResult); - fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) - fixed (CORINFO_GENERICHANDLE_RESULT* pResultPtr = &pResult) - mc.recExpandRawHandleIntrinsic(pResolvedTokenPtr, callerHandle, pResultPtr); + mc.recExpandRawHandleIntrinsic(ref pResolvedToken, callerHandle, ref pResult); } private bool isIntrinsicType(CORINFO_CLASS_STRUCT_* classHnd) @@ -595,8 +581,7 @@ private void setPatchpointInfo(PatchpointInfo* patchpointInfo) { AddCall("getOSRInfo"); var patchpointInfo = _original.getOSRInfo(ref ilOffset); - fixed (uint* ilOffsetPtr = &ilOffset) - mc.recGetOSRInfo(patchpointInfo, ilOffsetPtr); + mc.recGetOSRInfo(patchpointInfo, ref ilOffset); return patchpointInfo; } @@ -618,8 +603,7 @@ private void findCallSiteSig(CORINFO_MODULE_STRUCT_* module, uint methTOK, CORIN { AddCall("getTokenTypeAsHandle"); var temp = _original.getTokenTypeAsHandle(ref pResolvedToken); - fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) - mc.recGetTokenTypeAsHandle(pResolvedTokenPtr, temp); + mc.recGetTokenTypeAsHandle(ref pResolvedToken, temp); return temp; } @@ -735,9 +719,7 @@ private bool getIsClassInitedFlagAddress(CORINFO_CLASS_STRUCT_* cls, ref CORINFO { AddCall("getIsClassInitedFlagAddress"); var temp = _original.getIsClassInitedFlagAddress(cls, ref addr, ref offset); - fixed (CORINFO_CONST_LOOKUP* addrPtr = &addr) - fixed (int* offsetPtr = &offset) - mc.recGetIsClassInitedFlagAddress(cls, addrPtr, offsetPtr, temp); + mc.recGetIsClassInitedFlagAddress(cls, ref addr, ref offset, temp); return temp; } @@ -761,8 +743,7 @@ private bool getStaticBaseAddress(CORINFO_CLASS_STRUCT_* cls, bool isGc, ref COR { AddCall("getStaticBaseAddress"); var temp = _original.getStaticBaseAddress(cls, isGc, ref addr); - fixed (CORINFO_CONST_LOOKUP* addrPtr = &addr) - mc.recGetStaticBaseAddress(cls, isGc, addrPtr, temp); + mc.recGetStaticBaseAddress(cls, isGc, ref addr, temp); return temp; } @@ -842,8 +823,7 @@ private CorInfoHelpFunc getCastingHelper(ref CORINFO_RESOLVED_TOKEN pResolvedTok { AddCall("getCastingHelper"); var temp = _original.getCastingHelper(ref pResolvedToken, fThrowing); - fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) - mc.recGetCastingHelper(pResolvedTokenPtr, fThrowing, temp); + mc.recGetCastingHelper(ref pResolvedToken, fThrowing, temp); return temp; } @@ -915,9 +895,7 @@ private bool getReadyToRunHelper(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CorI { AddCall("getReadyToRunHelper"); var result = _original.getReadyToRunHelper(ref pResolvedToken, id, callerHandle, ref pLookup); - fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) - fixed (CORINFO_CONST_LOOKUP* pLookupPtr = &pLookup) - mc.recGetReadyToRunHelper(pResolvedTokenPtr, id, callerHandle, pLookupPtr, result); + mc.recGetReadyToRunHelper(ref pResolvedToken, id, callerHandle, ref pLookup, result); return result; } @@ -925,9 +903,7 @@ private void getReadyToRunDelegateCtorHelper(ref CORINFO_RESOLVED_TOKEN pTargetM { AddCall("getReadyToRunDelegateCtorHelper"); _original.getReadyToRunDelegateCtorHelper(ref pTargetMethod, targetConstraint, delegateType, callerHandle, ref pLookup); - fixed (CORINFO_RESOLVED_TOKEN* pTargetMethodPtr = &pTargetMethod) - fixed (CORINFO_LOOKUP* pLookupPtr = &pLookup) - mc.recGetReadyToRunDelegateCtorHelper(pTargetMethodPtr, (uint)targetConstraint, delegateType, callerHandle, pLookupPtr); + mc.recGetReadyToRunDelegateCtorHelper(ref pTargetMethod, (uint)targetConstraint, delegateType, callerHandle, ref pLookup); } private CorInfoInitClassResult initClass(CORINFO_FIELD_STRUCT_* field, CORINFO_METHOD_STRUCT_* method, CORINFO_CONTEXT_STRUCT* context) @@ -1062,9 +1038,7 @@ private CorInfoIsAccessAllowedResult canAccessClass(ref CORINFO_RESOLVED_TOKEN p { AddCall("canAccessClass"); var temp = _original.canAccessClass(ref pResolvedToken, callerHandle, ref pAccessHelper); - fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) - fixed (CORINFO_HELPER_DESC* pAccessHelperPtr = &pAccessHelper) - mc.recCanAccessClass(pResolvedTokenPtr, callerHandle, pAccessHelperPtr, temp); + mc.recCanAccessClass(ref pResolvedToken, callerHandle, ref pAccessHelper, temp); return temp; } @@ -1104,8 +1078,7 @@ private void getFieldInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_MET { AddCall("getFieldInfo"); _original.getFieldInfo(ref pResolvedToken, callerHandle, flags, pResult); - fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) - mc.recGetFieldInfo(pResolvedTokenPtr, callerHandle, flags, pResult); + mc.recGetFieldInfo(ref pResolvedToken, callerHandle, flags, pResult); } private uint getThreadLocalFieldInfo(CORINFO_FIELD_STRUCT_* field, bool isGCType) @@ -1150,9 +1123,7 @@ private void getBoundaries(CORINFO_METHOD_STRUCT_* ftn, ref uint cILOffsets, ref { AddCall("getBoundaries"); _original.getBoundaries(ftn, ref cILOffsets, ref pILOffsets, implicitBoundaries); - fixed (uint* cILOffsetsPtr = &cILOffsets) - fixed (uint** pILOffsetsPtr = &pILOffsets) - mc.recGetBoundaries(ftn, cILOffsetsPtr, pILOffsetsPtr, implicitBoundaries); + mc.recGetBoundaries(ftn, ref cILOffsets, ref pILOffsets, implicitBoundaries); } private void setBoundaries(CORINFO_METHOD_STRUCT_* ftn, uint cMap, OffsetMapping* pMap) @@ -1166,9 +1137,7 @@ private void getVars(CORINFO_METHOD_STRUCT_* ftn, ref uint cVars, ILVarInfo** va { AddCall("getVars"); _original.getVars(ftn, ref cVars, vars, ref extendOthers); - fixed (uint* cVarsPtr = &cVars) - fixed (bool* extendOthersPtr = &extendOthers) - mc.recGetVars(ftn, cVarsPtr, vars, extendOthersPtr); + mc.recGetVars(ftn, ref cVars, vars, ref extendOthers); } private void setVars(CORINFO_METHOD_STRUCT_* ftn, uint cVars, NativeVarInfo* vars) @@ -1216,24 +1185,21 @@ private void getEEInfo(ref CORINFO_EE_INFO pEEInfoOut) { AddCall("getEEInfo"); _original.getEEInfo(ref pEEInfoOut); - fixed (CORINFO_EE_INFO* pEEInfoOutPtr = &pEEInfoOut) - mc.recGetEEInfo(pEEInfoOutPtr); + mc.recGetEEInfo(ref pEEInfoOut); } private void getAsyncInfo(ref CORINFO_ASYNC_INFO pAsyncInfo) { AddCall("getAsyncInfo"); _original.getAsyncInfo(ref pAsyncInfo); - fixed (CORINFO_ASYNC_INFO* pAsyncInfoPtr = &pAsyncInfo) - mc.recGetAsyncInfo(pAsyncInfoPtr); + mc.recGetAsyncInfo(ref pAsyncInfo); } private CORINFO_METHOD_STRUCT_* getAwaitReturnCall(CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_CONTEXT_STRUCT** contextHandle, ref CORINFO_LOOKUP instArg) { AddCall("getAwaitReturnCall"); var result = _original.getAwaitReturnCall(callerHandle, contextHandle, ref instArg); - fixed (CORINFO_LOOKUP* instArgPtr = &instArg) - mc.recGetAwaitReturnCall(callerHandle, contextHandle, instArgPtr, result); + mc.recGetAwaitReturnCall(callerHandle, contextHandle, ref instArg, result); return result; } @@ -1241,9 +1207,7 @@ private void getAsyncInfo(ref CORINFO_ASYNC_INFO pAsyncInfo) { AddCall("getAwaitAwaiterInContinuationCall"); var result = _original.getAwaitAwaiterInContinuationCall(callerHandle, ref pResolvedToken, isUnsafe, contextHandle, ref instArg); - fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) - fixed (CORINFO_LOOKUP* instArgPtr = &instArg) - mc.recGetAwaitAwaiterInContinuationCall(callerHandle, pResolvedTokenPtr, isUnsafe, contextHandle, instArgPtr, result); + mc.recGetAwaitAwaiterInContinuationCall(callerHandle, ref pResolvedToken, isUnsafe, contextHandle, ref instArg, result); return result; } @@ -1291,16 +1255,14 @@ private void getSwiftLowering(CORINFO_CLASS_STRUCT_* structHnd, ref CORINFO_SWIF { AddCall("getSwiftLowering"); _original.getSwiftLowering(structHnd, ref pLowering); - fixed (CORINFO_SWIFT_LOWERING* pLoweringPtr = &pLowering) - mc.recGetSwiftLowering(structHnd, pLoweringPtr); + mc.recGetSwiftLowering(structHnd, ref pLowering); } private void getFpStructLowering(CORINFO_CLASS_STRUCT_* structHnd, ref CORINFO_FPSTRUCT_LOWERING pLowering) { AddCall("getFpStructLowering"); _original.getFpStructLowering(structHnd, ref pLowering); - fixed (CORINFO_FPSTRUCT_LOWERING* pLoweringPtr = &pLowering) - mc.recGetFpStructLowering(structHnd, pLoweringPtr); + mc.recGetFpStructLowering(structHnd, ref pLowering); } private CorInfoWasmType getWasmLowering(CORINFO_CLASS_STRUCT_* structHnd) @@ -1323,16 +1285,14 @@ private void getWasmWellKnownGlobals(ref CORINFO_WASM_WELLKNOWN_GLOBALS pWellKno { AddCall("getWasmWellKnownGlobals"); _original.getWasmWellKnownGlobals(ref pWellKnownGlobalsOut); - fixed (CORINFO_WASM_WELLKNOWN_GLOBALS* pWellKnownGlobalsOutPtr = &pWellKnownGlobalsOut) - mc.recGetWasmWellKnownGlobals(pWellKnownGlobalsOutPtr); + mc.recGetWasmWellKnownGlobals(ref pWellKnownGlobalsOut); } private uint getThreadTLSIndex(ref void* ppIndirection) { AddCall("getThreadTLSIndex"); var temp = _original.getThreadTLSIndex(ref ppIndirection); - fixed (void** ppIndirectionPtr = &ppIndirection) - mc.recGetThreadTLSIndex(ppIndirectionPtr, temp); + mc.recGetThreadTLSIndex(ref ppIndirection, temp); return temp; } @@ -1340,8 +1300,7 @@ private uint getThreadTLSIndex(ref void* ppIndirection) { AddCall("getAddrOfCaptureThreadGlobal"); var temp = _original.getAddrOfCaptureThreadGlobal(ref ppIndirection); - fixed (void** ppIndirectionPtr = &ppIndirection) - mc.recGetAddrOfCaptureThreadGlobal(ppIndirectionPtr, temp); + mc.recGetAddrOfCaptureThreadGlobal(ref ppIndirection, temp); return temp; } @@ -1349,24 +1308,21 @@ private void getFunctionEntryPoint(CORINFO_METHOD_STRUCT_* ftn, ref CORINFO_CONS { AddCall("getFunctionEntryPoint"); _original.getFunctionEntryPoint(ftn, ref pResult, accessFlags); - fixed (CORINFO_CONST_LOOKUP* pResultPtr = &pResult) - mc.recGetFunctionEntryPoint(ftn, pResultPtr, accessFlags); + mc.recGetFunctionEntryPoint(ftn, ref pResult, accessFlags); } private void getFunctionFixedEntryPoint(CORINFO_METHOD_STRUCT_* ftn, bool isUnsafeFunctionPointer, ref CORINFO_CONST_LOOKUP pResult) { AddCall("getFunctionFixedEntryPoint"); _original.getFunctionFixedEntryPoint(ftn, isUnsafeFunctionPointer, ref pResult); - fixed (CORINFO_CONST_LOOKUP* pResultPtr = &pResult) - mc.recGetFunctionFixedEntryPoint(ftn, pResultPtr); + mc.recGetFunctionFixedEntryPoint(ftn, ref pResult); } private CORINFO_MODULE_STRUCT_* embedModuleHandle(CORINFO_MODULE_STRUCT_* handle, ref void* ppIndirection) { AddCall("embedModuleHandle"); var temp = _original.embedModuleHandle(handle, ref ppIndirection); - fixed (void** ppIndirectionPtr = &ppIndirection) - mc.recEmbedModuleHandle(handle, ppIndirectionPtr, temp); + mc.recEmbedModuleHandle(handle, ref ppIndirection, temp); return temp; } @@ -1374,8 +1330,7 @@ private void getFunctionFixedEntryPoint(CORINFO_METHOD_STRUCT_* ftn, bool isUnsa { AddCall("embedClassHandle"); var temp = _original.embedClassHandle(handle, ref ppIndirection); - fixed (void** ppIndirectionPtr = &ppIndirection) - mc.recEmbedClassHandle(handle, ppIndirectionPtr, temp); + mc.recEmbedClassHandle(handle, ref ppIndirection, temp); return temp; } @@ -1383,8 +1338,7 @@ private void getFunctionFixedEntryPoint(CORINFO_METHOD_STRUCT_* ftn, bool isUnsa { AddCall("embedMethodHandle"); var temp = _original.embedMethodHandle(handle, ref ppIndirection); - fixed (void** ppIndirectionPtr = &ppIndirection) - mc.recEmbedMethodHandle(handle, ppIndirectionPtr, temp); + mc.recEmbedMethodHandle(handle, ref ppIndirection, temp); return temp; } @@ -1392,8 +1346,7 @@ private void getFunctionFixedEntryPoint(CORINFO_METHOD_STRUCT_* ftn, bool isUnsa { AddCall("embedFieldHandle"); var temp = _original.embedFieldHandle(handle, ref ppIndirection); - fixed (void** ppIndirectionPtr = &ppIndirection) - mc.recEmbedFieldHandle(handle, ppIndirectionPtr, temp); + mc.recEmbedFieldHandle(handle, ref ppIndirection, temp); return temp; } @@ -1401,25 +1354,21 @@ private void embedGenericHandle(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool { AddCall("embedGenericHandle"); _original.embedGenericHandle(ref pResolvedToken, fEmbedParent, callerHandle, ref pResult); - fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) - fixed (CORINFO_GENERICHANDLE_RESULT* pResultPtr = &pResult) - mc.recEmbedGenericHandle(pResolvedTokenPtr, fEmbedParent, callerHandle, pResultPtr); + mc.recEmbedGenericHandle(ref pResolvedToken, fEmbedParent, callerHandle, ref pResult); } private void getLocationOfThisType(CORINFO_METHOD_STRUCT_* context, ref CORINFO_LOOKUP_KIND pLookupKind) { AddCall("getLocationOfThisType"); _original.getLocationOfThisType(context, ref pLookupKind); - fixed (CORINFO_LOOKUP_KIND* pLookupKindPtr = &pLookupKind) - mc.recGetLocationOfThisType(context, pLookupKindPtr); + mc.recGetLocationOfThisType(context, ref pLookupKind); } private void getAddressOfPInvokeTarget(CORINFO_METHOD_STRUCT_* method, ref CORINFO_CONST_LOOKUP pLookup) { AddCall("getAddressOfPInvokeTarget"); _original.getAddressOfPInvokeTarget(method, ref pLookup); - fixed (CORINFO_CONST_LOOKUP* pLookupPtr = &pLookup) - mc.recGetAddressOfPInvokeTarget(method, pLookupPtr); + mc.recGetAddressOfPInvokeTarget(method, ref pLookup); } private void* GetCookieForInterpreterCalliSig(CORINFO_SIG_INFO* szMetaSig) @@ -1434,8 +1383,7 @@ private void getAddressOfPInvokeTarget(CORINFO_METHOD_STRUCT_* method, ref CORIN { AddCall("getJustMyCodeHandle"); var temp = _original.getJustMyCodeHandle(method, ref ppIndirection); - fixed (CORINFO_JUST_MY_CODE_HANDLE_** ppIndirectionPtr = &ppIndirection) - mc.recGetJustMyCodeHandle(method, ppIndirectionPtr, temp); + mc.recGetJustMyCodeHandle(method, ref ppIndirection, temp); return temp; } @@ -1443,10 +1391,7 @@ private void GetProfilingHandle(ref bool pbHookFunction, ref void* pProfilerHand { AddCall("GetProfilingHandle"); _original.GetProfilingHandle(ref pbHookFunction, ref pProfilerHandle, ref pbIndirectedHandles); - fixed (bool* pbHookFunctionPtr = &pbHookFunction) - fixed (void** pProfilerHandlePtr = &pProfilerHandle) - fixed (bool* pbIndirectedHandlesPtr = &pbIndirectedHandles) - mc.recGetProfilingHandle(pbHookFunctionPtr, pProfilerHandlePtr, pbIndirectedHandlesPtr); + mc.recGetProfilingHandle(ref pbHookFunction, ref pProfilerHandle, ref pbIndirectedHandles); } private bool getStaticFieldContent(CORINFO_FIELD_STRUCT_* field, byte* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects) @@ -1477,8 +1422,7 @@ private IntPtr getVarArgsHandle(CORINFO_SIG_INFO* pSig, CORINFO_METHOD_STRUCT_* { AddCall("getVarArgsHandle"); var temp = _original.getVarArgsHandle(pSig, methHnd, ref ppIndirection); - fixed (void** ppIndirectionPtr = &ppIndirection) - mc.recGetVarArgsHandle(pSig, methHnd, ppIndirectionPtr, (void*)temp); + mc.recGetVarArgsHandle(pSig, methHnd, ref ppIndirection, (void*)temp); return temp; } @@ -1494,8 +1438,7 @@ private InfoAccessType emptyStringLiteral(ref void* ppValue) { AddCall("emptyStringLiteral"); var temp = _original.emptyStringLiteral(ref ppValue); - fixed (void** ppValuePtr = &ppValue) - mc.recEmptyStringLiteral(ppValuePtr, temp); + mc.recEmptyStringLiteral(ref ppValue, temp); return temp; } @@ -1503,8 +1446,7 @@ private uint getFieldThreadLocalStoreID(CORINFO_FIELD_STRUCT_* field, ref void* { AddCall("getFieldThreadLocalStoreID"); var temp = _original.getFieldThreadLocalStoreID(field, ref ppIndirection); - fixed (void** ppIndirectionPtr = &ppIndirection) - mc.recGetFieldThreadLocalStoreID(field, ppIndirectionPtr, temp); + mc.recGetFieldThreadLocalStoreID(field, ref ppIndirection, temp); return temp; } @@ -1512,8 +1454,7 @@ private uint getFieldThreadLocalStoreID(CORINFO_FIELD_STRUCT_* field, ref void* { AddCall("GetDelegateCtor"); var temp = _original.GetDelegateCtor(methHnd, clsHnd, targetMethodHnd, ref pCtorData); - fixed (DelegateCtorArgs* pCtorDataPtr = &pCtorData) - mc.recGetDelegateCtor(methHnd, clsHnd, targetMethodHnd, pCtorDataPtr, temp); + mc.recGetDelegateCtor(methHnd, clsHnd, targetMethodHnd, ref pCtorData, temp); return temp; } @@ -1527,8 +1468,7 @@ private void MethodCompileComplete(CORINFO_METHOD_STRUCT_* methHnd) { AddCall("getContinuationType"); var result = _original.getContinuationType(dataSize, ref objRefs, objRefsSize); - fixed (bool* objRefsPtr = &objRefs) - mc.recGetContinuationType(dataSize, objRefsPtr, objRefsSize, result); + mc.recGetContinuationType(dataSize, ref objRefs, objRefsSize, result); return result; } @@ -1544,8 +1484,7 @@ private bool convertPInvokeCalliToCall(ref CORINFO_RESOLVED_TOKEN pResolvedToken { AddCall("convertPInvokeCalliToCall"); var result = _original.convertPInvokeCalliToCall(ref pResolvedToken, fMustConvert); - fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) - mc.recConvertPInvokeCalliToCall(pResolvedTokenPtr, fMustConvert, result); + mc.recConvertPInvokeCalliToCall(ref pResolvedToken, fMustConvert, result); return result; } @@ -1596,8 +1535,7 @@ private void setEHinfo(uint EHnumber, ref CORINFO_EH_CLAUSE clause) { AddCall("setEHinfo"); _original.setEHinfo(EHnumber, ref clause); - fixed (CORINFO_EH_CLAUSE* clausePtr = &clause) - cr.recSetEHinfo(EHnumber, clausePtr); + cr.recSetEHinfo(EHnumber, ref clause); } private bool logMsg(uint level, byte* fmt, IntPtr args) @@ -1655,8 +1593,7 @@ private uint getJitFlags(ref CORJIT_FLAGS jitFlags, uint sizeInBytes) { AddCall("getJitFlags"); var result = _original.getJitFlags(ref jitFlags, sizeInBytes); - fixed (CORJIT_FLAGS* jitFlagsPtr = &jitFlags) - mc.recGetJitFlags(jitFlagsPtr, sizeInBytes, result); + mc.recGetJitFlags(ref jitFlags, sizeInBytes, result); return result; } diff --git a/src/coreclr/tools/superpmi/managed/superpmi/CorInfoImpl.SuperPmi.cs b/src/coreclr/tools/superpmi/managed/superpmi/CorInfoImpl.SuperPmi.cs index c5440acfd8b8cc..aa1641bde6cbb2 100644 --- a/src/coreclr/tools/superpmi/managed/superpmi/CorInfoImpl.SuperPmi.cs +++ b/src/coreclr/tools/superpmi/managed/superpmi/CorInfoImpl.SuperPmi.cs @@ -178,8 +178,7 @@ private void reportTailCallDecision(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_M private void getEHinfo(CORINFO_METHOD_STRUCT_* ftn, uint EHnumber, ref CORINFO_EH_CLAUSE clause) { AddCall("getEHinfo"); - fixed (CORINFO_EH_CLAUSE* clausePtr = &clause) - mc.repGetEHinfo(ftn, EHnumber, clausePtr); + mc.repGetEHinfo(ftn, EHnumber, ref clause); } private CORINFO_CLASS_STRUCT_* getMethodClass(CORINFO_METHOD_STRUCT_* method) @@ -191,10 +190,7 @@ private void getEHinfo(CORINFO_METHOD_STRUCT_* ftn, uint EHnumber, ref CORINFO_E private void getMethodVTableOffset(CORINFO_METHOD_STRUCT_* method, ref uint offsetOfIndirection, ref uint offsetAfterIndirection, ref bool isRelative) { AddCall("getMethodVTableOffset"); - fixed (uint* offsetOfIndirectionPtr = &offsetOfIndirection) - fixed (uint* offsetAfterIndirectionPtr = &offsetAfterIndirection) - fixed (bool* isRelativePtr = &isRelative) - mc.repGetMethodVTableOffset(method, offsetOfIndirectionPtr, offsetAfterIndirectionPtr, isRelativePtr); + mc.repGetMethodVTableOffset(method, ref offsetOfIndirection, ref offsetAfterIndirection, ref isRelative); } private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) @@ -206,8 +202,7 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) private CORINFO_METHOD_STRUCT_* getAsyncOtherVariant(CORINFO_METHOD_STRUCT_* ftn, ref bool variantIsThunk) { AddCall("getAsyncOtherVariant"); - fixed (bool* variantIsThunkPtr = &variantIsThunk) - return mc.repGetAsyncOtherVariant(ftn, variantIsThunkPtr); + return mc.repGetAsyncOtherVariant(ftn, ref variantIsThunk); } private CORINFO_CLASS_STRUCT_* getDefaultComparerClass(CORINFO_CLASS_STRUCT_* elemType) @@ -231,9 +226,7 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) private void expandRawHandleIntrinsic(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_GENERICHANDLE_RESULT pResult) { AddCall("expandRawHandleIntrinsic"); - fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) - fixed (CORINFO_GENERICHANDLE_RESULT* pResultPtr = &pResult) - mc.repExpandRawHandleIntrinsic(pResolvedTokenPtr, callerHandle, pResultPtr); + mc.repExpandRawHandleIntrinsic(ref pResolvedToken, callerHandle, ref pResult); } private bool isIntrinsicType(CORINFO_CLASS_STRUCT_* classHnd) @@ -245,8 +238,7 @@ private bool isIntrinsicType(CORINFO_CLASS_STRUCT_* classHnd) private CorInfoCallConvExtension getUnmanagedCallConv(CORINFO_METHOD_STRUCT_* method, CORINFO_SIG_INFO* callSiteSig, ref bool pSuppressGCTransition) { AddCall("getUnmanagedCallConv"); - fixed (bool* pSuppressGCTransitionPtr = &pSuppressGCTransition) - return mc.repGetUnmanagedCallConv(method, callSiteSig, pSuppressGCTransitionPtr); + return mc.repGetUnmanagedCallConv(method, callSiteSig, ref pSuppressGCTransition); } private bool pInvokeMarshalingRequired(CORINFO_METHOD_STRUCT_* method, CORINFO_SIG_INFO* callSiteSig) @@ -277,16 +269,14 @@ private void setPatchpointInfo(PatchpointInfo* patchpointInfo) private PatchpointInfo* getOSRInfo(ref uint ilOffset) { AddCall("getOSRInfo"); - fixed (uint* ilOffsetPtr = &ilOffset) - return mc.repGetOSRInfo(ilOffsetPtr); + return mc.repGetOSRInfo(ref ilOffset); } private void resolveToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken) { AddCall("resolveToken"); uint exceptionCode; - fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) - mc.repResolveToken(pResolvedTokenPtr, out exceptionCode); + mc.repResolveToken(ref pResolvedToken, out exceptionCode); if (exceptionCode != 0) ThrowRecordedException(exceptionCode); } @@ -306,8 +296,7 @@ private void findCallSiteSig(CORINFO_MODULE_STRUCT_* module, uint methTOK, CORIN private CORINFO_CLASS_STRUCT_* getTokenTypeAsHandle(ref CORINFO_RESOLVED_TOKEN pResolvedToken) { AddCall("getTokenTypeAsHandle"); - fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) - return mc.repGetTokenTypeAsHandle(pResolvedTokenPtr); + return mc.repGetTokenTypeAsHandle(ref pResolvedToken); } private int getStringLiteral(CORINFO_MODULE_STRUCT_* module, uint metaTOK, char* buffer, int bufferSize, int startIndex) @@ -400,9 +389,7 @@ private void LongLifetimeFree(void* obj) private bool getIsClassInitedFlagAddress(CORINFO_CLASS_STRUCT_* cls, ref CORINFO_CONST_LOOKUP addr, ref int offset) { AddCall("getIsClassInitedFlagAddress"); - fixed (CORINFO_CONST_LOOKUP* addrPtr = &addr) - fixed (int* offsetPtr = &offset) - return mc.repGetIsClassInitedFlagAddress(cls, addrPtr, offsetPtr); + return mc.repGetIsClassInitedFlagAddress(cls, ref addr, ref offset); } private void* getClassThreadStaticDynamicInfo(CORINFO_CLASS_STRUCT_* clr) @@ -420,8 +407,7 @@ private bool getIsClassInitedFlagAddress(CORINFO_CLASS_STRUCT_* cls, ref CORINFO private bool getStaticBaseAddress(CORINFO_CLASS_STRUCT_* cls, bool isGc, ref CORINFO_CONST_LOOKUP addr) { AddCall("getStaticBaseAddress"); - fixed (CORINFO_CONST_LOOKUP* addrPtr = &addr) - return mc.repGetStaticBaseAddress(cls, isGc, addrPtr); + return mc.repGetStaticBaseAddress(cls, isGc, ref addr); } private uint getClassSize(CORINFO_CLASS_STRUCT_* cls) @@ -483,8 +469,7 @@ private CorInfoHelpFunc getNewHelper(CORINFO_CLASS_STRUCT_* classHandle, ref boo AddCall("getNewHelper"); CorInfoHelpFunc result; uint exceptionCode; - fixed (bool* pHasSideEffectsPtr = &pHasSideEffects) - result = mc.repGetNewHelper(classHandle, pHasSideEffectsPtr, out exceptionCode); + result = mc.repGetNewHelper(classHandle, ref pHasSideEffects, out exceptionCode); if (exceptionCode != 0) ThrowRecordedException(exceptionCode); return result; @@ -499,8 +484,7 @@ private CorInfoHelpFunc getNewArrHelper(CORINFO_CLASS_STRUCT_* arrayCls) private CorInfoHelpFunc getCastingHelper(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool fThrowing) { AddCall("getCastingHelper"); - fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) - return mc.repGetCastingHelper(pResolvedTokenPtr, fThrowing); + return mc.repGetCastingHelper(ref pResolvedToken, fThrowing); } private CorInfoHelpFunc getSharedCCtorHelper(CORINFO_CLASS_STRUCT_* clsHnd) @@ -554,18 +538,14 @@ private bool getStringChar(CORINFO_OBJECT_STRUCT_* strObj, int index, ushort* va private bool getReadyToRunHelper(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CorInfoHelpFunc id, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_CONST_LOOKUP pLookup) { AddCall("getReadyToRunHelper"); - fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) - fixed (CORINFO_CONST_LOOKUP* pLookupPtr = &pLookup) - return mc.repGetReadyToRunHelper(pResolvedTokenPtr, id, callerHandle, pLookupPtr); + return mc.repGetReadyToRunHelper(ref pResolvedToken, id, callerHandle, ref pLookup); } private void getReadyToRunDelegateCtorHelper(ref CORINFO_RESOLVED_TOKEN pTargetMethod, mdToken targetConstraint, CORINFO_CLASS_STRUCT_* delegateType, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_LOOKUP pLookup) { AddCall("getReadyToRunDelegateCtorHelper"); - fixed (CORINFO_RESOLVED_TOKEN* pTargetMethodPtr = &pTargetMethod) - fixed (CORINFO_LOOKUP* pLookupPtr = &pLookup) - mc.repGetReadyToRunDelegateCtorHelper(pTargetMethodPtr, targetConstraint, delegateType, callerHandle, pLookupPtr); + mc.repGetReadyToRunDelegateCtorHelper(ref pTargetMethod, targetConstraint, delegateType, callerHandle, ref pLookup); } private CorInfoInitClassResult initClass(CORINFO_FIELD_STRUCT_* field, CORINFO_METHOD_STRUCT_* method, CORINFO_CONTEXT_STRUCT* context) @@ -679,9 +659,7 @@ private CorInfoArrayIntrinsic getArrayIntrinsicID(CORINFO_METHOD_STRUCT_* ftn) private CorInfoIsAccessAllowedResult canAccessClass(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_HELPER_DESC pAccessHelper) { AddCall("canAccessClass"); - fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) - fixed (CORINFO_HELPER_DESC* pAccessHelperPtr = &pAccessHelper) - return mc.repCanAccessClass(pResolvedTokenPtr, callerHandle, pAccessHelperPtr); + return mc.repCanAccessClass(ref pResolvedToken, callerHandle, ref pAccessHelper); } private nuint printFieldName(CORINFO_FIELD_STRUCT_* field, byte* buffer, nuint bufferSize, nuint* pRequiredBufferSize) @@ -711,8 +689,7 @@ private uint getFieldOffset(CORINFO_FIELD_STRUCT_* field) private void getFieldInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult) { AddCall("getFieldInfo"); - fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) - mc.repGetFieldInfo(pResolvedTokenPtr, callerHandle, flags, pResult); + mc.repGetFieldInfo(ref pResolvedToken, callerHandle, flags, pResult); } private uint getThreadLocalFieldInfo(CORINFO_FIELD_STRUCT_* field, bool isGCtype) @@ -748,9 +725,7 @@ private int getArrayOrStringLength(CORINFO_OBJECT_STRUCT_* objHnd) private void getBoundaries(CORINFO_METHOD_STRUCT_* ftn, ref uint cILOffsets, ref uint* pILOffsets, BoundaryTypes* implicitBoundaries) { AddCall("getBoundaries"); - fixed (uint** ppILOffsets = &pILOffsets) - fixed (uint* cILOffsetsPtr = &cILOffsets) - mc.repGetBoundaries(ftn, cILOffsetsPtr, ppILOffsets, implicitBoundaries); + mc.repGetBoundaries(ftn, ref cILOffsets, ref pILOffsets, implicitBoundaries); // The JIT frees the array with freeArray, so move the data to memory that complies with that. if (cILOffsets > 0) @@ -776,9 +751,7 @@ private void setBoundaries(CORINFO_METHOD_STRUCT_* ftn, uint cMap, OffsetMapping private void getVars(CORINFO_METHOD_STRUCT_* ftn, ref uint cVars, ILVarInfo** vars, ref bool extendOthers) { AddCall("getVars"); - fixed (uint* cVarsPtr = &cVars) - fixed (bool* extendOthersPtr = &extendOthers) - mc.repGetVars(ftn, cVarsPtr, vars, extendOthersPtr); + mc.repGetVars(ftn, ref cVars, vars, ref extendOthers); // The JIT frees the array with freeArray, so move the data to memory that complies with that. if (cVars > 0) @@ -885,31 +858,26 @@ private CorInfoHFAElemType getHFAType(CORINFO_CLASS_STRUCT_* hClass) private void getEEInfo(ref CORINFO_EE_INFO pEEInfoOut) { AddCall("getEEInfo"); - fixed (CORINFO_EE_INFO* pEEInfoOutPtr = &pEEInfoOut) - mc.repGetEEInfo(pEEInfoOutPtr); + mc.repGetEEInfo(ref pEEInfoOut); } private void getAsyncInfo(ref CORINFO_ASYNC_INFO pAsyncInfoOut) { AddCall("getAsyncInfo"); - fixed (CORINFO_ASYNC_INFO* pAsyncInfoOutPtr = &pAsyncInfoOut) - mc.repGetAsyncInfo(pAsyncInfoOutPtr); + mc.repGetAsyncInfo(ref pAsyncInfoOut); } private CORINFO_METHOD_STRUCT_* getAwaitReturnCall(CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_CONTEXT_STRUCT** contextHandle, ref CORINFO_LOOKUP instArg) { AddCall("getAwaitReturnCall"); - fixed (CORINFO_LOOKUP* instArgPtr = &instArg) - return mc.repGetAwaitReturnCall(callerHandle, contextHandle, instArgPtr); + return mc.repGetAwaitReturnCall(callerHandle, contextHandle, ref instArg); } private CORINFO_METHOD_STRUCT_* getAwaitAwaiterInContinuationCall(CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool isUnsafe, CORINFO_CONTEXT_STRUCT** contextHandle, ref CORINFO_LOOKUP instArg) { AddCall("getAwaitAwaiterInContinuationCall"); - fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) - fixed (CORINFO_LOOKUP* instArgPtr = &instArg) - return mc.repGetAwaitAwaiterInContinuationCall(callerHandle, pResolvedTokenPtr, isUnsafe, contextHandle, instArgPtr); + return mc.repGetAwaitAwaiterInContinuationCall(callerHandle, ref pResolvedToken, isUnsafe, contextHandle, ref instArg); } private mdToken getMethodDefFromMethod(CORINFO_METHOD_STRUCT_* hMethod) @@ -945,15 +913,13 @@ private bool getSystemVAmd64PassStructInRegisterDescriptor(CORINFO_CLASS_STRUCT_ private void getSwiftLowering(CORINFO_CLASS_STRUCT_* structHnd, ref CORINFO_SWIFT_LOWERING pLowering) { AddCall("getSwiftLowering"); - fixed (CORINFO_SWIFT_LOWERING* pLoweringPtr = &pLowering) - mc.repGetSwiftLowering(structHnd, pLoweringPtr); + mc.repGetSwiftLowering(structHnd, ref pLowering); } private void getFpStructLowering(CORINFO_CLASS_STRUCT_* structHnd, ref CORINFO_FPSTRUCT_LOWERING pLowering) { AddCall("getFpStructLowering"); - fixed (CORINFO_FPSTRUCT_LOWERING* pLoweringPtr = &pLowering) - mc.repGetFpStructLowering(structHnd, pLoweringPtr); + mc.repGetFpStructLowering(structHnd, ref pLowering); } private CorInfoWasmType getWasmLowering(CORINFO_CLASS_STRUCT_* structHnd) @@ -971,22 +937,19 @@ private uint getAddressAlignment(void* address) private void getWasmWellKnownGlobals(ref CORINFO_WASM_WELLKNOWN_GLOBALS pWellKnownGlobalsOut) { AddCall("getWasmWellKnownGlobals"); - fixed (CORINFO_WASM_WELLKNOWN_GLOBALS* pWellKnownGlobalsOutPtr = &pWellKnownGlobalsOut) - mc.repGetWasmWellKnownGlobals(pWellKnownGlobalsOutPtr); + mc.repGetWasmWellKnownGlobals(ref pWellKnownGlobalsOut); } private uint getThreadTLSIndex(ref void* ppIndirection) { AddCall("getThreadTLSIndex"); - fixed (void** p = &ppIndirection) - return mc.repGetThreadTLSIndex(p); + return mc.repGetThreadTLSIndex(ref ppIndirection); } private int* getAddrOfCaptureThreadGlobal(ref void* ppIndirection) { AddCall("getAddrOfCaptureThreadGlobal"); - fixed (void** p = &ppIndirection) - return mc.repGetAddrOfCaptureThreadGlobal(p); + return mc.repGetAddrOfCaptureThreadGlobal(ref ppIndirection); } private void getHelperFtn(CorInfoHelpFunc ftnNum, CORINFO_CONST_LOOKUP* pNativeEntrypoint, CORINFO_METHOD_STRUCT_** pMethod) @@ -998,65 +961,55 @@ private void getHelperFtn(CorInfoHelpFunc ftnNum, CORINFO_CONST_LOOKUP* pNativeE private void getFunctionEntryPoint(CORINFO_METHOD_STRUCT_* ftn, ref CORINFO_CONST_LOOKUP pResult, CORINFO_ACCESS_FLAGS accessFlags) { AddCall("getFunctionEntryPoint"); - fixed (CORINFO_CONST_LOOKUP* pResultPtr = &pResult) - mc.repGetFunctionEntryPoint(ftn, pResultPtr, accessFlags); + mc.repGetFunctionEntryPoint(ftn, ref pResult, accessFlags); } private void getFunctionFixedEntryPoint(CORINFO_METHOD_STRUCT_* ftn, bool isUnsafeFunctionPointer, ref CORINFO_CONST_LOOKUP pResult) { AddCall("getFunctionFixedEntryPoint"); - fixed (CORINFO_CONST_LOOKUP* pResultPtr = &pResult) - mc.repGetFunctionFixedEntryPoint(ftn, isUnsafeFunctionPointer, pResultPtr); + mc.repGetFunctionFixedEntryPoint(ftn, isUnsafeFunctionPointer, ref pResult); } private CORINFO_MODULE_STRUCT_* embedModuleHandle(CORINFO_MODULE_STRUCT_* handle, ref void* ppIndirection) { AddCall("embedModuleHandle"); - fixed (void** p = &ppIndirection) - return mc.repEmbedModuleHandle(handle, p); + return mc.repEmbedModuleHandle(handle, ref ppIndirection); } private CORINFO_CLASS_STRUCT_* embedClassHandle(CORINFO_CLASS_STRUCT_* handle, ref void* ppIndirection) { AddCall("embedClassHandle"); - fixed (void** p = &ppIndirection) - return mc.repEmbedClassHandle(handle, p); + return mc.repEmbedClassHandle(handle, ref ppIndirection); } private CORINFO_METHOD_STRUCT_* embedMethodHandle(CORINFO_METHOD_STRUCT_* handle, ref void* ppIndirection) { AddCall("embedMethodHandle"); - fixed (void** p = &ppIndirection) - return mc.repEmbedMethodHandle(handle, p); + return mc.repEmbedMethodHandle(handle, ref ppIndirection); } private CORINFO_FIELD_STRUCT_* embedFieldHandle(CORINFO_FIELD_STRUCT_* handle, ref void* ppIndirection) { AddCall("embedFieldHandle"); - fixed (void** p = &ppIndirection) - return mc.repEmbedFieldHandle(handle, p); + return mc.repEmbedFieldHandle(handle, ref ppIndirection); } private void embedGenericHandle(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool fEmbedParent, CORINFO_METHOD_STRUCT_* callerHandle, ref CORINFO_GENERICHANDLE_RESULT pResult) { AddCall("embedGenericHandle"); - fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) - fixed (CORINFO_GENERICHANDLE_RESULT* pResultPtr = &pResult) - mc.repEmbedGenericHandle(pResolvedTokenPtr, fEmbedParent, callerHandle, pResultPtr); + mc.repEmbedGenericHandle(ref pResolvedToken, fEmbedParent, callerHandle, ref pResult); } private void getLocationOfThisType(CORINFO_METHOD_STRUCT_* context, ref CORINFO_LOOKUP_KIND pLookupKind) { AddCall("getLocationOfThisType"); - fixed (CORINFO_LOOKUP_KIND* pLookupKindPtr = &pLookupKind) - mc.repGetLocationOfThisType(context, pLookupKindPtr); + mc.repGetLocationOfThisType(context, ref pLookupKind); } private void getAddressOfPInvokeTarget(CORINFO_METHOD_STRUCT_* method, ref CORINFO_CONST_LOOKUP pLookup) { AddCall("getAddressOfPInvokeTarget"); - fixed (CORINFO_CONST_LOOKUP* pLookupPtr = &pLookup) - mc.repGetAddressOfPInvokeTarget(method, pLookupPtr); + mc.repGetAddressOfPInvokeTarget(method, ref pLookup); } private void* GetCookieForInterpreterCalliSig(CORINFO_SIG_INFO* szMetaSig) @@ -1068,17 +1021,13 @@ private void getAddressOfPInvokeTarget(CORINFO_METHOD_STRUCT_* method, ref CORIN private CORINFO_JUST_MY_CODE_HANDLE_* getJustMyCodeHandle(CORINFO_METHOD_STRUCT_* method, ref CORINFO_JUST_MY_CODE_HANDLE_* ppIndirection) { AddCall("getJustMyCodeHandle"); - fixed (CORINFO_JUST_MY_CODE_HANDLE_** p = &ppIndirection) - return mc.repGetJustMyCodeHandle(method, p); + return mc.repGetJustMyCodeHandle(method, ref ppIndirection); } private void GetProfilingHandle(ref bool pbHookFunction, ref void* pProfilerHandle, ref bool pbIndirectedHandles) { AddCall("GetProfilingHandle"); - fixed (void** p = &pProfilerHandle) - fixed (bool* pbHookFunctionPtr = &pbHookFunction) - fixed (bool* pbIndirectedHandlesPtr = &pbIndirectedHandles) - mc.repGetProfilingHandle(pbHookFunctionPtr, p, pbIndirectedHandlesPtr); + mc.repGetProfilingHandle(ref pbHookFunction, ref pProfilerHandle, ref pbIndirectedHandles); } private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, @@ -1086,8 +1035,7 @@ private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESO { AddCall("getCallInfo"); uint exceptionCode; - fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) - mc.repGetCallInfo(pResolvedTokenPtr, pConstrainedResolvedToken, callerHandle, flags, pResult, out exceptionCode); + mc.repGetCallInfo(ref pResolvedToken, pConstrainedResolvedToken, callerHandle, flags, pResult, out exceptionCode); if (exceptionCode != 0) ThrowRecordedException(exceptionCode); } @@ -1113,36 +1061,31 @@ private bool getObjectContent(CORINFO_OBJECT_STRUCT_* obj, byte* buffer, int buf private IntPtr getVarArgsHandle(CORINFO_SIG_INFO* pSig, CORINFO_METHOD_STRUCT_* methHnd, ref void* ppIndirection) { AddCall("getVarArgsHandle"); - fixed (void** p = &ppIndirection) - return mc.repGetVarArgsHandle(pSig, methHnd, p); + return mc.repGetVarArgsHandle(pSig, methHnd, ref ppIndirection); } private InfoAccessType constructStringLiteral(CORINFO_MODULE_STRUCT_* module, mdToken metaTok, ref void* ppValue) { AddCall("constructStringLiteral"); - fixed (void** p = &ppValue) - return mc.repConstructStringLiteral(module, metaTok, p); + return mc.repConstructStringLiteral(module, metaTok, ref ppValue); } private InfoAccessType emptyStringLiteral(ref void* ppValue) { AddCall("emptyStringLiteral"); - fixed (void** p = &ppValue) - return mc.repEmptyStringLiteral(p); + return mc.repEmptyStringLiteral(ref ppValue); } private uint getFieldThreadLocalStoreID(CORINFO_FIELD_STRUCT_* field, ref void* ppIndirection) { AddCall("getFieldThreadLocalStoreID"); - fixed (void** p = &ppIndirection) - return mc.repGetFieldThreadLocalStoreID(field, p); + return mc.repGetFieldThreadLocalStoreID(field, ref ppIndirection); } private CORINFO_METHOD_STRUCT_* GetDelegateCtor(CORINFO_METHOD_STRUCT_* methHnd, CORINFO_CLASS_STRUCT_* clsHnd, CORINFO_METHOD_STRUCT_* targetMethodHnd, ref DelegateCtorArgs pCtorData) { AddCall("GetDelegateCtor"); - fixed (DelegateCtorArgs* pCtorDataPtr = &pCtorData) - return mc.repGetDelegateCtor(methHnd, clsHnd, targetMethodHnd, pCtorDataPtr); + return mc.repGetDelegateCtor(methHnd, clsHnd, targetMethodHnd, ref pCtorData); } private void MethodCompileComplete(CORINFO_METHOD_STRUCT_* methHnd) @@ -1155,30 +1098,25 @@ private void MethodCompileComplete(CORINFO_METHOD_STRUCT_* methHnd) private bool getTailCallHelpers(ref CORINFO_RESOLVED_TOKEN callToken, CORINFO_SIG_INFO* sig, CORINFO_GET_TAILCALL_HELPERS_FLAGS flags, ref CORINFO_TAILCALL_HELPERS pResult) { AddCall("getTailCallHelpers"); - fixed (CORINFO_RESOLVED_TOKEN* callTokenPtr = &callToken) - fixed (CORINFO_TAILCALL_HELPERS* pResultPtr = &pResult) - return mc.repGetTailCallHelpers(callTokenPtr, sig, flags, pResultPtr); + return mc.repGetTailCallHelpers(ref callToken, sig, flags, ref pResult); } private CORINFO_CLASS_STRUCT_* getContinuationType(nuint dataSize, ref bool objRefs, nuint objRefsSize) { AddCall("getContinuationType"); - fixed (bool* objRefsPtr = &objRefs) - return mc.repGetContinuationType(dataSize, objRefsPtr, objRefsSize); + return mc.repGetContinuationType(dataSize, ref objRefs, objRefsSize); } private CORINFO_METHOD_STRUCT_* getAsyncResumptionStub(ref void* entryPoint) { AddCall("getAsyncResumptionStub"); - fixed (void** p = &entryPoint) - return mc.repGetAsyncResumptionStub(p); + return mc.repGetAsyncResumptionStub(ref entryPoint); } private bool convertPInvokeCalliToCall(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool mustConvert) { AddCall("convertPInvokeCalliToCall"); - fixed (CORINFO_RESOLVED_TOKEN* pResolvedTokenPtr = &pResolvedToken) - return mc.repConvertPInvokeCalliToCall(pResolvedTokenPtr, mustConvert); + return mc.repConvertPInvokeCalliToCall(ref pResolvedToken, mustConvert); } private bool notifyInstructionSetUsage(InstructionSet instructionSet, bool supportEnabled, bool preserveNegativeDependency) @@ -1190,8 +1128,7 @@ private bool notifyInstructionSetUsage(InstructionSet instructionSet, bool suppo private void updateEntryPointForTailCall(ref CORINFO_CONST_LOOKUP entryPoint) { AddCall("updateEntryPointForTailCall"); - fixed (CORINFO_CONST_LOOKUP* entryPointPtr = &entryPoint) - mc.repUpdateEntryPointForTailCall(entryPointPtr); + mc.repUpdateEntryPointForTailCall(ref entryPoint); } // Allocates the code and data blocks: the hot code aligned as requested, and all the RO data in one block. @@ -1276,8 +1213,7 @@ private void setEHcount(uint cEH) private void setEHinfo(uint EHnumber, ref CORINFO_EH_CLAUSE clause) { AddCall("setEHinfo"); - fixed (CORINFO_EH_CLAUSE* clausePtr = &clause) - cr.recSetEHinfo(EHnumber, clausePtr); + cr.recSetEHinfo(EHnumber, ref clause); } private bool logMsg(uint level, byte* fmt, IntPtr args) @@ -1318,11 +1254,7 @@ private HRESULT getPgoInstrumentationResults(CORINFO_METHOD_STRUCT_* ftnHnd, ref byte** pInstrumentationData, ref PgoSource pPgoSource, ref bool pDynamicPgo) { AddCall("getPgoInstrumentationResults"); - fixed (PgoInstrumentationSchema** ppSchema = &pSchema) - fixed (uint* pCountSchemaItemsPtr = &pCountSchemaItems) - fixed (PgoSource* pPgoSourcePtr = &pPgoSource) - fixed (bool* pDynamicPgoPtr = &pDynamicPgo) - return mc.repGetPgoInstrumentationResults(ftnHnd, ppSchema, pCountSchemaItemsPtr, pInstrumentationData, pPgoSourcePtr, pDynamicPgoPtr); + return mc.repGetPgoInstrumentationResults(ftnHnd, ref pSchema, ref pCountSchemaItems, pInstrumentationData, ref pPgoSource, ref pDynamicPgo); } private HRESULT allocPgoInstrumentationBySchema(CORINFO_METHOD_STRUCT_* ftnHnd, PgoInstrumentationSchema* pSchema, uint countSchemaItems, byte** pInstrumentationData) @@ -1364,8 +1296,7 @@ private uint getExpectedTargetArchitecture() private uint getJitFlags(ref CORJIT_FLAGS flags, uint sizeInBytes) { AddCall("getJitFlags"); - fixed (CORJIT_FLAGS* flagsPtr = &flags) - return jitInstance.getJitFlags(flagsPtr, sizeInBytes); + return jitInstance.getJitFlags(ref flags, sizeInBytes); } private CORINFO_WASM_TYPE_SYMBOL_STRUCT_* getWasmTypeSymbol(CorInfoWasmType* types, nuint typesSize) diff --git a/src/coreclr/tools/superpmi/managed/superpmi/JitInstance.cs b/src/coreclr/tools/superpmi/managed/superpmi/JitInstance.cs index 596ad7bf776c6e..75f58d0ef0328f 100644 --- a/src/coreclr/tools/superpmi/managed/superpmi/JitInstance.cs +++ b/src/coreclr/tools/superpmi/managed/superpmi/JitInstance.cs @@ -187,7 +187,7 @@ public ReplayResults CompileMethod(MethodContext methodToCompile, int mcIndex, b mc.repCompileMethod(&info, &flags, &os); CORJIT_FLAGS jitFlags = default; - getJitFlags(&jitFlags, (uint)sizeof(CORJIT_FLAGS)); + getJitFlags(ref jitFlags, (uint)sizeof(CORJIT_FLAGS)); results.IsMinOpts = jitFlags.IsSet(CorJitFlag.CORJIT_FLAG_DEBUG_CODE) || jitFlags.IsSet(CorJitFlag.CORJIT_FLAG_MIN_OPT) || jitFlags.IsSet(CorJitFlag.CORJIT_FLAG_TIER0); @@ -335,13 +335,13 @@ private static string getOption(string key, LightWeightMap options) } // The JIT flags of the compilation, adjusted for altjit. This doesn't record the call in the compile result. - public uint getJitFlags(CORJIT_FLAGS* jitFlags, uint sizeInBytes) + public uint getJitFlags(ref CORJIT_FLAGS jitFlags, uint sizeInBytes) { - uint ret = mc.repGetJitFlags(jitFlags, sizeInBytes); + uint ret = mc.repGetJitFlags(ref jitFlags, sizeInBytes); if (forceClearAltJitFlag) - jitFlags->Clear(CorJitFlag.CORJIT_FLAG_ALT_JIT); + jitFlags.Clear(CorJitFlag.CORJIT_FLAG_ALT_JIT); else if (forceSetAltJitFlag) - jitFlags->Set(CorJitFlag.CORJIT_FLAG_ALT_JIT); + jitFlags.Set(CorJitFlag.CORJIT_FLAG_ALT_JIT); return ret; } From a58918da3d02808bd3fdf39abf99107b74ae48a7 Mon Sep 17 00:00:00 2001 From: am11 <3840695+am11@users.noreply.github.com> Date: Tue, 10 Nov 2026 16:54:40 +0200 Subject: [PATCH 10/10] Link the SuperPMI tools with the C++ standard library that the native side is built against Co-authored-by: Cursor --- .../tools/superpmi/managed/Directory.Build.targets | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/coreclr/tools/superpmi/managed/Directory.Build.targets b/src/coreclr/tools/superpmi/managed/Directory.Build.targets index 75f920c42b0b88..242540298c08de 100644 --- a/src/coreclr/tools/superpmi/managed/Directory.Build.targets +++ b/src/coreclr/tools/superpmi/managed/Directory.Build.targets @@ -5,6 +5,14 @@ + + + + + +