From b8fed2bc468508824d8189c91ec257b71654d322 Mon Sep 17 00:00:00 2001 From: Akeit0 <90429982+Akeit0@users.noreply.github.com> Date: Fri, 2 May 2025 20:45:31 +0900 Subject: [PATCH] Add: Add project and code to make it easier to check JIT asm --- Lua.sln | 7 + sandbox/ConsoleApp2/.gitignore | 479 +++++++++++++ sandbox/JitTest/.gitignore | 480 +++++++++++++ sandbox/JitTest/JitTest.csproj | 20 + sandbox/JitTest/Program.cs | 62 ++ sandbox/JitTest/db.lua | 630 ++++++++++++++++++ sandbox/JitTest/test.lua | 118 ++++ .../AsyncMethodBuilderAttribute.cs | 5 +- src/Lua/Runtime/LuaVirtualMachine.Markers.cs | 310 +++++++++ src/Lua/Runtime/LuaVirtualMachine.cs | 40 +- 10 files changed, 2148 insertions(+), 3 deletions(-) create mode 100644 sandbox/JitTest/.gitignore create mode 100644 sandbox/JitTest/JitTest.csproj create mode 100644 sandbox/JitTest/Program.cs create mode 100644 sandbox/JitTest/db.lua create mode 100644 sandbox/JitTest/test.lua create mode 100644 src/Lua/Runtime/LuaVirtualMachine.Markers.cs diff --git a/Lua.sln b/Lua.sln index 44044c10..61acb3b7 100644 --- a/Lua.sln +++ b/Lua.sln @@ -24,6 +24,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lua.SourceGenerator", "src\ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleApp2", "sandbox\ConsoleApp2\ConsoleApp2.csproj", "{474D977A-946F-49F1-9293-F7F78E0F6A01}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JitTest", "sandbox\JitTest\JitTest.csproj", "{BF479E2C-AAF5-4128-B236-EC7D6092E1F8}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -57,6 +59,10 @@ Global {474D977A-946F-49F1-9293-F7F78E0F6A01}.Debug|Any CPU.Build.0 = Debug|Any CPU {474D977A-946F-49F1-9293-F7F78E0F6A01}.Release|Any CPU.ActiveCfg = Release|Any CPU {474D977A-946F-49F1-9293-F7F78E0F6A01}.Release|Any CPU.Build.0 = Release|Any CPU + {BF479E2C-AAF5-4128-B236-EC7D6092E1F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BF479E2C-AAF5-4128-B236-EC7D6092E1F8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BF479E2C-AAF5-4128-B236-EC7D6092E1F8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BF479E2C-AAF5-4128-B236-EC7D6092E1F8}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {6E33BFBC-E51F-493E-9AF0-30C1100F5B5D} = {18A64E25-9557-457B-80AE-A6EFE853118D} @@ -65,5 +71,6 @@ Global {FC157C29-8AAE-49C8-9536-208E3F0698DA} = {33883F28-679F-48AD-8E64-3515C7BDAF5A} {C4BB264C-4D37-4E2D-99FD-4918CE22D7E4} = {18A64E25-9557-457B-80AE-A6EFE853118D} {474D977A-946F-49F1-9293-F7F78E0F6A01} = {33883F28-679F-48AD-8E64-3515C7BDAF5A} + {BF479E2C-AAF5-4128-B236-EC7D6092E1F8} = {33883F28-679F-48AD-8E64-3515C7BDAF5A} EndGlobalSection EndGlobal diff --git a/sandbox/ConsoleApp2/.gitignore b/sandbox/ConsoleApp2/.gitignore index e69de29b..5e1a3804 100644 --- a/sandbox/ConsoleApp2/.gitignore +++ b/sandbox/ConsoleApp2/.gitignore @@ -0,0 +1,479 @@ +## 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 +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[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 +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# 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 +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.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 + +# 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 +DocProject/Help/*.HxC +DocProject/Help/*.hhc +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 +*.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/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/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 +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# 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/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +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 ;-) +_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 +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# 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/ + +# 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 diff --git a/sandbox/JitTest/.gitignore b/sandbox/JitTest/.gitignore new file mode 100644 index 00000000..b34b42fc --- /dev/null +++ b/sandbox/JitTest/.gitignore @@ -0,0 +1,480 @@ +## 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 +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[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 +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# 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 +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.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 + +# 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 +DocProject/Help/*.HxC +DocProject/Help/*.hhc +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 +*.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/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/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 +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# 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/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +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 ;-) +_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 +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# 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/ + +# 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 +/obj/ diff --git a/sandbox/JitTest/JitTest.csproj b/sandbox/JitTest/JitTest.csproj new file mode 100644 index 00000000..2eca573b --- /dev/null +++ b/sandbox/JitTest/JitTest.csproj @@ -0,0 +1,20 @@ + + + + Exe + net9.0 + 13 + enable + enable + + + + + + + + + + + + diff --git a/sandbox/JitTest/Program.cs b/sandbox/JitTest/Program.cs new file mode 100644 index 00000000..441041c0 --- /dev/null +++ b/sandbox/JitTest/Program.cs @@ -0,0 +1,62 @@ +// See https://aka.ms/new-console-template for more information + + +using System.Reflection; +using System.Runtime.CompilerServices; +using JitInspect; +using Lua; +using Lua.Runtime; +using Lua.Standard; + +// dotnet run --configuration Release /p:DefineConstants="CASE_MARKER" +// to activate the CASE_MARKER +// JitInspect can be run in Windows and Linux (MacOS is not supported yet) +var luaState = LuaState.Create(); +luaState.OpenStandardLibraries(); +{ + await luaState.DoFileAsync((GetAbsolutePath("db.lua"))); +} + +var closure = luaState.Load(File.ReadAllBytes(GetAbsolutePath("test.lua")),"test.lua"); + +for (int i = 0; i < 1000; i++) +{ + await luaState.MainThread.RunAsync(closure); + luaState.MainThread.Stack.Clear(); +} + +var savePath = GetAbsolutePath("history"); +var thisDir = GetThisDirectoryName(); +var newJIitPath = Path.Join(thisDir, $"jit_{DateTime.Now:yyyy-MM-dd-HH-mm-ss}.txt"); +var lastJitPaths = Directory.GetFiles(thisDir).Where(x=>x.Contains("jit_")); +if (!Directory.Exists(savePath)) +{ + Directory.CreateDirectory(savePath); +} +if (lastJitPaths.Any()) +{ + Console.WriteLine("Last:" + File.ReadAllLines(lastJitPaths.First())[^1]); + foreach (var jitPath in lastJitPaths) + { + var last = jitPath; + var dest = Path.Join(savePath, Path.GetFileName(jitPath)); + File.Move(last, dest); + } + +} +var method = typeof(LuaVirtualMachine).GetMethod("MoveNext", BindingFlags.Static | BindingFlags.NonPublic)!; +using var disassembler = JitDisassembler.Create(); +var nextJitText = disassembler.Disassemble(method); +File.WriteAllText(newJIitPath, nextJitText); +Console.WriteLine("New:" + nextJitText.Split("\n")[^1]); + + +static string GetThisDirectoryName([CallerFilePath] string callerFilePath = "") +{ + return Path.GetDirectoryName(callerFilePath)!; +} + +static string GetAbsolutePath(string relativePath, [CallerFilePath] string callerFilePath = "") +{ + return Path.Join(Path.GetDirectoryName(callerFilePath)!, relativePath); +} \ No newline at end of file diff --git a/sandbox/JitTest/db.lua b/sandbox/JitTest/db.lua new file mode 100644 index 00000000..f087d7e1 --- /dev/null +++ b/sandbox/JitTest/db.lua @@ -0,0 +1,630 @@ +-- testing debug library + +debug = require "debug" + +local function dostring(s) return assert(load(s))() end + +print"testing debug library and debug information" + +do +local a=1 +end + +function test (s, l, p) + collectgarbage() -- avoid gc during trace + local function f (event, line) + assert(event == 'line') + local l = table.remove(l, 1) + if p then print(l, line) end + assert(l == line, "wrong trace!!") + end + debug.sethook(f,"l"); load(s)(); debug.sethook() + assert(#l == 0) +end + + +do + assert(not pcall(debug.getinfo, print, "X")) -- invalid option + assert(debug.getinfo(1000) == nil) -- out of range level + assert(debug.getinfo(-1) == nil) -- out of range level + local a = debug.getinfo(print) + assert(a.what == "C#" and a.short_src == "[C#]") -- changed C to C# + a = debug.getinfo(print, "L") + assert(a.activelines == nil) + local b = debug.getinfo(test, "SfL") + assert(b.name == nil and b.what == "Lua" and b.linedefined == 13 and + b.lastlinedefined == b.linedefined + 10 and + b.func == test and not string.find(b.short_src, "%[")) + assert(b.activelines[b.linedefined + 1] and + b.activelines[b.lastlinedefined]) + assert(not b.activelines[b.linedefined] and + not b.activelines[b.lastlinedefined + 1]) +end + + +-- test file and string names truncation +a = "function f () end" +local function dostring (s, x) return load(s, x)() end +dostring(a) +assert(debug.getinfo(f).short_src == string.format('[string "%s"]', a)) +dostring(a..string.format("; %s\n=1", string.rep('p', 400))) +assert(string.find(debug.getinfo(f).short_src, '^%[string [^\n]*%.%.%."%]$')) +dostring(a..string.format("; %s=1", string.rep('p', 400))) +assert(string.find(debug.getinfo(f).short_src, '^%[string [^\n]*%.%.%."%]$')) +dostring("\n"..a) +assert(debug.getinfo(f).short_src == '[string "..."]') +dostring(a, "") +assert(debug.getinfo(f).short_src == '[string ""]') +dostring(a, "@xuxu") +assert(debug.getinfo(f).short_src == "xuxu") +dostring(a, "@"..string.rep('p', 1000)..'t') +assert(string.find(debug.getinfo(f).short_src, "^%.%.%.p*t$")) +dostring(a, "=xuxu") +assert(debug.getinfo(f).short_src == "xuxu") +dostring(a, string.format("=%s", string.rep('x', 500))) +assert(string.find(debug.getinfo(f).short_src, "^x*$")) +dostring(a, "=") +assert(debug.getinfo(f).short_src == "") +a = nil; f = nil; + + +repeat + local g = {x = function () + local a = debug.getinfo(2) + assert(a.name == 'f' and a.namewhat == 'local') + a = debug.getinfo(1) + assert(a.name == 'x' and a.namewhat == 'field') + return 'xixi' + end} + local f = function () return 1+1 and (not 1 or g.x()) end + assert(f() == 'xixi') + g = debug.getinfo(f) + assert(g.what == "Lua" and g.func == f and g.namewhat == "" and not g.name) + + function f (x, name) -- local! + name = name or 'f' + local a = debug.getinfo(1) + assert(a.name == name and a.namewhat == 'local') + return x + end + + -- breaks in different conditions + if 3>4 then break end; f() + if 3<4 then a=1 else break end; f() + while 1 do local x=10; break end; f() + local b = 1 + if 3>4 then return math.sin(1) end; f() + a = 3<4; f() + a = 3<4 or 1; f() + repeat local x=20; if 4>3 then f() else break end; f() until 1 + g = {} + f(g).x = f(2) and f(10)+f(9) + assert(g.x == f(19)) + function g(x) if not x then return 3 end return (x('a', 'x')) end + assert(g(f) == 'a') +until 1 + +test([[if +math.sin(1) +then + a=1 +else + a=2 +end +]], {2,3,4,7}) + +test([[-- +if nil then + a=1 +else + a=2 +end +]], {2,5,6}) + +test([[a=1 +repeat + a=a+1 +until a==3 +]], {1,3,4,3,4}) + +test([[ do + return +end +]], {2}) + +test([[local a +a=1 +while a<=3 do + a=a+1 +end +]], {1,2,3,4,3,4,3,4,3,5}) + +test([[while math.sin(1) do + if math.sin(1) + then break + end +end +a=1]], {1,2,3,6}) + +test([[for i=1,3 do + a=i +end +]], {1,2,1,2,1,2,1,3}) + +test([[for i,v in pairs{'a','b'} do + a=i..v +end +]], {1,2,1,2,1,3}) + +test([[for i=1,4 do a=1 end]], {1,1,1,1,1}) + + + +print'+' + +-- invalid levels in [gs]etlocal +assert(not pcall(debug.getlocal, 20, 1)) +assert(not pcall(debug.setlocal, -1, 1, 10)) + + +-- parameter names +local function foo (a,b,...) local d, e end +local co = coroutine.create(foo) + +assert(debug.getlocal(foo, 1) == 'a') +assert(debug.getlocal(foo, 2) == 'b') +assert(debug.getlocal(foo, 3) == nil) +assert(debug.getlocal(co, foo, 1) == 'a') +assert(debug.getlocal(co, foo, 2) == 'b') +assert(debug.getlocal(co, foo, 3) == nil) + +assert(debug.getlocal(print, 1) == nil) + + +-- varargs +local function foo (a, ...) + local t = table.pack(...) + for i = 1, t.n do + local n, v = debug.getlocal(1, -i) + assert(n == "(*vararg)" and v == t[i]) + end + assert(not debug.getlocal(1, -(t.n + 1))) + assert(not debug.setlocal(1, -(t.n + 1), 30)) + if t.n > 0 then + (function (x) + assert(debug.setlocal(2, -1, x) == "(*vararg)") + assert(debug.setlocal(2, -t.n, x) == "(*vararg)") + end)(430) + assert(... == 430) + end +end + +foo() +foo(print) +foo(200, 3, 4) +local a = {} +for i = 1,1000 do a[i] = i end +foo(table.unpack(a)) +a = nil + +-- access to vararg in non-vararg function +local function foo () return debug.getlocal(1, -1) end +assert(foo(10) == nil) + + +a = {}; L = nil +local glob = 1 +local oldglob = glob +debug.sethook(function (e,l) + collectgarbage() -- force GC during a hook + local f, m, c = debug.gethook() + assert(m == 'crl' and c == 0) + if e == "line" then + if glob ~= oldglob then + L = l-1 -- get the first line where "glob" has changed + oldglob = glob + end + elseif e == "call" then + local f = debug.getinfo(2, "f").func + a[f] = 1 + else assert(e == "return") + end +end, "crl") + + +function f(a,b) + collectgarbage() + local _, x = debug.getlocal(1, 1) + local _, y = debug.getlocal(1, 2) + assert(x == a and y == b) + assert(debug.setlocal(2, 3, "pera") == "AA".."AA") + assert(debug.setlocal(2, 4, "ma��") == "B") + x = debug.getinfo(2) + assert(x.func == g and x.what == "Lua" and x.name == 'g' and + x.nups == 1 and string.find(x.source, "^@.*db%.lua$")) + glob = glob+1 + assert(debug.getinfo(1, "l").currentline == L+1) + assert(debug.getinfo(1, "l").currentline == L+2) +end + +function foo() + glob = glob+1 + assert(debug.getinfo(1, "l").currentline == L+1) +end; foo() -- set L +-- check line counting inside strings and empty lines + +--_ = 'alo\ -- todo fix compiler bug Lua-CSharp +--alo' .. [[ +-- +--]] +--[[ +]] +assert(debug.getinfo(1, "l").currentline == L+11) -- check count of lines + + +function g(...) + local arg = {...} + do local a,b,c; a=math.sin(40); end + local feijao + local AAAA,B = "xuxu", "mam�o" + f(AAAA,B) + assert(AAAA == "pera" and B == "ma��") + do + local B = 13 + local x,y = debug.getlocal(1,5) + assert(x == 'B' and y == 13) + end +end + +g() + + +assert(a[f] and a[g] and a[assert] and a[debug.getlocal] and not a[print]) + + +-- tests for manipulating non-registered locals (C and Lua temporaries) + +local n, v = debug.getlocal(0, 1) +assert(v == 0 and n == "(*temporary)") +local n, v = debug.getlocal(0, 2) +assert(v == 2 and n == "(*temporary)") +assert(not debug.getlocal(0, 3)) +assert(not debug.getlocal(0, 0)) + +function f() + assert(select(2, debug.getlocal(2,3)) == 1) + assert(not debug.getlocal(2,4)) + debug.setlocal(2, 3, 10) + return 20 +end + +function g(a,b) return (a+1) + f() end + +assert(g(0,0) == 30) + + +debug.sethook(nil); +assert(debug.gethook() == nil) + + +-- testing access to function arguments + +X = nil +a = {} +function a:f (a, b, ...) local arg = {...}; local c = 13 end +debug.sethook(function (e) + assert(e == "call") + dostring("XX = 12") -- test dostring inside hooks + -- testing errors inside hooks + assert(not pcall(load("a='joao'+1"))) + debug.sethook(function (e, l) + assert(debug.getinfo(2, "l").currentline == l) + local f,m,c = debug.gethook() + assert(e == "line") + assert(m == 'l' and c == 0) + debug.sethook(nil) -- hook is called only once + assert(not X) -- check that + X = {}; local i = 1 + local x,y + while 1 do + x,y = debug.getlocal(2, i) + if x==nil then break end + X[x] = y + i = i+1 + end + end, "l") +end, "c") + +a:f(1,2,3,4,5) +assert(X.self == a and X.a == 1 and X.b == 2 and X.c == nil) +assert(XX == 12) +assert(debug.gethook() == nil) + + +-- testing upvalue access +local function getupvalues (f) + local t = {} + local i = 1 + while true do + local name, value = debug.getupvalue(f, i) + if not name then break end + assert(not t[name]) + t[name] = value + i = i + 1 + end + return t +end + +local a,b,c = 1,2,3 +local function foo1 (a) b = a; return c end +local function foo2 (x) a = x; return c+b end +assert(debug.getupvalue(foo1, 3) == nil) +assert(debug.getupvalue(foo1, 0) == nil) +assert(debug.setupvalue(foo1, 3, "xuxu") == nil) +local t = getupvalues(foo1) +assert(t.a == nil and t.b == 2 and t.c == 3) +t = getupvalues(foo2) +assert(t.a == 1 and t.b == 2 and t.c == 3) +assert(debug.setupvalue(foo1, 1, "xuxu") == "b") +assert(({debug.getupvalue(foo2, 3)})[2] == "xuxu") +-- upvalues of C functions are allways "called" "" (the empty string) +assert(debug.getupvalue(string.gmatch("x", "x"), 1) == "") + + +-- testing count hooks +local a=0 +debug.sethook(function (e) a=a+1 end, "", 1) +a=0; for i=1,1000 do end; assert(1000 < a and a < 1012) +debug.sethook(function (e) a=a+1 end, "", 4) +a=0; for i=1,1000 do end; assert(250 < a and a < 255) +local f,m,c = debug.gethook() +assert(m == "" and c == 4) +debug.sethook(function (e) a=a+1 end, "", 4000) +a=0; for i=1,1000 do end; assert(a == 0) + +if not _no32 then + debug.sethook(print, "", 2^24 - 1) -- count upperbound + local f,m,c = debug.gethook() + assert(({debug.gethook()})[3] == 2^24 - 1) +end + +debug.sethook() + + +-- tests for tail calls +local function f (x) + if x then + assert(debug.getinfo(1, "S").what == "Lua") + assert(debug.getinfo(1, "t").istailcall == true) + local tail = debug.getinfo(2) + assert(tail.func == g1 and tail.istailcall == true) + assert(debug.getinfo(3, "S").what == "main") + print"+" + end +end + +function g(x) return f(x) end + +function g1(x) g(x) end + +local function h (x) local f=g1; return f(x) end + +h(true) + +local b = {} +debug.sethook(function (e) table.insert(b, e) end, "cr") +h(false) +debug.sethook() +local res = {"return", -- first return (from sethook) + "call", "tail call", "call", "tail call", + "return", "return", + "call", -- last call (to sethook) +} +for i = 1, #res do assert(res[i] == table.remove(b, 1)) end + +b = 0 +debug.sethook(function (e) + if e == "tail call" then + b = b + 1 + assert(debug.getinfo(2, "t").istailcall == true) + else + assert(debug.getinfo(2, "t").istailcall == false) + end + end, "c") +h(false) +debug.sethook() +assert(b == 2) -- two tail calls + +lim = 30000 +if _soft then limit = 3000 end +local function foo (x) + if x==0 then + assert(debug.getinfo(2).what == "main") + local info = debug.getinfo(1) + assert(info.istailcall == true and info.func == foo) + else return foo(x-1) + end +end + +foo(lim) + + +print"+" + + +-- testing local function information +co = load[[ + local A = function () + return x + end + return +]] + +local a = 0 +-- 'A' should be visible to debugger only after its complete definition +debug.sethook(function (e, l) + if l == 3 then a = a + 1; assert(debug.getlocal(2, 1) == nil)-- assert(debug.getlocal(2, 1) == "(*temporary)") --changed behavior Lua-CSharp + elseif l == 4 then a = a + 1; assert(debug.getlocal(2, 1) == "A") + end +end, "l") +co() -- run local function definition +debug.sethook() -- turn off hook +assert(a == 2) -- ensure all two lines where hooked + +-- testing traceback + +assert(debug.traceback(print) == print) +assert(debug.traceback(print, 4) == print) +assert(string.find(debug.traceback("hi", 4), "^hi\n")) +assert(string.find(debug.traceback("hi"), "^hi\n")) +assert(not string.find(debug.traceback("hi"), "'traceback'")) +assert(string.find(debug.traceback("hi", 0), "'traceback'")) +assert(string.find(debug.traceback(), "^stack traceback:\n")) + + +-- testing nparams, nups e isvararg +local t = debug.getinfo(print, "u") +assert(t.isvararg == true and t.nparams == 0 and t.nups == 0) + +t = debug.getinfo(function (a,b,c) end, "u") +assert(t.isvararg == false and t.nparams == 3 and t.nups == 0) + +t = debug.getinfo(function (a,b,...) return t[a] end, "u") +assert(t.isvararg == true and t.nparams == 2 and t.nups == 1) + +t = debug.getinfo(1) -- main +assert(t.isvararg == true and t.nparams == 0 and t.nups == 1 and + debug.getupvalue(t.func, 1) == "_ENV") + + +-- testing debugging of coroutines + +local function checktraceback (co, p, level) + local tb = debug.traceback(co, nil, level) + local i = 0 + for l in string.gmatch(tb, "[^\n]+\n?") do + assert(i == 0 or string.find(l, p[i])) + i = i+1 + end + assert(p[i] == nil) +end + + +local function f (n) + if n > 0 then f(n-1) + else coroutine.yield() end +end + +local co = coroutine.create(f) +coroutine.resume(co, 3) +checktraceback(co, {"yield", "db.lua", "db.lua", "db.lua", "db.lua"}) +checktraceback(co, {"db.lua", "db.lua", "db.lua", "db.lua"}, 1) +checktraceback(co, {"db.lua", "db.lua", "db.lua"}, 2) +checktraceback(co, {"db.lua"}, 4) +checktraceback(co, {}, 40) + + +co = coroutine.create(function (x) + local a = 1 + coroutine.yield(debug.getinfo(1, "l")) + coroutine.yield(debug.getinfo(1, "l").currentline) + return a + end) + +local tr = {} +local foo = function (e, l) if l then table.insert(tr, l) end end +debug.sethook(co, foo, "lcr") + +local _, l = coroutine.resume(co, 10) +local x = debug.getinfo(co, 1, "lfLS") +assert(x.currentline == l.currentline and x.activelines[x.currentline]) +assert(type(x.func) == "function") +for i=x.linedefined + 1, x.lastlinedefined do + assert(x.activelines[i]) + x.activelines[i] = nil +end +assert(next(x.activelines) == nil) -- no 'extra' elements +assert(debug.getinfo(co, 2) == nil) +local a,b = debug.getlocal(co, 1, 1) +assert(a == "x" and b == 10) +a,b = debug.getlocal(co, 1, 2) +assert(a == "a" and b == 1) +debug.setlocal(co, 1, 2, "hi") +assert(debug.gethook(co) == foo) +assert(#tr == 2 and + tr[1] == l.currentline-1 and tr[2] == l.currentline) + +a,b,c = pcall(coroutine.resume, co) +assert(a and b and c == l.currentline+1) +checktraceback(co, {"yield", "in function <"}) + +a,b = coroutine.resume(co) +assert(a and b == "hi") +assert(#tr == 4 and tr[4] == l.currentline+2) +assert(debug.gethook(co) == foo) +assert(debug.gethook() == nil) +checktraceback(co, {}) + + +-- check traceback of suspended (or dead with error) coroutines + +function f(i) if i==0 then error(i) else coroutine.yield(); f(i-1) end end + +co = coroutine.create(function (x) f(x) end) +a, b = coroutine.resume(co, 3) +t = {"'yield'", "'f'", "in function <"} +while coroutine.status(co) == "suspended" do + checktraceback(co, t) + a, b = coroutine.resume(co) + table.insert(t, 2, "'f'") -- one more recursive call to 'f' +end +t[1] = "'error'" +checktraceback(co, t) + + +-- test acessing line numbers of a coroutine from a resume inside +-- a C function (this is a known bug in Lua 5.0) + +local function g(x) + coroutine.yield(x) +end + +local function f (i) + debug.sethook(function () end, "l") + for j=1,1000 do + g(i+j) + end +end + +local co = coroutine.wrap(f) +co(10) +pcall(co) +pcall(co) + + +assert(type(debug.getregistry()) == "table") + + +-- test tagmethod information +local a = {} +local function f (t) + local info = debug.getinfo(1); + assert(info.namewhat == "metamethod") + a.op = info.name + return info.name +end +setmetatable(a, { + __index = f; __add = f; __div = f; __mod = f; __concat = f; __pow = f; + __eq = f; __le = f; __lt = f; +}) + +local b = setmetatable({}, getmetatable(a)) + +assert(a[3] == "index" and a^3 == "pow" and a..a == "concat") +assert(a/3 == "div" and 3%a == "mod") +assert (a==b and a.op == "eq") +assert (a>=b and a.op == "le") +assert (a>b and a.op == "lt") + + +print"OK" diff --git a/sandbox/JitTest/test.lua b/sandbox/JitTest/test.lua new file mode 100644 index 00000000..2426a766 --- /dev/null +++ b/sandbox/JitTest/test.lua @@ -0,0 +1,118 @@ + +local temp = 3 %"4" + +sun = {} +jupiter = {} +saturn = {} +uranus = {} +neptune = {} + +local sqrt = math.sqrt + +local PI = 3.141592653589793 +local SOLAR_MASS = 4 * PI * PI +local DAYS_PER_YEAR = 365.24 +sun.x = 0.0 +sun.y = 0.0 +sun.z = 0.0 +sun.vx = 0.0 +sun.vy = 0.0 +sun.vz = 0.0 +sun.mass = SOLAR_MASS +jupiter.x = 4.84143144246472090e+00 +jupiter.y = -1.16032004402742839e+00 +jupiter.z = -1.03622044471123109e-01 +jupiter.vx = 1.66007664274403694e-03 * DAYS_PER_YEAR +jupiter.vy = 7.69901118419740425e-03 * DAYS_PER_YEAR +jupiter.vz = -6.90460016972063023e-05 * DAYS_PER_YEAR +jupiter.mass = 9.54791938424326609e-04 * SOLAR_MASS +saturn.x = 8.34336671824457987e+00 +saturn.y = 4.12479856412430479e+00 +saturn.z = -4.03523417114321381e-01 +saturn.vx = -2.76742510726862411e-03 * DAYS_PER_YEAR +saturn.vy = 4.99852801234917238e-03 * DAYS_PER_YEAR +saturn.vz = 2.30417297573763929e-05 * DAYS_PER_YEAR +saturn.mass = 2.85885980666130812e-04 * SOLAR_MASS +uranus.x = 1.28943695621391310e+01 +uranus.y = -1.51111514016986312e+01 +uranus.z = -2.23307578892655734e-01 +uranus.vx = 2.96460137564761618e-03 * DAYS_PER_YEAR +uranus.vy = 2.37847173959480950e-03 * DAYS_PER_YEAR +uranus.vz = -2.96589568540237556e-05 * DAYS_PER_YEAR +uranus.mass = 4.36624404335156298e-05 * SOLAR_MASS +neptune.x = 1.53796971148509165e+01 +neptune.y = -2.59193146099879641e+01 +neptune.z = 1.79258772950371181e-01 +neptune.vx = 2.68067772490389322e-03 * DAYS_PER_YEAR +neptune.vy = 1.62824170038242295e-03 * DAYS_PER_YEAR +neptune.vz = -9.51592254519715870e-05 * DAYS_PER_YEAR +neptune.mass = 5.15138902046611451e-05 * SOLAR_MASS + +local bodies = { sun, jupiter, saturn, uranus, neptune } + +local function advance(bodies, nbody, dt) + for i = 1, nbody do + local bi = bodies[i] + local bix, biy, biz, bimass = bi.x, bi.y, bi.z, bi.mass + local bivx, bivy, bivz = bi.vx, bi.vy, bi.vz + for j = i + 1, nbody do + local bj = bodies[j] + local dx, dy, dz = bix - bj.x, biy - bj.y, biz - bj.z + local dist2 = dx * dx + dy * dy + dz * dz + local mag = sqrt(dist2) + mag = dt / (mag * dist2) + local bm = bj.mass * mag + bivx = bivx - (dx * bm) + bivy = bivy - (dy * bm) + bivz = bivz - (dz * bm) + bm = bimass * mag + bj.vx = bj.vx + (dx * bm) + bj.vy = bj.vy + (dy * bm) + bj.vz = bj.vz + (dz * bm) + end + bi.vx = bivx + bi.vy = bivy + bi.vz = bivz + bi.x = bix + dt * bivx + bi.y = biy + dt * bivy + bi.z = biz + dt * bivz + end +end + +local function energy(bodies, nbody) + local e = 0 + for i = 1, nbody do + local bi = bodies[i] + local vx, vy, vz, bim = bi.vx, bi.vy, bi.vz, bi.mass + e = e + (0.5 * bim * (vx * vx + vy * vy + vz * vz)) + for j = i + 1, nbody do + local bj = bodies[j] + local dx, dy, dz = bi.x - bj.x, bi.y - bj.y, bi.z - bj.z + local distance = sqrt(dx * dx + dy * dy + dz * dz) + e = e - ((bim * bj.mass) / distance) + end + end + return e +end + +local function offsetMomentum(b, nbody) + local px, py, pz = 0, 0, 0 + for i = 1, nbody do + local bi = b[i] + local bim = bi.mass + px = px + (bi.vx * bim) + py = py + (bi.vy * bim) + pz = pz + (bi.vz * bim) + end + b[1].vx = -px / SOLAR_MASS + b[1].vy = -py / SOLAR_MASS + b[1].vz = -pz / SOLAR_MASS +end + +local N = tonumber(arg and arg[1]) or 1000 +local nbody = #bodies + +offsetMomentum(bodies, nbody) +energy(bodies, nbody) +for i = 1, N do advance(bodies, nbody, 0.01) end +energy(bodies, nbody) \ No newline at end of file diff --git a/src/Lua/Internal/CompilerServices/AsyncMethodBuilderAttribute.cs b/src/Lua/Internal/CompilerServices/AsyncMethodBuilderAttribute.cs index bad54905..bed84737 100644 --- a/src/Lua/Internal/CompilerServices/AsyncMethodBuilderAttribute.cs +++ b/src/Lua/Internal/CompilerServices/AsyncMethodBuilderAttribute.cs @@ -1,10 +1,11 @@ #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member #pragma warning disable CS0436 - +#if !NET5_0_OR_GREATER namespace System.Runtime.CompilerServices { internal sealed class AsyncMethodBuilderAttribute(Type builderType) : Attribute { public Type BuilderType { get; } = builderType; } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/src/Lua/Runtime/LuaVirtualMachine.Markers.cs b/src/Lua/Runtime/LuaVirtualMachine.Markers.cs new file mode 100644 index 00000000..63554dc0 --- /dev/null +++ b/src/Lua/Runtime/LuaVirtualMachine.Markers.cs @@ -0,0 +1,310 @@ +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using Lua.Internal; +using System.Diagnostics; + +// ReSharper disable InconsistentNaming + +namespace Lua.Runtime; + +static partial class LuaVirtualMachine +{ + static class Markers + { + static Markers() + { + InitializeMarkers(); + } + + /// + /// This method is used to call the marker method once for the JIT decompiler. + /// ClrMd, used for the JIT decompiler, cannot identify a method unless that method is called at least once. + /// + [Conditional("CASE_MARKER")] + [MethodImpl(MethodImplOptions.NoInlining)] + static void InitializeMarkers() + { + Move(); + LoadK(); + LoadKX(); + LoadBool(); + LoadNil(); + GetUpVal(); + GetTabUp(); + GetTable(); + SetTabUp(); + SetUpVal(); + SetTable(); + NewTable(); + Self(); + Add(); + Sub(); + Mul(); + Div(); + Mod(); + Pow(); + Unm(); + Not(); + Len(); + Concat(); + Jmp(); + Eq(); + Lt(); + Le(); + Test(); + TestSet(); + Call(); + TailCall(); + Return(); + ForLoop(); + ForPrep(); + TForCall(); + TForLoop(); + SetList(); + Closure(); + VarArg(); + ExtraArg(); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void Move() + { + } + + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void LoadK() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void LoadKX() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void LoadBool() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void LoadNil() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void GetUpVal() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void GetTabUp() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void GetTable() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void SetTabUp() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void SetUpVal() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void SetTable() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void NewTable() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void Self() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void Add() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void Sub() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void Mul() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void Div() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void Mod() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void Pow() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void Unm() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void Not() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void Len() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void Concat() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void Jmp() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void Eq() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void Lt() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void Le() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void Test() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void TestSet() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void Call() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void TailCall() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void Return() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void ForLoop() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void ForPrep() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void TForCall() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void TForLoop() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void SetList() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void Closure() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void VarArg() + { + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [Conditional("CASE_MARKER")] + public static void ExtraArg() + { + } + } +} \ No newline at end of file diff --git a/src/Lua/Runtime/LuaVirtualMachine.cs b/src/Lua/Runtime/LuaVirtualMachine.cs index f6338046..fd73def0 100644 --- a/src/Lua/Runtime/LuaVirtualMachine.cs +++ b/src/Lua/Runtime/LuaVirtualMachine.cs @@ -340,31 +340,39 @@ static bool MoveNext(VirtualMachineExecutionContext context) switch (opCode) { case OpCode.Move: + Markers.Move(); ref var stackHead = ref stack.FastGet(frameBase); Unsafe.Add(ref stackHead, iA) = Unsafe.Add(ref stackHead, instruction.B); stack.NotifyTop(iA + frameBase + 1); continue; case OpCode.LoadK: + Markers.LoadK(); stack.GetWithNotifyTop(iA + frameBase) = Unsafe.Add(ref constHead, instruction.Bx); continue; case OpCode.LoadKX: + Markers.LoadKX(); stack.GetWithNotifyTop(iA + frameBase) = Unsafe.Add(ref constHead, Unsafe.Add(ref instructionsHead, ++context.Pc).Ax); continue; case OpCode.LoadBool: + Markers.LoadBool(); stack.GetWithNotifyTop(iA + frameBase) = instruction.B != 0; if (instruction.C != 0) context.Pc++; continue; case OpCode.LoadNil: + Markers.LoadNil(); var ra1 = iA + frameBase + 1; var iB = instruction.B; stack.GetBuffer().Slice(ra1 - 1, iB + 1).Clear(); stack.NotifyTop(ra1 + iB); continue; case OpCode.GetUpVal: + Markers.GetUpVal(); stack.GetWithNotifyTop(iA + frameBase) = context.LuaClosure.GetUpValue(instruction.B); continue; case OpCode.GetTabUp: case OpCode.GetTable: + Markers.GetTabUp(); + Markers.GetTable(); stackHead = ref stack.FastGet(frameBase); ref readonly var vc = ref RKC(ref stackHead, ref constHead, instruction); ref readonly var vb = ref (instruction.OpCode == OpCode.GetTable ? ref Unsafe.Add(ref stackHead, instruction.B) : ref context.LuaClosure.GetUpValueRef(instruction.B)); @@ -379,6 +387,8 @@ static bool MoveNext(VirtualMachineExecutionContext context) return true; case OpCode.SetTabUp: case OpCode.SetTable: + Markers.SetTabUp(); + Markers.SetTable(); stackHead = ref stack.FastGet(frameBase); vb = ref RKB(ref stackHead, ref constHead, instruction); if (vb.TryReadNumber(out var numB)) @@ -411,13 +421,15 @@ static bool MoveNext(VirtualMachineExecutionContext context) return true; case OpCode.SetUpVal: + Markers.SetUpVal(); context.LuaClosure.SetUpValue(instruction.B, stack.FastGet(iA + frameBase)); continue; case OpCode.NewTable: - + Markers.NewTable(); stack.GetWithNotifyTop(iA + frameBase) = new LuaTable(instruction.B, instruction.C); continue; case OpCode.Self: + Markers.Self(); stackHead = ref stack.FastGet(frameBase); vc = ref RKC(ref stackHead, ref constHead, instruction); table = Unsafe.Add(ref stackHead, instruction.B); @@ -439,6 +451,12 @@ static bool MoveNext(VirtualMachineExecutionContext context) case OpCode.Div: case OpCode.Mod: case OpCode.Pow: + Markers.Add(); + Markers.Sub(); + Markers.Mul(); + Markers.Div(); + Markers.Mod(); + Markers.Pow(); stackHead = ref stack.FastGet(frameBase); vb = ref RKB(ref stackHead, ref constHead, instruction); vc = ref RKC(ref stackHead, ref constHead, instruction); @@ -492,6 +510,7 @@ static double ArithmeticOperation(OpCode code, double a, double b) return true; case OpCode.Unm: + Markers.Unm(); stackHead = ref stack.FastGet(frameBase); vb = ref Unsafe.Add(ref stackHead, instruction.B); @@ -511,12 +530,14 @@ static double ArithmeticOperation(OpCode code, double a, double b) return true; case OpCode.Not: + Markers.Not(); stackHead = ref stack.FastGet(frameBase); Unsafe.Add(ref stackHead, iA) = !Unsafe.Add(ref stackHead, instruction.B).ToBoolean(); stack.NotifyTop(iA + frameBase + 1); continue; case OpCode.Len: + Markers.Len(); stackHead = ref stack.FastGet(frameBase); vb = ref Unsafe.Add(ref stackHead, instruction.B); @@ -536,6 +557,7 @@ static double ArithmeticOperation(OpCode code, double a, double b) return true; case OpCode.Concat: + Markers.Concat(); if (Concat(context)) { //if (doRestart) goto Restart; @@ -544,6 +566,7 @@ static double ArithmeticOperation(OpCode code, double a, double b) return true; case OpCode.Jmp: + Markers.Jmp(); context.Pc += instruction.SBx; if (iA != 0) @@ -553,6 +576,7 @@ static double ArithmeticOperation(OpCode code, double a, double b) continue; case OpCode.Eq: + Markers.Eq(); stackHead = ref stack.Get(frameBase); vb = ref RKB(ref stackHead, ref constHead, instruction); vc = ref RKC(ref stackHead, ref constHead, instruction); @@ -575,6 +599,8 @@ static double ArithmeticOperation(OpCode code, double a, double b) return true; case OpCode.Lt: case OpCode.Le: + Markers.Lt(); + Markers.Le(); stackHead = ref stack.Get(frameBase); vb = ref RKB(ref stackHead, ref constHead, instruction); vc = ref RKC(ref stackHead, ref constHead, instruction); @@ -610,6 +636,7 @@ static double ArithmeticOperation(OpCode code, double a, double b) return true; case OpCode.Test: + Markers.Test(); if (stack.Get(iA + frameBase).ToBoolean() != (instruction.C == 1)) { context.Pc++; @@ -617,6 +644,7 @@ static double ArithmeticOperation(OpCode code, double a, double b) continue; case OpCode.TestSet: + Markers.TestSet(); vb = ref stack.Get(instruction.B + frameBase); if (vb.ToBoolean() != (instruction.C == 1)) { @@ -630,6 +658,7 @@ static double ArithmeticOperation(OpCode code, double a, double b) continue; case OpCode.Call: + Markers.Call(); if (Call(context, out doRestart)) { if (doRestart) @@ -642,6 +671,7 @@ static double ArithmeticOperation(OpCode code, double a, double b) return true; case OpCode.TailCall: + Markers.TailCall(); if (TailCall(context, out doRestart)) { if (doRestart) goto Restart; @@ -651,6 +681,7 @@ static double ArithmeticOperation(OpCode code, double a, double b) return true; case OpCode.Return: + Markers.Return(); context.State.CloseUpValues(context.Thread, frameBase); if (context.Pop(instruction, frameBase)) { @@ -659,6 +690,7 @@ static double ArithmeticOperation(OpCode code, double a, double b) goto End; case OpCode.ForLoop: + Markers.ForLoop(); ref var indexRef = ref stack.Get(iA + frameBase); var limit = Unsafe.Add(ref indexRef, 1).UnsafeReadDouble(); var step = Unsafe.Add(ref indexRef, 2).UnsafeReadDouble(); @@ -676,6 +708,7 @@ static double ArithmeticOperation(OpCode code, double a, double b) stack.NotifyTop(iA + frameBase + 1); continue; case OpCode.ForPrep: + Markers.ForPrep(); indexRef = ref stack.Get(iA + frameBase); if (!indexRef.TryReadDouble(out var init)) @@ -701,6 +734,7 @@ static double ArithmeticOperation(OpCode code, double a, double b) context.Pc += instruction.SBx; continue; case OpCode.TForCall: + Markers.TForCall(); if (TForCall(context, out doRestart)) { if (doRestart) goto Restart; @@ -709,6 +743,7 @@ static double ArithmeticOperation(OpCode code, double a, double b) return true; case OpCode.TForLoop: + Markers.TForLoop(); ref var forState = ref stack.Get(iA + frameBase + 1); if (forState.Type is not LuaValueType.Nil) @@ -719,15 +754,18 @@ static double ArithmeticOperation(OpCode code, double a, double b) continue; case OpCode.SetList: + Markers.SetList(); SetList(context); continue; case OpCode.Closure: + Markers.Closure(); ra1 = iA + frameBase + 1; stack.EnsureCapacity(ra1); stack.Get(ra1 - 1) = new LuaClosure(context.Thread, context.Prototype.ChildPrototypes[instruction.Bx]); stack.NotifyTop(ra1); continue; case OpCode.VarArg: + Markers.VarArg(); VarArg(context); static void VarArg(VirtualMachineExecutionContext context)