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)