From 679d2d73c6ca3d94ce1ef791454a1b25ef011229 Mon Sep 17 00:00:00 2001 From: kohanis Date: Thu, 7 Mar 2024 14:39:19 +0300 Subject: [PATCH 1/4] .gitignore update --- .gitignore | 351 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 320 insertions(+), 31 deletions(-) diff --git a/.gitignore b/.gitignore index 84b8305d..6f806069 100644 --- a/.gitignore +++ b/.gitignore @@ -1,49 +1,99 @@ +/Harmony/Harmony.zip +# Build results +/Harmony/build +# Documentation +/Harmony/Documentation/api/.manifest +/Harmony/Documentation/api/*.html +/Harmony/Documentation/api/*.yml +/Harmony/Documentation/Documentation.dll + ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. +## +## Get latest from `dotnet new gitignore` + +# dotenv files +.env + # User-specific files +*.rsuser *.suo *.user *.userosscache *.sln.docstates + # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs + +# Mono auto generated files +mono_crash.* + # Build results -/Harmony/build [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ -[Xx]64/ -[Xx]86/ -[Bb]uild/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ bld/ [Bb]in/ [Oo]bj/ -# Visual Studio 2015 cache/options directory +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* -# NUNIT + +# NUnit *.VisualState.xml TestResult.xml +nunit-*.xml + # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ dlldata.c -# DNX + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET project.lock.json +project.fragment.lock.json artifacts/ + +# Tye +.tye/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio *_i.c *_p.c -*_i.h +*_h.h *.ilk *.meta *.obj +*.iobj *.pch *.pdb +*.ipdb *.pgc *.pgd *.rsp @@ -53,15 +103,19 @@ artifacts/ *.tlh *.tmp *.tmp_proj +*_wpftmp.csproj *.log +*.tlog *.vspscc *.vssscc .builds *.pidb *.svclog *.scc + # Chutzpah Test files _Chutzpah* + # Visual C++ cache files ipch/ *.aps @@ -71,36 +125,62 @@ ipch/ *.sdf *.cachefile *.VC.db +*.VC.VC.opendb + # Visual Studio profiler *.psess *.vsp *.vspx *.sap + +# Visual Studio Trace Files +*.e2e + # TFS 2012 Local Workspace $tf/ + # Guidance Automation Toolkit *.gpState + # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user -# JustCode is a .NET coding add-in -.JustCode + # TeamCity is a build add-in _TeamCity* + # DotCover is a Code Coverage Tool *.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + # NCrunch _NCrunch_* .*crunch*.local.xml nCrunchTemp_* + # MightyMoose *.mm.* AutoTest.Net/ + # Web workbench (sass) .sass-cache/ + # Installshield output folder [Ee]xpress/ + # DocProject is a documentation generator add-in DocProject/buildhelp/ DocProject/Help/*.HxT @@ -110,54 +190,82 @@ DocProject/Help/*.hhk DocProject/Help/*.hhp DocProject/Help/Html2 DocProject/Help/html + # Click-Once directory publish/ + # Publish Web Output *.[Pp]ublish.xml *.azurePubxml -# TODO: Un-comment the next line if you do not want to checkin -# your web deploy settings because they may include unencrypted -# passwords -#*.pubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml *.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + # NuGet Packages *.nupkg +# NuGet Symbol Packages +*.snupkg # The packages folder can be ignored because of Package Restore -**/packages/* +**/[Pp]ackages/* # except build/, which is used as an MSBuild target. -!**/packages/build/ +!**/[Pp]ackages/build/ # Uncomment if necessary however generally it will be regenerated when needed -#!**/packages/repositories.config -# NuGet v3's project.json files produces more ignoreable files +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files *.nuget.props *.nuget.targets + # Microsoft Azure Build Output csx/ *.build.csdef + # Microsoft Azure Emulator ecf/ rcf/ -# Windows Store app package directory + +# Windows Store app package directories and files AppPackages/ BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache -!*.[Cc]ache/ +!?*.[Cc]ache/ + # Others ClientBin/ -[Ss]tyle[Cc]op.* ~$* *~ *.dbmdl *.dbproj.schemaview +*.jfm *.pfx *.publishsettings -node_modules/ orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + # RIA/Silverlight projects Generated_Code/ + # Backup & report files from converting an old project file # to a newer Visual Studio version. Backup files are not needed, # because we have git ;-) @@ -165,23 +273,53 @@ _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + # SQL Server files *.mdf *.ldf +*.ndf + # Business Intelligence projects *.rdl.data *.bim.layout *.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + # Microsoft Fakes FakesAssemblies/ + # GhostDoc plugin setting file *.GhostDoc.xml + # Node.js Tools for Visual Studio .ntvs_analysis.dat +node_modules/ + # Visual Studio 6 build log *.plg + # Visual Studio 6 workspace options file *.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + # Visual Studio LightSwitch build output **/*.HTMLClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts @@ -189,16 +327,167 @@ FakesAssemblies/ **/*.Server/GeneratedArtifacts **/*.Server/ModelManifest.xml _Pvt_Extensions -# LightSwitch generated files -GeneratedArtifacts/ -ModelManifest.xml + # Paket dependency manager .paket/paket.exe +paket-files/ + # FAKE - F# Make .fake/ -/Harmony/Harmony.zip -# Documentation -/Harmony/Documentation/api/.manifest -/Harmony/Documentation/api/*.html -/Harmony/Documentation/api/*.yml -/Harmony/Documentation/Documentation.dll + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +tools/** +!tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml +.idea + +## +## Visual studio for Mac +## + + +# globs +Makefile.in +*.userprefs +*.usertasks +config.make +config.status +aclocal.m4 +install-sh +autom4te.cache/ +*.tar.gz +tarballs/ +test-results/ + +# Mac bundle stuff +*.dmg +*.app + +# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# Vim temporary swap files +*.swp From 8cb43cb73f7cf377696734b54b28da18d1f94fad Mon Sep 17 00:00:00 2001 From: kohanis Date: Thu, 7 Mar 2024 14:39:29 +0300 Subject: [PATCH 2/4] GetMethodFromStackframe fix --- Harmony/Internal/HarmonySharedState.cs | 6 +++- Harmony/Public/Harmony.cs | 5 +-- HarmonyTests/Extras/RetrieveOriginalMethod.cs | 32 +++++++++---------- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/Harmony/Internal/HarmonySharedState.cs b/Harmony/Internal/HarmonySharedState.cs index 170701f8..c44f9bd4 100644 --- a/Harmony/Internal/HarmonySharedState.cs +++ b/Harmony/Internal/HarmonySharedState.cs @@ -1,4 +1,5 @@ using Mono.Cecil; +using MonoMod.Core.Platforms; using MonoMod.Utils; using System; using System.Collections.Generic; @@ -127,7 +128,10 @@ internal static void UpdatePatchInfo(MethodBase original, MethodInfo replacement internal static MethodBase GetOriginal(MethodInfo replacement) { - lock (originals) return originals.GetValueSafe(replacement); + // The runtime can return several different MethodInfo's that point to the same method. Use the correct one + replacement = PlatformTriple.Current.GetIdentifiable(replacement) as MethodInfo; + lock (originals) + return originals.GetValueSafe(replacement); } internal static MethodBase FindReplacement(StackFrame frame) diff --git a/Harmony/Public/Harmony.cs b/Harmony/Public/Harmony.cs index 65b8e9ed..33739306 100644 --- a/Harmony/Public/Harmony.cs +++ b/Harmony/Public/Harmony.cs @@ -1,4 +1,3 @@ -using MonoMod.Core.Platforms; using System; using System.Collections.Generic; using System.Diagnostics; @@ -258,9 +257,7 @@ public IEnumerable GetPatchedMethods() public static MethodBase GetOriginalMethod(MethodInfo replacement) { if (replacement == null) throw new ArgumentNullException(nameof(replacement)); - // The runtime can return several different MethodInfo's that point to the same method. Use the correct one - var identifiableReplacement = PlatformTriple.Current.GetIdentifiable(replacement) as MethodInfo; - return HarmonySharedState.GetOriginal(identifiableReplacement); + return HarmonySharedState.GetOriginal(replacement); } /// Tries to get the method from a stackframe including dynamic replacement methods diff --git a/HarmonyTests/Extras/RetrieveOriginalMethod.cs b/HarmonyTests/Extras/RetrieveOriginalMethod.cs index e2769269..5554b4a3 100644 --- a/HarmonyTests/Extras/RetrieveOriginalMethod.cs +++ b/HarmonyTests/Extras/RetrieveOriginalMethod.cs @@ -3,6 +3,7 @@ using System; using System.Diagnostics; using System.Reflection; +using System.Runtime.CompilerServices; namespace HarmonyLibTests.Extras { @@ -14,20 +15,20 @@ private static void CheckStackTraceFor(MethodBase expectedMethod) Assert.NotNull(expectedMethod); var st = new StackTrace(1, false); - var method = Harmony.GetMethodFromStackframe(st.GetFrame(0)); - - Assert.NotNull(method); - - if (method is MethodInfo replacement) - { - var original = Harmony.GetOriginalMethod(replacement); - Assert.NotNull(original); - Assert.AreEqual(original, expectedMethod); - } + var frame = st.GetFrame(0); + Assert.NotNull(frame); + + var methodFromStackframe = Harmony.GetMethodFromStackframe(frame); + Assert.NotNull(methodFromStackframe); + Assert.AreEqual(expectedMethod, methodFromStackframe); + + var replacement = frame.GetMethod() as MethodInfo; + Assert.NotNull(replacement); + var original = Harmony.GetOriginalMethod(replacement); + Assert.NotNull(original); + Assert.AreEqual(expectedMethod, original); } - /* TODO - * [Test] public void TestRegularMethod() { @@ -37,7 +38,7 @@ public void TestRegularMethod() _ = harmony.Patch(originalMethod, new HarmonyMethod(dummyPrefix)); PatchTarget(); } - + [Test] public void TestConstructor() { @@ -48,7 +49,6 @@ public void TestConstructor() var inst = new NestedClass(5); _ = inst.index; } - */ internal static void PatchTarget() { @@ -60,7 +60,7 @@ internal static void PatchTarget() } } - // [MethodImpl(MethodImplOptions.NoInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] internal static void DummyPrefix() { } @@ -69,7 +69,7 @@ class NestedClass { public NestedClass(int i) { try { - CheckStackTraceFor(AccessTools.Constructor(typeof(NestedClass), [typeof(int)])); + CheckStackTraceFor(AccessTools.Constructor(typeof(NestedClass), [typeof(int)])); throw new Exception(); } catch (Exception e) { From c7537ceac72c82d0da501894a506b2ac817f970c Mon Sep 17 00:00:00 2001 From: Andreas Pardeike Date: Tue, 19 Mar 2024 21:45:12 +0100 Subject: [PATCH 3/4] Revert ".gitignore update" This reverts commit 679d2d73c6ca3d94ce1ef791454a1b25ef011229. --- .gitignore | 351 +++++------------------------------------------------ 1 file changed, 31 insertions(+), 320 deletions(-) diff --git a/.gitignore b/.gitignore index 6f806069..84b8305d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,99 +1,49 @@ -/Harmony/Harmony.zip -# Build results -/Harmony/build -# Documentation -/Harmony/Documentation/api/.manifest -/Harmony/Documentation/api/*.html -/Harmony/Documentation/api/*.yml -/Harmony/Documentation/Documentation.dll - ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. -## -## Get latest from `dotnet new gitignore` - -# dotenv files -.env - # User-specific files -*.rsuser *.suo *.user *.userosscache *.sln.docstates - # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs - -# Mono auto generated files -mono_crash.* - # Build results +/Harmony/build [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ -x64/ -x86/ -[Ww][Ii][Nn]32/ -[Aa][Rr][Mm]/ -[Aa][Rr][Mm]64/ +[Xx]64/ +[Xx]86/ +[Bb]uild/ bld/ [Bb]in/ [Oo]bj/ -[Ll]og/ -[Ll]ogs/ - -# Visual Studio 2015/2017 cache/options directory +# Visual Studio 2015 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ - -# Visual Studio 2017 auto generated files -Generated\ Files/ - # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* - -# NUnit +# NUNIT *.VisualState.xml TestResult.xml -nunit-*.xml - # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ dlldata.c - -# Benchmark Results -BenchmarkDotNet.Artifacts/ - -# .NET +# DNX project.lock.json -project.fragment.lock.json artifacts/ - -# Tye -.tye/ - -# ASP.NET Scaffolding -ScaffoldingReadMe.txt - -# StyleCop -StyleCopReport.xml - -# Files built by Visual Studio *_i.c *_p.c -*_h.h +*_i.h *.ilk *.meta *.obj -*.iobj *.pch *.pdb -*.ipdb *.pgc *.pgd *.rsp @@ -103,19 +53,15 @@ StyleCopReport.xml *.tlh *.tmp *.tmp_proj -*_wpftmp.csproj *.log -*.tlog *.vspscc *.vssscc .builds *.pidb *.svclog *.scc - # Chutzpah Test files _Chutzpah* - # Visual C++ cache files ipch/ *.aps @@ -125,62 +71,36 @@ ipch/ *.sdf *.cachefile *.VC.db -*.VC.VC.opendb - # Visual Studio profiler *.psess *.vsp *.vspx *.sap - -# Visual Studio Trace Files -*.e2e - # TFS 2012 Local Workspace $tf/ - # Guidance Automation Toolkit *.gpState - # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user - +# JustCode is a .NET coding add-in +.JustCode # TeamCity is a build add-in _TeamCity* - # DotCover is a Code Coverage Tool *.dotCover - -# AxoCover is a Code Coverage Tool -.axoCover/* -!.axoCover/settings.json - -# Coverlet is a free, cross platform Code Coverage Tool -coverage*.json -coverage*.xml -coverage*.info - -# Visual Studio code coverage results -*.coverage -*.coveragexml - # NCrunch _NCrunch_* .*crunch*.local.xml nCrunchTemp_* - # MightyMoose *.mm.* AutoTest.Net/ - # Web workbench (sass) .sass-cache/ - # Installshield output folder [Ee]xpress/ - # DocProject is a documentation generator add-in DocProject/buildhelp/ DocProject/Help/*.HxT @@ -190,82 +110,54 @@ DocProject/Help/*.hhk DocProject/Help/*.hhp DocProject/Help/Html2 DocProject/Help/html - # Click-Once directory publish/ - # Publish Web Output *.[Pp]ublish.xml *.azurePubxml -# Note: Comment the next line if you want to checkin your web deploy settings, -# but database connection strings (with potential passwords) will be unencrypted -*.pubxml +# TODO: Un-comment the next line if you do not want to checkin +# your web deploy settings because they may include unencrypted +# passwords +#*.pubxml *.publishproj - -# Microsoft Azure Web App publish settings. Comment the next line if you want to -# checkin your Azure Web App publish settings, but sensitive information contained -# in these scripts will be unencrypted -PublishScripts/ - # NuGet Packages *.nupkg -# NuGet Symbol Packages -*.snupkg # The packages folder can be ignored because of Package Restore -**/[Pp]ackages/* +**/packages/* # except build/, which is used as an MSBuild target. -!**/[Pp]ackages/build/ +!**/packages/build/ # Uncomment if necessary however generally it will be regenerated when needed -#!**/[Pp]ackages/repositories.config -# NuGet v3's project.json files produces more ignorable files +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files *.nuget.props *.nuget.targets - # Microsoft Azure Build Output csx/ *.build.csdef - # Microsoft Azure Emulator ecf/ rcf/ - -# Windows Store app package directories and files +# Windows Store app package directory AppPackages/ BundleArtifacts/ -Package.StoreAssociation.xml -_pkginfo.txt -*.appx -*.appxbundle -*.appxupload - # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache -!?*.[Cc]ache/ - +!*.[Cc]ache/ # Others ClientBin/ +[Ss]tyle[Cc]op.* ~$* *~ *.dbmdl *.dbproj.schemaview -*.jfm *.pfx *.publishsettings +node_modules/ orleans.codegen.cs - -# Including strong name files can present a security risk -# (https://github.com/github/gitignore/pull/2483#issue-259490424) -#*.snk - -# Since there are multiple workflows, uncomment next line to ignore bower_components -# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) -#bower_components/ - # RIA/Silverlight projects Generated_Code/ - # Backup & report files from converting an old project file # to a newer Visual Studio version. Backup files are not needed, # because we have git ;-) @@ -273,53 +165,23 @@ _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm -ServiceFabricBackup/ -*.rptproj.bak - # SQL Server files *.mdf *.ldf -*.ndf - # Business Intelligence projects *.rdl.data *.bim.layout *.bim_*.settings -*.rptproj.rsuser -*- [Bb]ackup.rdl -*- [Bb]ackup ([0-9]).rdl -*- [Bb]ackup ([0-9][0-9]).rdl - # Microsoft Fakes FakesAssemblies/ - # GhostDoc plugin setting file *.GhostDoc.xml - # Node.js Tools for Visual Studio .ntvs_analysis.dat -node_modules/ - # Visual Studio 6 build log *.plg - # Visual Studio 6 workspace options file *.opt - -# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) -*.vbw - -# Visual Studio 6 auto-generated project file (contains which files were open etc.) -*.vbp - -# Visual Studio 6 workspace and project file (working project files containing files to include in project) -*.dsw -*.dsp - -# Visual Studio 6 technical files -*.ncb -*.aps - # Visual Studio LightSwitch build output **/*.HTMLClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts @@ -327,167 +189,16 @@ node_modules/ **/*.Server/GeneratedArtifacts **/*.Server/ModelManifest.xml _Pvt_Extensions - +# LightSwitch generated files +GeneratedArtifacts/ +ModelManifest.xml # Paket dependency manager .paket/paket.exe -paket-files/ - # FAKE - F# Make .fake/ - -# CodeRush personal settings -.cr/personal - -# Python Tools for Visual Studio (PTVS) -__pycache__/ -*.pyc - -# Cake - Uncomment if you are using it -tools/** -!tools/packages.config - -# Tabs Studio -*.tss - -# Telerik's JustMock configuration file -*.jmconfig - -# BizTalk build output -*.btp.cs -*.btm.cs -*.odx.cs -*.xsd.cs - -# OpenCover UI analysis results -OpenCover/ - -# Azure Stream Analytics local run output -ASALocalRun/ - -# MSBuild Binary and Structured Log -*.binlog - -# NVidia Nsight GPU debugger configuration file -*.nvuser - -# MFractors (Xamarin productivity tool) working folder -.mfractor/ - -# Local History for Visual Studio -.localhistory/ - -# Visual Studio History (VSHistory) files -.vshistory/ - -# BeatPulse healthcheck temp database -healthchecksdb - -# Backup folder for Package Reference Convert tool in Visual Studio 2017 -MigrationBackup/ - -# Ionide (cross platform F# VS Code tools) working folder -.ionide/ - -# Fody - auto-generated XML schema -FodyWeavers.xsd - -# VS Code files for those working on multiple tools -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json -*.code-workspace - -# Local History for Visual Studio Code -.history/ - -# Windows Installer files from build outputs -*.cab -*.msi -*.msix -*.msm -*.msp - -# JetBrains Rider -*.sln.iml -.idea - -## -## Visual studio for Mac -## - - -# globs -Makefile.in -*.userprefs -*.usertasks -config.make -config.status -aclocal.m4 -install-sh -autom4te.cache/ -*.tar.gz -tarballs/ -test-results/ - -# Mac bundle stuff -*.dmg -*.app - -# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore -# General -.DS_Store -.AppleDouble -.LSOverride - -# Icon must end with two \r -Icon - - -# Thumbnails -._* - -# Files that might appear in the root of a volume -.DocumentRevisions-V100 -.fseventsd -.Spotlight-V100 -.TemporaryItems -.Trashes -.VolumeIcon.icns -.com.apple.timemachine.donotpresent - -# Directories potentially created on remote AFP share -.AppleDB -.AppleDesktop -Network Trash Folder -Temporary Items -.apdisk - -# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore -# Windows thumbnail cache files -Thumbs.db -ehthumbs.db -ehthumbs_vista.db - -# Dump file -*.stackdump - -# Folder config file -[Dd]esktop.ini - -# Recycle Bin used on file shares -$RECYCLE.BIN/ - -# Windows Installer files -*.cab -*.msi -*.msix -*.msm -*.msp - -# Windows shortcuts -*.lnk - -# Vim temporary swap files -*.swp +/Harmony/Harmony.zip +# Documentation +/Harmony/Documentation/api/.manifest +/Harmony/Documentation/api/*.html +/Harmony/Documentation/api/*.yml +/Harmony/Documentation/Documentation.dll From 50600f18beab7559f4e77b71a1a9a8ee9a769d32 Mon Sep 17 00:00:00 2001 From: Andreas Pardeike Date: Fri, 22 Mar 2024 10:00:00 +0100 Subject: [PATCH 4/4] cleans up, refactors getting original methods [DebugFat breaking] --- Harmony/Internal/CodeTranspiler.cs | 2 +- Harmony/Internal/HarmonySharedState.cs | 71 ++++++++++++++++++++++---- Harmony/Internal/MethodCopier.cs | 2 +- Harmony/Internal/MethodPatcher.cs | 2 +- Harmony/Internal/PatchModels.cs | 2 +- Harmony/Internal/PatchTools.cs | 4 +- Harmony/Public/Harmony.cs | 17 +++--- Harmony/Public/HarmonyMethod.cs | 4 +- Harmony/Tools/AccessTools.cs | 8 ++- 9 files changed, 83 insertions(+), 29 deletions(-) diff --git a/Harmony/Internal/CodeTranspiler.cs b/Harmony/Internal/CodeTranspiler.cs index 778e8796..d74844ea 100644 --- a/Harmony/Internal/CodeTranspiler.cs +++ b/Harmony/Internal/CodeTranspiler.cs @@ -194,7 +194,7 @@ internal static IEnumerable ConvertToGeneralInstructions(MethodInfo transpiler, { var type = transpiler.GetParameters() .Select(p => p.ParameterType) - .FirstOrDefault(t => IsCodeInstructionsParameter(t)); + .FirstOrDefault(IsCodeInstructionsParameter); if (type == typeof(IEnumerable)) { unassignedValues = null; diff --git a/Harmony/Internal/HarmonySharedState.cs b/Harmony/Internal/HarmonySharedState.cs index c44f9bd4..a87c6a4a 100644 --- a/Harmony/Internal/HarmonySharedState.cs +++ b/Harmony/Internal/HarmonySharedState.cs @@ -1,5 +1,4 @@ using Mono.Cecil; -using MonoMod.Core.Platforms; using MonoMod.Utils; using System; using System.Collections.Generic; @@ -36,10 +35,13 @@ internal static class HarmonySharedState const string name = "HarmonySharedState"; internal const int internalVersion = 102; // bump this if the layout of the HarmonySharedState type changes - // state/originals/methodStarts are set to instances stored in the global dynamic types static fields with the same name + // state/originals/originalsMono are set to instances stored in the global dynamic types static fields with the same name static readonly Dictionary state; static readonly Dictionary originals; - + static readonly Dictionary originalsMono; + + static readonly AccessTools.FieldRef methodAddressRef; + internal static readonly int actualVersion; static HarmonySharedState() @@ -47,6 +49,10 @@ static HarmonySharedState() // create singleton type var type = GetOrCreateSharedStateType(); + // this field is useed to find methods from stackframes in Mono + if (AccessTools.IsMonoRuntime && AccessTools.Field(typeof(StackFrame), "methodAddress") is FieldInfo field) + methodAddressRef = AccessTools.FieldRefAccess(field); + // copy 'actualVersion' over to our fields var versionField = type.GetField("version"); if ((int)versionField.GetValue(null) == 0) @@ -63,6 +69,11 @@ static HarmonySharedState() if (originalsField != null && originalsField.GetValue(null) is null) originalsField.SetValue(null, new Dictionary()); + // get or initialize global 'originalsMono' field + var originalsMonoField = type.GetField("originalsMono"); + if (originalsMonoField != null && originalsMonoField.GetValue(null) is null) + originalsMonoField.SetValue(null, new Dictionary()); + // copy 'state' over to our fields state = (Dictionary)stateField.GetValue(null); @@ -70,6 +81,11 @@ static HarmonySharedState() originals = []; if (originalsField != null) // may not exist in older versions originals = (Dictionary)originalsField.GetValue(null); + + // copy 'originalsMono' over to our fields + originalsMono = []; + if (originalsMonoField != null) // may not exist in older versions + originalsMono = (Dictionary)originalsMonoField.GetValue(null); } // creates a dynamic 'global' type if it does not exist @@ -95,6 +111,12 @@ static Type GetOrCreateSharedStateType() module.ImportReference(typeof(Dictionary)) )); + typedef.Fields.Add(new FieldDefinition( + "originalsMono", + Mono.Cecil.FieldAttributes.Public | Mono.Cecil.FieldAttributes.Static, + module.ImportReference(typeof(Dictionary)) + )); + typedef.Fields.Add(new FieldDefinition( "version", Mono.Cecil.FieldAttributes.Public | Mono.Cecil.FieldAttributes.Static, @@ -123,22 +145,49 @@ internal static void UpdatePatchInfo(MethodBase original, MethodInfo replacement { var bytes = patchInfo.Serialize(); lock (state) state[original] = bytes; - lock (originals) originals[replacement] = original; + lock (originals) originals[replacement.Identifiable()] = original; + if (AccessTools.IsMonoRuntime) + { + var methodAddress = (long)replacement.MethodHandle.GetFunctionPointer(); + lock (originalsMono) originalsMono[methodAddress] = [original, replacement]; + } } - internal static MethodBase GetOriginal(MethodInfo replacement) + // With mono, useReplacement is used to either return the original or the replacement + // On .NET, useReplacement is ignored and the original is always returned + internal static MethodBase GetRealMethod(MethodInfo method, bool useReplacement) { - // The runtime can return several different MethodInfo's that point to the same method. Use the correct one - replacement = PlatformTriple.Current.GetIdentifiable(replacement) as MethodInfo; + var identifiableMethod = method.Identifiable(); lock (originals) - return originals.GetValueSafe(replacement); + if (originals.TryGetValue(identifiableMethod, out var original)) + return original; + + if (AccessTools.IsMonoRuntime) + { + var methodAddress = (long)method.MethodHandle.GetFunctionPointer(); + lock (originalsMono) + if (originalsMono.TryGetValue(methodAddress, out var info)) + return useReplacement ? info[1] : info[0]; + } + + return method; } - internal static MethodBase FindReplacement(StackFrame frame) + internal static MethodBase GetStackFrameMethod(StackFrame frame, bool useReplacement) { var method = frame.GetMethod() as MethodInfo; - if (method == null) return null; - return GetOriginal(method); + if (method != null) + return GetRealMethod(method, useReplacement); + + if (methodAddressRef != null) + { + var methodAddress = methodAddressRef(frame); + lock (originalsMono) + if (originalsMono.TryGetValue(methodAddress, out var info)) + return useReplacement ? info[1] : info[0]; + } + + return null; } } } diff --git a/Harmony/Internal/MethodCopier.cs b/Harmony/Internal/MethodCopier.cs index 90e603c3..e9c674a3 100644 --- a/Harmony/Internal/MethodCopier.cs +++ b/Harmony/Internal/MethodCopier.cs @@ -358,7 +358,7 @@ internal List FinalizeILCodes(Emitter emitter, List // pass2 - filter through all processors // var codeTranspiler = new CodeTranspiler(ilInstructions); - transpilers.Do(transpiler => codeTranspiler.Add(transpiler)); + transpilers.Do(codeTranspiler.Add); var codeInstructions = codeTranspiler.GetResult(generator, method); if (emitter is null) diff --git a/Harmony/Internal/MethodPatcher.cs b/Harmony/Internal/MethodPatcher.cs index 3c19924d..4b5356ec 100644 --- a/Harmony/Internal/MethodPatcher.cs +++ b/Harmony/Internal/MethodPatcher.cs @@ -101,7 +101,7 @@ internal MethodInfo CreateReplacement(out Dictionary final Label? skipOriginalLabel = null; LocalBuilder runOriginalVariable = null; - var prefixAffectsOriginal = prefixes.Any(fix => PrefixAffectsOriginal(fix)); + var prefixAffectsOriginal = prefixes.Any(PrefixAffectsOriginal); var anyFixHasRunOriginalVar = fixes.Any(fix => fix.GetParameters().Any(p => p.Name == RUN_ORIGINAL_VAR)); if (prefixAffectsOriginal || anyFixHasRunOriginalVar) { diff --git a/Harmony/Internal/PatchModels.cs b/Harmony/Internal/PatchModels.cs index ca97c70c..dadf9985 100644 --- a/Harmony/Internal/PatchModels.cs +++ b/Harmony/Internal/PatchModels.cs @@ -101,7 +101,7 @@ internal static AttributePatch Create(MethodInfo patch) var f_info = AccessTools.Field(attr.GetType(), nameof(HarmonyAttribute.info)); return f_info.GetValue(attr); }) - .Select(harmonyInfo => AccessTools.MakeDeepCopy(harmonyInfo)) + .Select(AccessTools.MakeDeepCopy) .ToList(); var info = HarmonyMethod.Merge(list); info.method = patch; diff --git a/Harmony/Internal/PatchTools.cs b/Harmony/Internal/PatchTools.cs index 2f5d92d7..82c55062 100644 --- a/Harmony/Internal/PatchTools.cs +++ b/Harmony/Internal/PatchTools.cs @@ -32,7 +32,7 @@ internal static void DetourMethod(MethodBase method, MethodBase replacement) static Assembly GetExecutingAssemblyReplacement() { var frames = new StackTrace().GetFrames(); - if (frames?.Skip(1).FirstOrDefault() is { } frame && Harmony.GetOriginalMethodFromStackframe(frame) is { } original) + if (frames?.Skip(1).FirstOrDefault() is { } frame && Harmony.GetMethodFromStackframe(frame) is { } original) return original.Module.Assembly; return Assembly.GetExecutingAssembly(); } @@ -78,7 +78,7 @@ internal static AssemblyBuilder DefineDynamicAssembly(string name) internal static List GetPatchMethods(Type type) { return AccessTools.GetDeclaredMethods(type) - .Select(method => AttributePatch.Create(method)) + .Select(AttributePatch.Create) .Where(attributePatch => attributePatch is not null) .ToList(); } diff --git a/Harmony/Public/Harmony.cs b/Harmony/Public/Harmony.cs index 33739306..d87909d7 100644 --- a/Harmony/Public/Harmony.cs +++ b/Harmony/Public/Harmony.cs @@ -226,7 +226,7 @@ public void Unpatch(MethodBase original, MethodInfo patch) public static bool HasAnyPatches(string harmonyID) { return GetAllPatchedMethods() - .Select(original => GetPatchInfo(original)) + .Select(GetPatchInfo) .Any(info => info.Owners.Contains(harmonyID)); } @@ -251,13 +251,13 @@ public IEnumerable GetPatchedMethods() public static IEnumerable GetAllPatchedMethods() => PatchProcessor.GetAllPatchedMethods(); /// Gets the original method from a given replacement method - /// A replacement method, for example from a stacktrace + /// A replacement method (patched original method) /// The original method/constructor or null if not found /// public static MethodBase GetOriginalMethod(MethodInfo replacement) { if (replacement == null) throw new ArgumentNullException(nameof(replacement)); - return HarmonySharedState.GetOriginal(replacement); + return HarmonySharedState.GetRealMethod(replacement, useReplacement: false); } /// Tries to get the method from a stackframe including dynamic replacement methods @@ -267,7 +267,7 @@ public static MethodBase GetOriginalMethod(MethodInfo replacement) public static MethodBase GetMethodFromStackframe(StackFrame frame) { if (frame == null) throw new ArgumentNullException(nameof(frame)); - return HarmonySharedState.FindReplacement(frame) ?? frame.GetMethod(); + return HarmonySharedState.GetStackFrameMethod(frame, useReplacement: true); } /// Gets the original method from the stackframe and uses original if method is a dynamic replacement @@ -275,16 +275,15 @@ public static MethodBase GetMethodFromStackframe(StackFrame frame) /// The original method from that stackframe public static MethodBase GetOriginalMethodFromStackframe(StackFrame frame) { - var member = GetMethodFromStackframe(frame); - if (member is MethodInfo methodInfo) - member = GetOriginalMethod(methodInfo) ?? member; - return member; + if (frame == null) throw new ArgumentNullException(nameof(frame)); + return HarmonySharedState.GetStackFrameMethod(frame, useReplacement: false); } /// Gets Harmony version for all active Harmony instances /// [out] The current Harmony version /// A dictionary containing assembly versions keyed by Harmony IDs /// - public static Dictionary VersionInfo(out Version currentVersion) => PatchProcessor.VersionInfo(out currentVersion); + public static Dictionary VersionInfo(out Version currentVersion) + => PatchProcessor.VersionInfo(out currentVersion); } } diff --git a/Harmony/Public/HarmonyMethod.cs b/Harmony/Public/HarmonyMethod.cs index e19d8cc0..379ae6db 100644 --- a/Harmony/Public/HarmonyMethod.cs +++ b/Harmony/Public/HarmonyMethod.cs @@ -292,7 +292,7 @@ static HarmonyMethod GetHarmonyMethodInfo(object attribute) public static List GetFromType(Type type) { return type.GetCustomAttributes(true) - .Select(attr => GetHarmonyMethodInfo(attr)) + .Select(GetHarmonyMethodInfo) .Where(info => info is not null) .ToList(); } @@ -310,7 +310,7 @@ public static List GetFromType(Type type) public static List GetFromMethod(MethodBase method) { return method.GetCustomAttributes(true) - .Select(attr => GetHarmonyMethodInfo(attr)) + .Select(GetHarmonyMethodInfo) .Where(info => info is not null) .ToList(); } diff --git a/Harmony/Tools/AccessTools.cs b/Harmony/Tools/AccessTools.cs index fe73ec53..cac03790 100644 --- a/Harmony/Tools/AccessTools.cs +++ b/Harmony/Tools/AccessTools.cs @@ -1,3 +1,4 @@ +using MonoMod.Core.Platforms; using MonoMod.Utils; using System; using System.Collections; @@ -84,7 +85,7 @@ public static Type[] GetTypesFromAssembly(Assembly assembly) /// Enumerates all successfully loaded types in the current app domain, excluding visual studio assemblies /// An enumeration of all in all assemblies, excluding visual studio assemblies /// - public static IEnumerable AllTypes() => AllAssemblies().SelectMany(a => GetTypesFromAssembly(a)); + public static IEnumerable AllTypes() => AllAssemblies().SelectMany(GetTypesFromAssembly); /// Enumerates all inner types (non-recursive) of a given type /// The class/type to start with @@ -133,6 +134,11 @@ public static T FindIncludingInnerTypes(Type type, Func func) where return result; } + /// Creates an identifiable version of a method + /// The method + /// + public static MethodInfo Identifiable(this MethodInfo method) => PlatformTriple.Current.GetIdentifiable(method) as MethodInfo ?? method; + /// Gets the reflection information for a directly declared field /// The class/type where the field is defined /// The name of the field