Repository: neo-project/neo-vm
Branch: master
Commit: 9af8dbd56c8f
Files: 270
Total size: 1.4 MB
Directory structure:
gitextract_7tmmrk3b/
├── .editorconfig
├── .github/
│ └── workflows/
│ └── main.yml
├── .gitignore
├── LICENSE
├── README.md
├── benchmarks/
│ └── Neo.VM.Benchmarks/
│ ├── Benchmarks.POC.cs
│ ├── Benchmarks_VMHotPaths.cs
│ ├── Builders/
│ │ ├── Helper.cs
│ │ ├── Instruction.cs
│ │ ├── InstructionBuilder.cs
│ │ └── JumpTarget.cs
│ ├── Neo.VM.Benchmarks.csproj
│ ├── OpCodes/
│ │ ├── Arrays/
│ │ │ └── OpCode.ReverseN.cs
│ │ ├── Benchmark.Opcode.cs
│ │ ├── BenchmarkEngine.cs
│ │ ├── BenchmarkMode.cs
│ │ ├── Benchmarks_StackOps.cs
│ │ └── OpCodeBase.cs
│ ├── Program.cs
│ ├── TestArray.cs
│ ├── TestStruct.cs
│ └── VMTypes/
│ ├── Benchmarks_Convert.cs
│ └── Benchmarks_DeepCopy.cs
├── neo-vm.sln
├── src/
│ └── Neo.VM/
│ ├── BadScriptException.cs
│ ├── CatchableException.cs
│ ├── Collections/
│ │ └── OrderedDictionary.cs
│ ├── Debugger.cs
│ ├── EvaluationStack.cs
│ ├── ExceptionHandlingContext.cs
│ ├── ExceptionHandlingState.cs
│ ├── ExecutionContext.SharedStates.cs
│ ├── ExecutionContext.cs
│ ├── ExecutionEngine.cs
│ ├── ExecutionEngineLimits.cs
│ ├── IReferenceCounter.cs
│ ├── Instruction.cs
│ ├── IsExternalInit.cs
│ ├── JumpTable/
│ │ ├── JumpTable.Bitwisee.cs
│ │ ├── JumpTable.Compound.cs
│ │ ├── JumpTable.Control.cs
│ │ ├── JumpTable.Numeric.cs
│ │ ├── JumpTable.Push.cs
│ │ ├── JumpTable.Slot.cs
│ │ ├── JumpTable.Splice.cs
│ │ ├── JumpTable.Stack.cs
│ │ ├── JumpTable.Types.cs
│ │ └── JumpTable.cs
│ ├── Neo.VM.csproj
│ ├── OpCode.cs
│ ├── OperandSizeAttribute.cs
│ ├── RCVersion.cs
│ ├── ReferenceCounter.cs
│ ├── ReferenceCounterV2.cs
│ ├── ReferenceEqualityComparer.cs
│ ├── Script.cs
│ ├── ScriptBuilder.cs
│ ├── Slot.cs
│ ├── StronglyConnectedComponents/
│ │ └── Tarjan.cs
│ ├── Types/
│ │ ├── Array.cs
│ │ ├── Boolean.cs
│ │ ├── Buffer.cs
│ │ ├── ByteString.cs
│ │ ├── CompoundType.cs
│ │ ├── Integer.cs
│ │ ├── InteropInterface.cs
│ │ ├── Map.cs
│ │ ├── Null.cs
│ │ ├── Pointer.cs
│ │ ├── PrimitiveType.cs
│ │ ├── StackItem.Vertex.cs
│ │ ├── StackItem.cs
│ │ ├── StackItemType.cs
│ │ └── Struct.cs
│ ├── Unsafe.cs
│ ├── Utility.cs
│ ├── VMState.cs
│ └── VMUnhandledException.cs
└── tests/
└── Neo.VM.Tests/
├── Converters/
│ ├── ScriptConverter.cs
│ └── UppercaseEnum.cs
├── Extensions/
│ ├── JsonExtensions.cs
│ └── StringExtensions.cs
├── Helpers/
│ └── RandomHelper.cs
├── Neo.VM.Tests.csproj
├── Properties/
│ └── AssemblyInfo.cs
├── Tests/
│ ├── OpCodes/
│ │ ├── Arithmetic/
│ │ │ ├── GE.json
│ │ │ ├── GT.json
│ │ │ ├── LE.json
│ │ │ ├── LT.json
│ │ │ ├── MODMUL.json
│ │ │ ├── MODPOW.json
│ │ │ ├── NOT.json
│ │ │ ├── NUMEQUAL.json
│ │ │ ├── NUMNOTEQUAL.json
│ │ │ ├── POW.json
│ │ │ ├── SHL.json
│ │ │ ├── SHR.json
│ │ │ ├── SIGN.json
│ │ │ └── SQRT.json
│ │ ├── Arrays/
│ │ │ ├── APPEND.json
│ │ │ ├── CLEARITEMS.json
│ │ │ ├── HASKEY.json
│ │ │ ├── KEYS.json
│ │ │ ├── NEWARRAY.json
│ │ │ ├── NEWARRAY0.json
│ │ │ ├── NEWARRAY_T.json
│ │ │ ├── NEWMAP.json
│ │ │ ├── NEWSTRUCT.json
│ │ │ ├── NEWSTRUCT0.json
│ │ │ ├── PACK.json
│ │ │ ├── PACKMAP.json
│ │ │ ├── PACKSTRUCT.json
│ │ │ ├── PICKITEM.json
│ │ │ ├── POPITEM.json
│ │ │ ├── REMOVE.json
│ │ │ ├── REVERSEITEMS.json
│ │ │ ├── SETITEM.json
│ │ │ ├── SIZE.json
│ │ │ ├── UNPACK.json
│ │ │ └── VALUES.json
│ │ ├── BitwiseLogic/
│ │ │ ├── AND.json
│ │ │ ├── EQUAL.json
│ │ │ ├── INVERT.json
│ │ │ ├── NOTEQUAL.json
│ │ │ ├── OR.json
│ │ │ └── XOR.json
│ │ ├── Control/
│ │ │ ├── ABORT.json
│ │ │ ├── ABORTMSG.json
│ │ │ ├── ASSERT.json
│ │ │ ├── ASSERTMSG.json
│ │ │ ├── CALL.json
│ │ │ ├── CALLA.json
│ │ │ ├── CALL_L.json
│ │ │ ├── JMP.json
│ │ │ ├── JMPEQ.json
│ │ │ ├── JMPEQ_L.json
│ │ │ ├── JMPGE.json
│ │ │ ├── JMPGE_L.json
│ │ │ ├── JMPGT.json
│ │ │ ├── JMPGT_L.json
│ │ │ ├── JMPIF.json
│ │ │ ├── JMPIFNOT.json
│ │ │ ├── JMPIFNOT_L.json
│ │ │ ├── JMPIF_L.json
│ │ │ ├── JMPLE.json
│ │ │ ├── JMPLE_L.json
│ │ │ ├── JMPLT.json
│ │ │ ├── JMPLT_L.json
│ │ │ ├── JMPNE.json
│ │ │ ├── JMPNE_L.json
│ │ │ ├── JMP_L.json
│ │ │ ├── NOP.json
│ │ │ ├── RET.json
│ │ │ ├── SYSCALL.json
│ │ │ ├── THROW.json
│ │ │ ├── TRY_CATCH.json
│ │ │ ├── TRY_CATCH_FINALLY.json
│ │ │ ├── TRY_CATCH_FINALLY10.json
│ │ │ ├── TRY_CATCH_FINALLY2.json
│ │ │ ├── TRY_CATCH_FINALLY3.json
│ │ │ ├── TRY_CATCH_FINALLY4.json
│ │ │ ├── TRY_CATCH_FINALLY5.json
│ │ │ ├── TRY_CATCH_FINALLY6.json
│ │ │ ├── TRY_CATCH_FINALLY7.json
│ │ │ ├── TRY_CATCH_FINALLY8.json
│ │ │ ├── TRY_CATCH_FINALLY9.json
│ │ │ └── TRY_FINALLY.json
│ │ ├── Push/
│ │ │ ├── PUSHA.json
│ │ │ ├── PUSHDATA1.json
│ │ │ ├── PUSHDATA2.json
│ │ │ ├── PUSHDATA4.json
│ │ │ ├── PUSHINT8_to_PUSHINT256.json
│ │ │ ├── PUSHM1_to_PUSH16.json
│ │ │ └── PUSHNULL.json
│ │ ├── Slot/
│ │ │ ├── INITSLOT.json
│ │ │ ├── INITSSLOT.json
│ │ │ ├── LDARG.json
│ │ │ ├── LDARG0.json
│ │ │ ├── LDARG1.json
│ │ │ ├── LDARG2.json
│ │ │ ├── LDARG3.json
│ │ │ ├── LDARG4.json
│ │ │ ├── LDARG5.json
│ │ │ ├── LDARG6.json
│ │ │ ├── LDLOC.json
│ │ │ ├── LDLOC0.json
│ │ │ ├── LDLOC1.json
│ │ │ ├── LDLOC2.json
│ │ │ ├── LDLOC3.json
│ │ │ ├── LDLOC4.json
│ │ │ ├── LDLOC5.json
│ │ │ ├── LDLOC6.json
│ │ │ ├── LDSFLD.json
│ │ │ ├── LDSFLD0.json
│ │ │ ├── LDSFLD1.json
│ │ │ ├── LDSFLD2.json
│ │ │ ├── LDSFLD3.json
│ │ │ ├── LDSFLD4.json
│ │ │ ├── LDSFLD5.json
│ │ │ ├── LDSFLD6.json
│ │ │ ├── STARG.json
│ │ │ ├── STARG0.json
│ │ │ ├── STARG1.json
│ │ │ ├── STARG2.json
│ │ │ ├── STARG3.json
│ │ │ ├── STARG4.json
│ │ │ ├── STARG5.json
│ │ │ ├── STARG6.json
│ │ │ ├── STLOC.json
│ │ │ ├── STSFLD.json
│ │ │ ├── STSFLD0.json
│ │ │ ├── STSFLD1.json
│ │ │ ├── STSFLD2.json
│ │ │ ├── STSFLD3.json
│ │ │ ├── STSFLD4.json
│ │ │ ├── STSFLD5.json
│ │ │ └── STSFLD6.json
│ │ ├── Splice/
│ │ │ ├── CAT.json
│ │ │ ├── LEFT.json
│ │ │ ├── MEMCPY.json
│ │ │ ├── NEWBUFFER.json
│ │ │ ├── RIGHT.json
│ │ │ └── SUBSTR.json
│ │ ├── Stack/
│ │ │ ├── CLEAR.json
│ │ │ ├── DEPTH.json
│ │ │ ├── DROP.json
│ │ │ ├── NIP.json
│ │ │ ├── OVER.json
│ │ │ ├── PICK.json
│ │ │ ├── REVERSE3.json
│ │ │ ├── REVERSE4.json
│ │ │ ├── REVERSEN.json
│ │ │ ├── ROLL.json
│ │ │ ├── ROT.json
│ │ │ ├── SWAP.json
│ │ │ ├── TUCK.json
│ │ │ └── XDROP.json
│ │ └── Types/
│ │ ├── CONVERT.json
│ │ ├── ISNULL.json
│ │ └── ISTYPE.json
│ └── Others/
│ ├── Debugger.json
│ ├── Init.json
│ ├── InvocationLimits.json
│ ├── OtherCases.json
│ ├── ScriptLogic.json
│ ├── StackItemLimits.json
│ └── StackLimits.json
├── Types/
│ ├── TestEngine.cs
│ ├── VMUT.cs
│ ├── VMUTActionType.cs
│ ├── VMUTEntry.cs
│ ├── VMUTExecutionContextState.cs
│ ├── VMUTExecutionEngineState.cs
│ ├── VMUTStackItem.cs
│ ├── VMUTStackItemType.cs
│ └── VMUTStep.cs
├── UT_Debugger.cs
├── UT_EvaluationStack.cs
├── UT_ExecutionContext.cs
├── UT_ReferenceCounter.cs
├── UT_ReferenceCounterComprehensive.cs
├── UT_Script.cs
├── UT_ScriptBuilder.cs
├── UT_Slot.cs
├── UT_StackItem.cs
├── UT_Struct.cs
├── UT_Unsafe.cs
├── UT_Utility.cs
├── UT_VMJson.cs
└── VMJsonTestBase.cs
================================================
FILE CONTENTS
================================================
================================================
FILE: .editorconfig
================================================
###############################
# Core EditorConfig Options #
###############################
# dotnet-format requires version 3.1.37601
# dotnet tool update -g dotnet-format
# remember to have: git config --global core.autocrlf false #(which is usually default)
# top-most EditorConfig file
root = true
# Don't use tabs for indentation.
[*]
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
charset = utf-8
end_of_line = lf
# (Please don't specify an indent_size here; that has too many unintended consequences.)
spelling_exclusion_path = SpellingExclusions.dic
# Code files
[*.{cs,csx,vb,vbx}]
indent_size = 4
insert_final_newline = true
trim_trailing_whitespace = true
charset = utf-8
# XML project files
[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
indent_size = 2
# XML config files
[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]
indent_size = 2
# JSON files
[*.json]
indent_size = 2
# Powershell files
[*.ps1]
indent_size = 2
# Shell script files
[*.sh]
end_of_line = lf
indent_size = 2
# YAML files
[*.yml]
end_of_line = lf
indent_size = 2
# Dotnet code style settings:
[*.{cs,vb}]
# Use file-scoped namespace
csharp_style_namespace_declarations = file_scoped:warning
# Member can be made 'readonly'
csharp_style_prefer_readonly_struct_member = true
dotnet_diagnostic.IDE0251.severity = warning
dotnet_diagnostic.CS1591.severity = silent
// Use primary constructor
csharp_style_prefer_primary_constructors = false
# Sort using and Import directives with System.* appearing first
dotnet_sort_system_directives_first = false
dotnet_separate_import_directive_groups = false
# Avoid "this." and "Me." if not necessary
dotnet_style_qualification_for_field = false:warning
dotnet_style_qualification_for_property = false:warning
dotnet_style_qualification_for_method = false:warning
dotnet_style_qualification_for_event = false:warning
# Use language keywords instead of framework type names for type references
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
dotnet_style_predefined_type_for_member_access = true:suggestion
# Suggest more modern language features when available
dotnet_style_object_initializer = true:warning
dotnet_style_collection_initializer = true:warning
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_null_propagation = true:suggestion
dotnet_style_explicit_tuple_names = true:suggestion
dotnet_style_prefer_collection_expression = never
# Whitespace options
dotnet_style_allow_multiple_blank_lines_experimental = false
# Non-private static fields are PascalCase
dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.symbols = non_private_static_fields
dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.style = non_private_static_field_style
dotnet_naming_symbols.non_private_static_fields.applicable_kinds = field
dotnet_naming_symbols.non_private_static_fields.applicable_accessibilities = public, protected, internal, protected_internal, private_protected
dotnet_naming_symbols.non_private_static_fields.required_modifiers = static
dotnet_naming_style.non_private_static_field_style.capitalization = pascal_case
# Non-private readonly fields are PascalCase
dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.symbols = non_private_readonly_fields
dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.style = non_private_readonly_field_style
dotnet_naming_symbols.non_private_readonly_fields.applicable_kinds = field
dotnet_naming_symbols.non_private_readonly_fields.applicable_accessibilities = public, protected, internal, protected_internal, private_protected
dotnet_naming_symbols.non_private_readonly_fields.required_modifiers = readonly
dotnet_naming_style.non_private_readonly_field_style.capitalization = pascal_case
# Local functions are PascalCase
dotnet_naming_rule.local_functions_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.local_functions_should_be_pascal_case.symbols = local_functions
dotnet_naming_rule.local_functions_should_be_pascal_case.style = local_function_style
dotnet_naming_symbols.local_functions.applicable_kinds = local_function
dotnet_naming_style.local_function_style.capitalization = pascal_case
file_header_template = Copyright (C) 2015-2026 The Neo Project.\n\n{fileName} file belongs to the neo project and is free\nsoftware distributed under the MIT software license, see the\naccompanying file LICENSE in the main directory of the\nrepository or http://www.opensource.org/licenses/mit-license.php\nfor more details.\n\nRedistribution and use in source and binary forms with or without\nmodifications are permitted.
# Require file header
dotnet_diagnostic.IDE0073.severity = warning
# RS0016: Only enable if API files are present
dotnet_public_api_analyzer.require_api_files = true
# IDE0055: Fix formatting
# Workaround for https://github.com/dotnet/roslyn/issues/70570
dotnet_diagnostic.IDE0055.severity = warning
# CSharp code style settings:
[*.cs]
# Newline settings
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_between_query_expression_clauses = true
# Indentation preferences
csharp_indent_block_contents = true
csharp_indent_braces = false
csharp_indent_case_contents = true
csharp_indent_case_contents_when_block = true
csharp_indent_switch_labels = true
csharp_indent_labels = flush_left
# Whitespace options
csharp_style_allow_embedded_statements_on_same_line_experimental = false
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = false
csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = false
csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = false
# Prefer method-like constructs to have a block body
csharp_style_expression_bodied_methods = false:none
csharp_style_expression_bodied_constructors = false:none
csharp_style_expression_bodied_operators = false:none
# Prefer property-like constructs to have an expression-body
csharp_style_expression_bodied_properties = true:none
csharp_style_expression_bodied_indexers = true:none
csharp_style_expression_bodied_accessors = true:none
# IDE0230: Use UTF-8 string literal
csharp_style_prefer_utf8_string_literals = true:silent
# Suggest more modern language features when available
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
csharp_style_inlined_variable_declaration = true:suggestion
csharp_style_throw_expression = true:suggestion
csharp_style_conditional_delegate_call = true:suggestion
csharp_style_prefer_extended_property_pattern = true:suggestion
# Space preferences
csharp_space_after_cast = false
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_after_comma = true
csharp_space_after_dot = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_after_semicolon_in_for_statement = true
csharp_space_around_binary_operators = before_and_after
csharp_space_around_declaration_statements = do_not_ignore
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_before_comma = false
csharp_space_before_dot = false
csharp_space_before_open_square_brackets = false
csharp_space_before_semicolon_in_for_statement = false
csharp_space_between_empty_square_brackets = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_declaration_name_and_open_parenthesis = false
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_parentheses = false
csharp_space_between_square_brackets = false
# Blocks are allowed
csharp_prefer_braces = true:silent
csharp_preserve_single_line_blocks = true
csharp_preserve_single_line_statements = true
# IDE0060: Remove unused parameter
dotnet_diagnostic.IDE0060.severity = none
[src/{Analyzers,CodeStyle,Features,Workspaces,EditorFeatures,VisualStudio}/**/*.{cs,vb}]
# Avoid "this." and "Me." if not necessary
dotnet_diagnostic.IDE0003.severity = warning
dotnet_diagnostic.IDE0009.severity = warning
# IDE0011: Add braces
csharp_prefer_braces = when_multiline:warning
# NOTE: We need the below severity entry for Add Braces due to https://github.com/dotnet/roslyn/issues/44201
dotnet_diagnostic.IDE0011.severity = warning
# IDE0040: Add accessibility modifiers
dotnet_diagnostic.IDE0040.severity = warning
# IDE0052: Remove unread private member
dotnet_diagnostic.IDE0052.severity = warning
# IDE0059: Unnecessary assignment to a value
dotnet_diagnostic.IDE0059.severity = warning
# Use collection expression for array
dotnet_diagnostic.IDE0300.severity = warning
# CA1012: Abstract types should not have public constructors
dotnet_diagnostic.CA1012.severity = warning
# CA1822: Make member static
dotnet_diagnostic.CA1822.severity = warning
# csharp_style_allow_embedded_statements_on_same_line_experimental
dotnet_diagnostic.IDE2001.severity = warning
# csharp_style_allow_blank_lines_between_consecutive_braces_experimental
dotnet_diagnostic.IDE2002.severity = warning
# csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental
dotnet_diagnostic.IDE2004.severity = warning
# csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental
dotnet_diagnostic.IDE2005.severity = warning
# csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental
dotnet_diagnostic.IDE2006.severity = warning
[src/{VisualStudio}/**/*.{cs,vb}]
# CA1822: Make member static
# There is a risk of accidentally breaking an internal API that partners rely on though IVT.
dotnet_code_quality.CA1822.api_surface = private
================================================
FILE: .github/workflows/main.yml
================================================
name: .NET Core Test and Publish
on:
push:
branches: [master]
pull_request:
env:
DOTNET_VERSION: 10.0.x
jobs:
Test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Setup .NET Core
uses: actions/setup-dotnet@v5
with:
dotnet-version: |
${{ env.DOTNET_VERSION }}
- name: Check format
run: |
dotnet format --verify-no-changes --verbosity diagnostic
- name: Test
run: |
find tests -name *.csproj | xargs -I % dotnet add % package coverlet.msbuild
dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=lcov /p:CoverletOutput=${GITHUB_WORKSPACE}/coverage/lcov
- name: Codecov
uses: codecov/codecov-action@v6
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ${{ github.workspace }}/TestResults/coverage/coverage.info
fail_ci_if_error: false
PublishMyGet:
if: github.ref == 'refs/heads/master' && startsWith(github.repository, 'neo-project/')
needs: Test
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Setup .NET Core
uses: actions/setup-dotnet@v5
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
- name: Pack with dotnet
run: git rev-list --count HEAD |xargs printf "CI%05d" |xargs dotnet pack -c Debug -o out --include-source --version-suffix
- name: Publish to MyGet
run: dotnet nuget push out/*.nupkg -s https://www.myget.org/F/neo/api/v2/package -k ${MYGET_TOKEN} -ss https://www.myget.org/F/neo/symbols/api/v2/package -sk ${MYGET_TOKEN}
env:
MYGET_TOKEN: ${{ secrets.MYGET_TOKEN }}
Release:
if: github.ref == 'refs/heads/master' && startsWith(github.repository, 'neo-project/')
needs: Test
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Get version
id: get_version
run: |
sudo apt install xmlstarlet
find src -name *.csproj | xargs xmlstarlet sel -t -v "concat('version=v',//Version/text())" | xargs echo >> $GITHUB_OUTPUT
- name: Check tag
if: steps.get_version.outputs.version != 'v' && startsWith(steps.get_version.outputs.version, 'v')
id: check_tag
run: curl -s -I ${{ format('https://github.com/{0}/releases/tag/{1}', github.repository, steps.get_version.outputs.version) }} | head -n 1 | cut -d$' ' -f2 | xargs printf "statusCode=%s" | xargs echo >> $GITHUB_OUTPUT
- name: Create release
if: steps.check_tag.outputs.statusCode == '404'
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ steps.get_version.outputs.version }}
release_name: ${{ steps.get_version.outputs.version }}
prerelease: ${{ contains(steps.get_version.outputs.version, '-') }}
- name: Setup .NET Core
if: steps.check_tag.outputs.statusCode == '404'
uses: actions/setup-dotnet@v5
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
- name: Publish to NuGet
if: steps.check_tag.outputs.statusCode == '404'
run: |
dotnet pack -o out -c Release
dotnet nuget push out/*.nupkg -s https://api.nuget.org/v3/index.json -k ${NUGET_TOKEN}
env:
NUGET_TOKEN: ${{ secrets.NUGET_TOKEN }}
================================================
FILE: .gitignore
================================================
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015 cache/options directory
.vs/
# Git worktrees (project-local)
.worktrees/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.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
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# 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
# TODO: 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
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.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
# 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
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# 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
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# 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/
# JetBrains Rider
.idea/
*.sln.iml
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2016
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# NeoVM — The NEO Virtual Machine
[](https://www.nuget.org/packages/Neo.VM/)
[](https://coveralls.io/github/neo-project/neo-vm)
[](LICENSE)
NeoVM is the lightweight, deterministic, stack-based virtual machine that executes Neo smart contracts. It’s designed to be embeddable, predictable, and portable across platforms. For an overview and deep dives (architecture, stacks, instruction set), see the official developer docs. ([NEO Developer Resource](https://developers.neo.org/docs/n3/foundation/neovm))
---
## Features
* **Deterministic & Turing-complete** execution for smart contracts.
* **Small, embeddable runtime** suitable for host applications beyond the Neo blockchain.
* **Clear isolation boundary**: external effects are provided by the host via an interop/syscall layer (e.g., ApplicationEngine in Neo).
* **Rich instruction set** (control flow, stacks, arithmetic, crypto, data structures).
---
## Packages
The VM is published as a NuGet package:
```
dotnet add package Neo.VM
```
This adds the VM to your project; you can then embed and drive it from your host application.
Targets **.NET 10.0** and **.NET Standard 2.1** (compatible with a wide range of runtimes).
---
## Contributing
Contributions are welcome! Typical flow:
1. Fork the repo and create a feature branch.
2. Make changes with tests (`tests/Neo.VM.Tests`).
3. Ensure `dotnet test` passes and follow standard C# conventions.
4. Open a pull request with a clear description and rationale.
---
## See also
* **neo (core library)** — base classes, ledger, P2P, IO. ([Github](https://github.com/neo-project/neo))
* **neo-devpack-dotnet** — C# → NeoVM compiler and developer toolkit. ([Github](https://github.com/neo-project/neo-devpack-dotnet))
================================================
FILE: benchmarks/Neo.VM.Benchmarks/Benchmarks.POC.cs
================================================
// Copyright (C) 2015-2026 The Neo Project.
//
// Benchmarks.POC.cs file belongs to the neo project and is free
// software distributed under the MIT software license, see the
// accompanying file LICENSE in the main directory of the
// repository or http://www.opensource.org/licenses/mit-license.php
// for more details.
//
// Redistribution and use in source and binary forms with or without
// modifications are permitted.
using BenchmarkDotNet.Attributes;
using System.Diagnostics;
namespace Neo.VM.Benchmarks;
public class Benchmarks_PoCs
{
[Benchmark]
public static void NeoIssue2528()
{
// https://github.com/neo-project/neo/issues/2528
// L01: INITSLOT 1, 0
// L02: NEWARRAY0
// L03: DUP
// L04: DUP
// L05: PUSHINT16 2043
// L06: STLOC 0
// L07: PUSH1
// L08: PACK
// L09: LDLOC 0
// L10: DEC
// L11: STLOC 0
// L12: LDLOC 0
// L13: JMPIF_L L07
// L14: PUSH1
// L15: PACK
// L16: APPEND
// L17: PUSHINT32 38000
// L18: STLOC 0
// L19: PUSH0
// L20: PICKITEM
// L21: LDLOC 0
// L22: DEC
// L23: STLOC 0
// L24: LDLOC 0
// L25: JMPIF_L L19
// L26: DROP
Run("VwEAwkpKAfsHdwARwG8AnXcAbwAl9////xHAzwJwlAAAdwAQzm8AnXcAbwAl9////0U=");
}
[Benchmark]
public static void NeoVMIssue418()
{
// https://github.com/neo-project/neo-vm/issues/418
// L00: NEWARRAY0
// L01: PUSH0
// L02: PICK
// L03: PUSH1
// L04: PACK
// L05: PUSH1
// L06: PICK
// L07: PUSH1
// L08: PACK
// L09: INITSSLOT 1
// L10: PUSHINT16 510
// L11: DEC
// L12: STSFLD0
// L13: PUSH1
// L14: PICK
// L15: PUSH1
// L16: PICK
// L17: PUSH2
// L18: PACK
// L19: REVERSE3
// L20: PUSH2
// L21: PACK
// L22: LDSFLD0
// L23: DUP
// L24: JMPIF L11
// L25: DROP
// L26: ROT
// L27: DROP
Run("whBNEcARTRHAVgEB/gGdYBFNEU0SwFMSwFhKJPNFUUU=");
}
[Benchmark]
public static void NeoIssue2723()
{
// L00: INITSSLOT 1
// L01: PUSHINT32 130000
// L02: STSFLD 0
// L03: PUSHINT32 1048576
// L04: NEWBUFFER
// L05: DROP
// L06: LDSFLD 0
// L07: DEC
// L08: DUP
// L09: STSFLD 0
// L10: JMPIF L03
Run("VgEC0PsBAGcAAgAAEACIRV8AnUpnACTz");
}
// Below are PoCs from issue https://github.com/neo-project/neo/issues/2723 by @dusmart
[Benchmark]
public static void PoC_NewBuffer()
{
// INITSLOT 0100
// PUSHINT32 23000000
// STLOC 00
// PUSHINT32 1048576
// NEWBUFFER
// DROP
// LDLOC 00
// DEC
// STLOC 00
// LDLOC 00
// JMPIF_L f2ffffff
// CLEAR
// RET
Run("VwEAAsDzXgF3AAIAABAAiEVvAJ13AG8AJfL///9JQA==");
}
[Benchmark]
public static void PoC_Cat()
{
// INITSLOT 0100
// PUSHINT32 1048575
// NEWBUFFER
// PUSH1
// NEWBUFFER
// PUSHINT32 133333337
// STLOC 00
// OVER
// OVER
// CAT
// DROP
// LDLOC 00
// DEC
// STLOC 00
// LDLOC 00
// JMPIF_L f5ffffff
// CLEAR
// RET
Run("VwEAAv//DwCIEYgCWYHyB3cAS0uLRW8AnXcAbwAl9f///0lA");
}
[Benchmark]
public static void PoC_Left()
{
// INITSLOT 0100
// PUSHINT32 1048576
// NEWBUFFER
// PUSHINT32 133333337
// STLOC 00
// DUP
// PUSHINT32 1048576
// LEFT
// DROP
// LDLOC 00
// DEC
// STLOC 00
// LDLOC 00
// JMPIF_L f1ffffff
// CLEAR
// RET
Run("VwEAAgAAEACIAlmB8gd3AEoCAAAQAI1FbwCddwBvACXx////SUA=");
}
[Benchmark]
public static void PoC_Right()
{
// INITSLOT 0100
// PUSHINT32 1048576
// NEWBUFFER
// PUSHINT32 133333337
// STLOC 00
// DUP
// PUSHINT32 1048576
// RIGHT
// DROP
// LDLOC 00
// DEC
// STLOC 00
// LDLOC 00
// JMPIF_L f1ffffff
// CLEAR
// RET
Run("VwEAAgAAEACIAlmB8gd3AEoCAAAQAI5FbwCddwBvACXx////SUA=");
}
[Benchmark]
public static void PoC_ReverseN()
{
// INITSLOT 0100
// PUSHINT16 2040
// STLOC 00
// PUSHDATA1 aaabbbbbbbbbcccccccdddddddeeeeeeefffffff
// LDLOC 00
// DEC
// STLOC 00
// LDLOC 00
// JMPIF_L cfffffff
// PUSHINT32 23000000
// STLOC 00
// PUSHINT16 2040
// REVERSEN
// LDLOC 00
// DEC
// STLOC 00
// LDLOC 00
// JMPIF_L f5ffffff
// CLEAR
// RET
Run("VwEAAfgHdwAMKGFhYWJiYmJiYmJiYmNjY2NjY2NkZGRkZGRkZWVlZWVlZWZmZmZmZmZvAJ13AG8AJc////8CwPNeAXcAAfgHVW8AnXcAbwAl9f///0lA");
}
[Benchmark]
public static void PoC_Substr()
{
// INITSLOT 0100
// PUSHINT32 1048576
// NEWBUFFER
// PUSHINT32 133333337
// STLOC 00
// DUP
// PUSH0
// PUSHINT32 1048576
// SUBSTR
// DROP
// LDLOC 00
// DEC
// STLOC 00
// LDLOC 00
// JMPIF_L f0ffffff
// CLEAR
// RET
Run("VwEAAgAAEACIAlmB8gd3AEoQAgAAEACMRW8AnXcAbwAl8P///0lA");
}
[Benchmark]
public static void PoC_NewArray()
{
// INITSLOT 0100
// PUSHINT32 1333333337
// STLOC 00
// PUSHINT16 2040
// NEWARRAY
// DROP
// LDLOC 00
// DEC
// STLOC 00
// LDLOC 00
// JMPIF_L f4ffffff
// RET
Run("VwEAAlkNeU93AAH4B8NFbwCddwBvACX0////QA==");
}
[Benchmark]
public static void PoC_NewStruct()
{
// INITSLOT 0100
// PUSHINT32 1333333337
// STLOC 00
// PUSHINT16 2040
// NEWSTRUCT
// DROP
// LDLOC 00
// DEC
// STLOC 00
// LDLOC 00
// JMPIF_L f4ffffff
// RET
Run("VwEAAlkNeU93AAH4B8ZFbwCddwBvACX0////QA==");
}
[Benchmark]
public static void PoC_Roll()
{
// INITSLOT 0100
// PUSHINT16 2040
// STLOC 00
// PUSHDATA1 aaabbbbbbbbbcccccccdddddddeeeeeeefffffff
// LDLOC 00
// DEC
// STLOC 00
// LDLOC 00
// JMPIF_L cfffffff
// PUSHINT32 23000000
// STLOC 00
// PUSHINT16 2039
// ROLL
// LDLOC 00
// DEC
// STLOC 00
// LDLOC 00
// JMPIF_L f5ffffff
// CLEAR
// RET
Run("VwEAAfgHdwAMKGFhYWJiYmJiYmJiYmNjY2NjY2NkZGRkZGRkZWVlZWVlZWZmZmZmZmZvAJ13AG8AJc////8CwPNeAXcAAfcHUm8AnXcAbwAl9f///0lA");
}
[Benchmark]
public static void PoC_XDrop()
{
// INITSLOT 0100
// PUSHINT16 2040
// STLOC 00
// PUSHDATA1 aaabbbbbbbbbcccccccdddddddeeeeeeefffffff
// LDLOC 00
// DEC
// STLOC 00
// LDLOC 00
// JMPIF_L cfffffff
// PUSHINT32 23000000
// STLOC 00
// PUSHINT16 2039
// XDROP
// DUP
// LDLOC 00
// DEC
// STLOC 00
// LDLOC 00
// JMPIF_L f4ffffff
// CLEAR
// RET
Run("VwEAAfgHdwAMKGFhYWJiYmJiYmJiYmNjY2NjY2NkZGRkZGRkZWVlZWVlZWZmZmZmZmZvAJ13AG8AJc////8CwPNeAXcAAfcHSEpvAJ13AG8AJfT///9JQA==");
}
[Benchmark]
public static void PoC_MemCpy()
{
// INITSLOT 0100
// PUSHINT32 1048576
// NEWBUFFER
// PUSHINT32 1048576
// NEWBUFFER
// PUSHINT32 133333337
// STLOC 00
// OVER
// PUSH0
// PUSH2
// PICK
// PUSH0
// PUSHINT32 1048576
// MEMCPY
// LDLOC 00
// DEC
// STLOC 00
// LDLOC 00
// JMPIF_L eeffffff
// CLEAR
// RET
Run("VwEAAgAAEACIAgAAEACIAlmB8gd3AEsQEk0QAgAAEACJbwCddwBvACXu////SUA=");
}
[Benchmark]
public static void PoC_Unpack()
{
// INITSLOT 0200
// PUSHINT16 1010
// NEWARRAY
// STLOC 01
// PUSHINT32 1333333337
// STLOC 00
// LDLOC 01
// UNPACK
// CLEAR
// LDLOC 00
// DEC
// STLOC 00
// LDLOC 00
// JMPIF_L f5ffffff
// RET
Run("VwIAAfIDw3cBAlkNeU93AG8BwUlvAJ13AG8AJfX///9A");
}
[Benchmark]
public static void PoC_GetScriptContainer()
{
// SYSCALL System.Runtime.GetScriptContainer
// DROP
// JMP fa
Run("QS1RCDBFIvo=");
}
private static void Run(string poc)
{
byte[] script = Convert.FromBase64String(poc);
using ExecutionEngine engine = new();
engine.LoadScript(script);
engine.Execute();
Debug.Assert(engine.State == VMState.HALT);
}
}
================================================
FILE: benchmarks/Neo.VM.Benchmarks/Benchmarks_VMHotPaths.cs
================================================
// Copyright (C) 2015-2026 The Neo Project.
//
// Benchmarks_VMHotPaths.cs file belongs to the neo project and is free
// software distributed under the MIT software license, see the
// accompanying file LICENSE in the main directory of the
// repository or http://www.opensource.org/licenses/mit-license.php
// for more details.
//
// Redistribution and use in source and binary forms with or without
// modifications are permitted.
using BenchmarkDotNet.Attributes;
using Neo.VM.Types;
using System;
using System.Collections.Generic;
using System.Linq;
using VMArray = Neo.VM.Types.Array;
namespace Neo.VM.Benchmarks;
public class Benchmarks_ArrayBuild
{
[Params(1, 8, 32, 256, 1024)]
public int N { get; set; }
private static readonly StackItem Item = StackItem.Null;
[Benchmark]
public VMArray BuildWithListFill()
{
var referenceCounter = new ReferenceCounter();
var items = new List(N);
for (int i = 0; i < N; i++)
items.Add(Item);
return new VMArray(referenceCounter, items);
}
[Benchmark]
public VMArray BuildWithArrayFill()
{
var referenceCounter = new ReferenceCounter();
var itemArray = new StackItem[N];
System.Array.Fill(itemArray, Item);
return new VMArray(referenceCounter, itemArray);
}
}
public class Benchmarks_MapSubItems
{
[Params(1, 8, 32, 256, 1024)]
public int N { get; set; }
private Map _map = null!;
[GlobalSetup]
public void Setup()
{
_map = new Map();
for (int i = 0; i < N; i++)
_map[new Integer(i)] = new Integer(i + 1);
}
[Benchmark]
public int EnumerateYield()
{
int count = 0;
foreach (var _ in SubItemsYield(_map))
count++;
return count;
}
[Benchmark]
public int EnumerateConcat()
{
int count = 0;
foreach (var _ in SubItemsConcat(_map))
count++;
return count;
}
private static IEnumerable SubItemsYield(Map map)
{
foreach (var key in map.Keys)
yield return key;
foreach (var value in map.Values)
yield return value;
}
private static IEnumerable SubItemsConcat(Map map) => map.Keys.Concat(map.Values);
}
public class Benchmarks_ListCopy
{
private const int SourceCount = 4096;
[Params(1, 8, 32, 256, 1024, 2048)]
public int CopyCount { get; set; }
private List _source = null!;
private List _target = null!;
[GlobalSetup]
public void Setup()
{
_source = new List(SourceCount);
for (int i = 0; i < SourceCount; i++)
_source.Add(StackItem.Null);
_target = new List(CopyCount);
}
[Benchmark]
public int AddRangeSkip()
{
_target.Clear();
_target.AddRange(_source.Skip(_source.Count - CopyCount));
return _target.Count;
}
[Benchmark]
public int ManualLoop()
{
_target.Clear();
int start = _source.Count - CopyCount;
for (int i = start; i < _source.Count; i++)
_target.Add(_source[i]);
return _target.Count;
}
}
public class Benchmarks_InstructionAdvance
{
[Params(1024, 4096, 16384)]
public int InstructionCount { get; set; }
private Script _script = null!;
private ExecutionContext _context = null!;
[GlobalSetup]
public void Setup()
{
var bytes = new byte[InstructionCount];
System.Array.Fill(bytes, (byte)OpCode.PUSH0);
_script = new Script(bytes);
_context = new ExecutionContext(_script, 0, new ReferenceCounter());
}
[IterationSetup]
public void IterationSetup()
{
WarmInstructionCache();
_context.InstructionPointer = 0;
}
[Benchmark]
public Instruction? AdvanceWithMoveNext()
{
Instruction? last = null;
while (true)
{
last = _context.CurrentInstruction ?? Instruction.RET;
if (!_context.MoveNext()) break;
}
return last;
}
[Benchmark]
public Instruction? AdvanceWithPointer()
{
Instruction? last = null;
while (true)
{
var current = _context.CurrentInstruction;
if (current is null) break;
last = current;
_context.InstructionPointer += current.Size;
}
return last;
}
private void WarmInstructionCache()
{
while (true)
{
var current = _context.CurrentInstruction;
if (current is null) break;
_context.InstructionPointer += current.Size;
}
}
}
================================================
FILE: benchmarks/Neo.VM.Benchmarks/Builders/Helper.cs
================================================
// Copyright (C) 2015-2026 The Neo Project.
//
// Helper.cs file belongs to the neo project and is free
// software distributed under the MIT software license, see the
// accompanying file LICENSE in the main directory of the
// repository or http://www.opensource.org/licenses/mit-license.php
// for more details.
//
// Redistribution and use in source and binary forms with or without
// modifications are permitted.
using System.Buffers.Binary;
namespace Neo.VM.Benchmarks.Builders;
public static class Helper
{
public static void RebuildOffsets(this IReadOnlyList instructions)
{
var offset = 0;
foreach (var instruction in instructions)
{
instruction._offset = offset;
offset += instruction.Size;
}
}
public static void RebuildOperands(this IReadOnlyList instructions)
{
foreach (var instruction in instructions)
{
if (instruction._target is null) continue;
bool isLong;
if (instruction._opCode >= OpCode.JMP && instruction._opCode <= OpCode.CALL_L)
isLong = (instruction._opCode - OpCode.JMP) % 2 != 0;
else
isLong = instruction._opCode == OpCode.PUSHA || instruction._opCode == OpCode.CALLA || instruction._opCode == OpCode.TRY_L || instruction._opCode == OpCode.ENDTRY_L;
if (instruction._opCode == OpCode.TRY || instruction._opCode == OpCode.TRY_L)
{
var offset1 = instruction._target._instruction?._offset - instruction._offset ?? 0;
var offset2 = instruction._target2!._instruction?._offset - instruction._offset ?? 0;
if (isLong)
{
instruction._operand = new byte[sizeof(int) + sizeof(int)];
BinaryPrimitives.WriteInt32LittleEndian(instruction._operand, offset1);
BinaryPrimitives.WriteInt32LittleEndian(instruction._operand.AsSpan(sizeof(int)), offset2);
}
else
{
instruction._operand = new byte[sizeof(sbyte) + sizeof(sbyte)];
var sbyte1 = checked((sbyte)offset1);
var sbyte2 = checked((sbyte)offset2);
instruction._operand[0] = unchecked((byte)sbyte1);
instruction._operand[1] = unchecked((byte)sbyte2);
}
}
else
{
int offset = instruction._target._instruction!._offset - instruction._offset;
if (isLong)
{
instruction._operand = BitConverter.GetBytes(offset);
}
else
{
var sbyte1 = checked((sbyte)offset);
instruction._operand = [unchecked((byte)sbyte1)];
}
}
}
}
}
================================================
FILE: benchmarks/Neo.VM.Benchmarks/Builders/Instruction.cs
================================================
// Copyright (C) 2015-2026 The Neo Project.
//
// Instruction.cs file belongs to the neo project and is free
// software distributed under the MIT software license, see the
// accompanying file LICENSE in the main directory of the
// repository or http://www.opensource.org/licenses/mit-license.php
// for more details.
//
// Redistribution and use in source and binary forms with or without
// modifications are permitted.
using Microsoft.CodeAnalysis;
using System.Diagnostics;
using System.Reflection;
namespace Neo.VM.Benchmarks.Builders;
[DebuggerDisplay("{_opCode}")]
public class Instruction
{
private static readonly int[] s_operandSizePrefixTable = new int[256];
private static readonly int[] s_operandSizeTable = new int[256];
public OpCode _opCode;
public byte[]? _operand;
public JumpTarget? _target;
public JumpTarget? _target2;
public int _offset;
public int Size
{
get
{
int prefixSize = s_operandSizePrefixTable[(int)_opCode];
return prefixSize > 0
? sizeof(OpCode) + _operand!.Length
: sizeof(OpCode) + s_operandSizeTable[(int)_opCode];
}
}
static Instruction()
{
foreach (var field in typeof(OpCode).GetFields(BindingFlags.Public | BindingFlags.Static))
{
var attribute = field.GetCustomAttribute();
if (attribute is null) continue;
var index = (int)(OpCode)field.GetValue(null)!;
s_operandSizePrefixTable[index] = attribute.SizePrefix;
s_operandSizeTable[index] = attribute.Size;
}
}
public byte[] ToArray()
{
if (_operand is null) return [(byte)_opCode];
return _operand.Prepend((byte)_opCode).ToArray();
}
}
================================================
FILE: benchmarks/Neo.VM.Benchmarks/Builders/InstructionBuilder.cs
================================================
// Copyright (C) 2015-2026 The Neo Project.
//
// InstructionBuilder.cs file belongs to the neo project and is free
// software distributed under the MIT software license, see the
// accompanying file LICENSE in the main directory of the
// repository or http://www.opensource.org/licenses/mit-license.php
// for more details.
//
// Redistribution and use in source and binary forms with or without
// modifications are permitted.
using System.Buffers.Binary;
using System.Numerics;
namespace Neo.VM.Benchmarks.Builders;
internal class InstructionBuilder
{
private readonly List _instructions = new();
public InstructionBuilder() { }
internal Instruction AddInstruction(Instruction instruction)
{
_instructions.Add(instruction);
return instruction;
}
internal Instruction AddInstruction(OpCode opcode)
{
return AddInstruction(new Instruction
{
_opCode = opcode
});
}
internal Instruction Jump(OpCode opcode, JumpTarget target)
{
return AddInstruction(new Instruction
{
_opCode = opcode,
_target = target
});
}
internal void Push(bool value)
{
AddInstruction(value ? OpCode.PUSHT : OpCode.PUSHF);
}
internal Instruction Ret() => AddInstruction(OpCode.RET);
internal Instruction Push(BigInteger number)
{
if (number >= -1 && number <= 16) return AddInstruction(number == -1 ? OpCode.PUSHM1 : OpCode.PUSH0 + (byte)(int)number);
Span buffer = stackalloc byte[32];
if (!number.TryWriteBytes(buffer, out var bytesWritten, isUnsigned: false, isBigEndian: false))
throw new ArgumentOutOfRangeException(nameof(number));
var instruction = bytesWritten switch
{
1 => new Instruction
{
_opCode = OpCode.PUSHINT8,
_operand = PadRight(buffer, bytesWritten, 1, number.Sign < 0).ToArray()
},
2 => new Instruction
{
_opCode = OpCode.PUSHINT16,
_operand = PadRight(buffer, bytesWritten, 2, number.Sign < 0).ToArray()
},
<= 4 => new Instruction
{
_opCode = OpCode.PUSHINT32,
_operand = PadRight(buffer, bytesWritten, 4, number.Sign < 0).ToArray()
},
<= 8 => new Instruction
{
_opCode = OpCode.PUSHINT64,
_operand = PadRight(buffer, bytesWritten, 8, number.Sign < 0).ToArray()
},
<= 16 => new Instruction
{
_opCode = OpCode.PUSHINT128,
_operand = PadRight(buffer, bytesWritten, 16, number.Sign < 0).ToArray()
},
<= 32 => new Instruction
{
_opCode = OpCode.PUSHINT256,
_operand = PadRight(buffer, bytesWritten, 32, number.Sign < 0).ToArray()
},
_ => throw new ArgumentOutOfRangeException($"Number too large: {bytesWritten}")
};
AddInstruction(instruction);
return instruction;
}
internal Instruction Push(string s)
{
return Push(s.ToStrictUtf8Bytes());
}
internal Instruction Push(byte[] data)
{
OpCode opcode;
byte[] buffer;
switch (data.Length)
{
case <= byte.MaxValue:
opcode = OpCode.PUSHDATA1;
buffer = new byte[sizeof(byte) + data.Length];
buffer[0] = (byte)data.Length;
Buffer.BlockCopy(data, 0, buffer, sizeof(byte), data.Length);
break;
case <= ushort.MaxValue:
opcode = OpCode.PUSHDATA2;
buffer = new byte[sizeof(ushort) + data.Length];
BinaryPrimitives.WriteUInt16LittleEndian(buffer, (ushort)data.Length);
Buffer.BlockCopy(data, 0, buffer, sizeof(ushort), data.Length);
break;
default:
opcode = OpCode.PUSHDATA4;
buffer = new byte[sizeof(uint) + data.Length];
BinaryPrimitives.WriteUInt32LittleEndian(buffer, (uint)data.Length);
Buffer.BlockCopy(data, 0, buffer, sizeof(uint), data.Length);
break;
}
return AddInstruction(new Instruction
{
_opCode = opcode,
_operand = buffer
});
}
internal void Push(object? obj)
{
switch (obj)
{
case bool data:
Push(data);
break;
case byte[] data:
Push(data);
break;
case string data:
Push(data);
break;
case BigInteger data:
Push(data);
break;
case char data:
Push((ushort)data);
break;
case sbyte data:
Push(data);
break;
case byte data:
Push(data);
break;
case short data:
Push(data);
break;
case ushort data:
Push(data);
break;
case int data:
Push(data);
break;
case uint data:
Push(data);
break;
case long data:
Push(data);
break;
case ulong data:
Push(data);
break;
case Enum data:
Push(BigInteger.Parse(data.ToString("d")));
break;
case null:
AddInstruction(OpCode.PUSHNULL);
break;
default:
throw new NotSupportedException($"Unsupported constant value: {obj}");
}
}
// Helper method to reverse stack items
internal void ReverseStackItems(int count)
{
switch (count)
{
case 2:
AddInstruction(OpCode.SWAP);
break;
case 3:
AddInstruction(OpCode.REVERSE3);
break;
case 4:
AddInstruction(OpCode.REVERSE4);
break;
default:
Push(count);
AddInstruction(OpCode.REVERSEN);
break;
}
}
internal static ReadOnlySpan PadRight(Span buffer, int dataLength, int padLength, bool negative)
{
byte pad = negative ? (byte)0xff : (byte)0;
for (int x = dataLength; x < padLength; x++)
buffer[x] = pad;
return buffer[..padLength];
}
internal Instruction IsType(Types.StackItemType type)
{
return AddInstruction(new Instruction
{
_opCode = OpCode.ISTYPE,
_operand = [(byte)type]
});
}
internal Instruction ChangeType(Types.StackItemType type)
{
return AddInstruction(new Instruction
{
_opCode = OpCode.CONVERT,
_operand = [(byte)type]
});
}
internal byte[] ToArray()
{
var instructions = _instructions.ToArray();
instructions.RebuildOffsets();
instructions.RebuildOperands();
return instructions.Select(p => p.ToArray()).SelectMany(p => p).ToArray();
}
}
================================================
FILE: benchmarks/Neo.VM.Benchmarks/Builders/JumpTarget.cs
================================================
// Copyright (C) 2015-2026 The Neo Project.
//
// JumpTarget.cs file belongs to the neo project and is free
// software distributed under the MIT software license, see the
// accompanying file LICENSE in the main directory of the
// repository or http://www.opensource.org/licenses/mit-license.php
// for more details.
//
// Redistribution and use in source and binary forms with or without
// modifications are permitted.
namespace Neo.VM.Benchmarks.Builders;
public class JumpTarget
{
public Instruction? _instruction;
}
================================================
FILE: benchmarks/Neo.VM.Benchmarks/Neo.VM.Benchmarks.csproj
================================================
Exe
net10.0
enable
enable
false
================================================
FILE: benchmarks/Neo.VM.Benchmarks/OpCodes/Arrays/OpCode.ReverseN.cs
================================================
// Copyright (C) 2015-2026 The Neo Project.
//
// OpCode.ReverseN.cs file belongs to the neo project and is free
// software distributed under the MIT software license, see the
// accompanying file LICENSE in the main directory of the
// repository or http://www.opensource.org/licenses/mit-license.php
// for more details.
//
// Redistribution and use in source and binary forms with or without
// modifications are permitted.
using Neo.VM.Benchmarks.Builders;
namespace Neo.VM.Benchmarks.OpCodes.Arrays;
public class OpCode_ReverseN : OpCodeBase
{
protected override byte[] CreateScript(BenchmarkMode benchmarkMode)
{
var builder = new InstructionBuilder();
var initBegin = new JumpTarget();
builder.AddInstruction(new Builders.Instruction { _opCode = OpCode.INITSLOT, _operand = [1, 0] });
builder.Push(ItemCount);
builder.AddInstruction(OpCode.STLOC0);
initBegin._instruction = builder.AddInstruction(OpCode.NOP);
builder.Push(0);
builder.AddInstruction(OpCode.LDLOC0);
builder.AddInstruction(OpCode.DEC);
builder.AddInstruction(OpCode.STLOC0);
builder.AddInstruction(OpCode.LDLOC0);
builder.Jump(OpCode.JMPIF, initBegin);
if (benchmarkMode == BenchmarkMode.BaseLine)
{
return builder.ToArray();
}
builder.Push(ItemCount);
builder.AddInstruction(OpCode.REVERSEN);
if (benchmarkMode == BenchmarkMode.OneGAS)
{
// just keep running until GAS is exhausted
var loopStart = new JumpTarget { _instruction = builder.AddInstruction(OpCode.NOP) };
builder.Push(ItemCount);
builder.AddInstruction(OpCode.REVERSEN);
builder.Jump(OpCode.JMP, loopStart);
}
return builder.ToArray();
}
}
// for 0
// BenchmarkDotNet v0.13.12, Windows 11 (10.0.22631.4249/23H2/2023Update/SunValley3)
// Intel Core i9-14900HX, 1 CPU, 32 logical and 24 physical cores
// .NET SDK 8.0.205
// [Host] : .NET 8.0.5 (8.0.524.21615), X64 RyuJIT AVX2
// DefaultJob : .NET 8.0.5 (8.0.524.21615), X64 RyuJIT AVX2
//
//
// | Method | ItemCount | Mean | Error | StdDev | Median | Ratio | RatioSD |
// |--------------------- |---------- |-----------------:|--------------:|---------------:|-----------------:|----------:|---------:|
// | Bench_ReverseN | 1 | 63.43 us | 0.466 us | 0.518 us | 63.45 us | 0.99 | 0.01 |
// | Bench_OneGasReverseN | 1 | 403,904.11 us | 6,492.511 us | 6,073.099 us | 402,932.40 us | 6,315.67 | 89.44 |
// | Bench_BaseLine | 1 | 63.96 us | 0.763 us | 0.714 us | 63.92 us | 1.00 | 0.00 |
// | | | | | | | | |
// | Bench_ReverseN | 2 | 62.55 us | 0.988 us | 0.924 us | 62.46 us | 0.95 | 0.02 |
// | Bench_OneGasReverseN | 2 | 424,297.10 us | 8,453.137 us | 7,493.486 us | 423,912.90 us | 6,446.21 | 118.35 |
// | Bench_BaseLine | 2 | 65.83 us | 0.845 us | 0.749 us | 65.95 us | 1.00 | 0.00 |
// | | | | | | | | |
// | Bench_ReverseN | 4 | 63.93 us | 0.418 us | 0.371 us | 63.89 us | 0.95 | 0.03 |
// | Bench_OneGasReverseN | 4 | 443,708.92 us | 6,689.013 us | 6,256.907 us | 444,636.60 us | 6,560.69 | 229.86 |
// | Bench_BaseLine | 4 | 67.64 us | 1.281 us | 1.524 us | 67.79 us | 1.00 | 0.00 |
// | | | | | | | | |
// | Bench_ReverseN | 8 | 66.69 us | 0.757 us | 0.671 us | 66.69 us | 1.00 | 0.02 |
// | Bench_OneGasReverseN | 8 | 463,571.38 us | 6,614.687 us | 6,187.382 us | 465,568.00 us | 6,963.59 | 85.80 |
// | Bench_BaseLine | 8 | 66.64 us | 0.870 us | 0.771 us | 66.68 us | 1.00 | 0.00 |
// | | | | | | | | |
// | Bench_ReverseN | 16 | 65.85 us | 0.994 us | 0.929 us | 65.61 us | 0.94 | 0.02 |
// | Bench_OneGasReverseN | 16 | 740,905.55 us | 71,090.901 us | 209,613.127 us | 653,644.75 us | 9,341.86 | 3,092.85 |
// | Bench_BaseLine | 16 | 70.08 us | 1.376 us | 1.638 us | 70.15 us | 1.00 | 0.00 |
// | | | | | | | | |
// | Bench_ReverseN | 32 | 66.47 us | 0.928 us | 2.187 us | 65.77 us | 1.02 | 0.04 |
// | Bench_OneGasReverseN | 32 | 631,596.65 us | 11,060.847 us | 10,346.323 us | 629,654.10 us | 9,360.06 | 221.36 |
// | Bench_BaseLine | 32 | 67.49 us | 0.900 us | 0.842 us | 67.56 us | 1.00 | 0.00 |
// | | | | | | | | |
// | Bench_ReverseN | 64 | 72.21 us | 0.921 us | 0.862 us | 72.05 us | 1.02 | 0.02 |
// | Bench_OneGasReverseN | 64 | 787,570.95 us | 6,915.746 us | 6,468.994 us | 786,778.70 us | 11,090.76 | 177.74 |
// | Bench_BaseLine | 64 | 71.02 us | 0.946 us | 0.884 us | 71.06 us | 1.00 | 0.00 |
// | | | | | | | | |
// | Bench_ReverseN | 128 | 80.17 us | 0.723 us | 0.676 us | 80.19 us | 0.98 | 0.01 |
// | Bench_OneGasReverseN | 128 | 1,134,510.61 us | 14,991.714 us | 14,023.259 us | 1,133,177.90 us | 13,828.61 | 184.58 |
// | Bench_BaseLine | 128 | 81.90 us | 0.623 us | 0.553 us | 81.77 us | 1.00 | 0.00 |
// | | | | | | | | |
// | Bench_ReverseN | 256 | 98.24 us | 1.140 us | 1.067 us | 98.05 us | 0.99 | 0.01 |
// | Bench_OneGasReverseN | 256 | 1,785,906.33 us | 13,785.746 us | 12,895.195 us | 1,788,819.30 us | 18,067.20 | 198.87 |
// | Bench_BaseLine | 256 | 98.85 us | 0.961 us | 0.899 us | 98.95 us | 1.00 | 0.00 |
// | | | | | | | | |
// | Bench_ReverseN | 512 | 136.19 us | 1.614 us | 1.510 us | 136.34 us | 1.02 | 0.02 |
// | Bench_OneGasReverseN | 512 | 3,100,087.41 us | 16,564.249 us | 15,494.209 us | 3,097,066.60 us | 23,209.57 | 381.50 |
// | Bench_BaseLine | 512 | 133.60 us | 2.144 us | 2.006 us | 132.73 us | 1.00 | 0.00 |
// | | | | | | | | |
// | Bench_ReverseN | 1024 | 207.06 us | 2.213 us | 2.070 us | 206.76 us | 1.01 | 0.01 |
// | Bench_OneGasReverseN | 1024 | 5,762,294.72 us | 20,289.404 us | 16,942.572 us | 5,764,133.80 us | 28,109.14 | 349.87 |
// | Bench_BaseLine | 1024 | 205.07 us | 2.360 us | 2.208 us | 205.07 us | 1.00 | 0.00 |
// | | | | | | | | |
// | Bench_ReverseN | 2040 | 345.09 us | 4.271 us | 3.995 us | 345.40 us | 0.97 | 0.01 |
// | Bench_OneGasReverseN | 2040 | 11,005,147.03 us | 37,306.455 us | 33,071.200 us | 11,003,479.70 us | 31,019.36 | 356.02 |
// | Bench_BaseLine | 2040 | 354.62 us | 4.623 us | 4.325 us | 353.32 us | 1.00 | 0.00 |
// for StackItems that has a size of maximum stack size.
// | Method | ItemCount | Mean | Error | StdDev |
// |--------------------- |---------- |----------------:|--------------:|--------------:|
// | Bench_ReverseN | 1 | 104.0 us | 0.77 us | 0.72 us |
// | Bench_OneGasReverseN | 1 | 389,585.4 us | 4,740.18 us | 4,433.96 us |
// | Bench_ReverseN | 2 | 148.3 us | 2.25 us | 2.10 us |
// | Bench_OneGasReverseN | 2 | 417,831.5 us | 6,651.20 us | 6,221.53 us |
// | Bench_ReverseN | 4 | 231.8 us | 3.92 us | 3.67 us |
// | Bench_OneGasReverseN | 4 | 428,442.6 us | 8,034.41 us | 7,515.39 us |
// | Bench_ReverseN | 8 | 387.8 us | 5.23 us | 4.89 us |
// | Bench_OneGasReverseN | 8 | 448,046.9 us | 6,270.18 us | 5,235.89 us |
// | Bench_ReverseN | 16 | 240.0 us | 7.30 us | 21.53 us |
// | Bench_OneGasReverseN | 16 | 522,904.3 us | 7,157.93 us | 6,695.54 us |
// | Bench_ReverseN | 32 | 302.4 us | 9.53 us | 27.79 us |
// | Bench_OneGasReverseN | 32 | 626,536.6 us | 6,629.69 us | 6,201.42 us |
// | Bench_ReverseN | 64 | 1,728.3 us | 34.27 us | 58.19 us |
// | Bench_OneGasReverseN | 64 | 827,284.5 us | 15,943.00 us | 14,913.09 us |
// | Bench_ReverseN | 128 | 3,704.5 us | 73.98 us | 175.82 us |
// | Bench_OneGasReverseN | 128 | 1,125,104.6 us | 10,629.65 us | 9,942.98 us |
// | Bench_ReverseN | 256 | 6,381.1 us | 127.42 us | 290.21 us |
// | Bench_OneGasReverseN | 256 | 1,804,355.7 us | 9,690.50 us | 8,590.37 us |
// | Bench_ReverseN | 512 | 9,485.9 us | 184.52 us | 492.52 us |
// | Bench_OneGasReverseN | 512 | 3,159,411.1 us | 28,901.54 us | 27,034.52 us |
// | Bench_ReverseN | 1024 | 14,125.6 us | 282.51 us | 577.08 us |
// | Bench_OneGasReverseN | 1024 | 5,799,154.5 us | 33,817.93 us | 31,633.31 us |
// | Bench_ReverseN | 2040 | 22,868.0 us | 449.84 us | 929.00 us |
// | Bench_OneGasReverseN | 2040 | 11,100,853.9 us | 159,980.97 us | 141,818.97 us |
================================================
FILE: benchmarks/Neo.VM.Benchmarks/OpCodes/Benchmark.Opcode.cs
================================================
// Copyright (C) 2015-2026 The Neo Project.
//
// Benchmark.Opcode.cs file belongs to the neo project and is free
// software distributed under the MIT software license, see the
// accompanying file LICENSE in the main directory of the
// repository or http://www.opensource.org/licenses/mit-license.php
// for more details.
//
// Redistribution and use in source and binary forms with or without
// modifications are permitted.
namespace Neo.VM.Benchmarks.OpCodes;
public class Benchmark_Opcode
{
internal static readonly long OneGasDatoshi = 1_0000_0000;
public static readonly IReadOnlyDictionary OpCodePrices = new Dictionary
{
[OpCode.PUSHINT8] = 1 << 0,
[OpCode.PUSHINT16] = 1 << 0,
[OpCode.PUSHINT32] = 1 << 0,
[OpCode.PUSHINT64] = 1 << 0,
[OpCode.PUSHINT128] = 1 << 2,
[OpCode.PUSHINT256] = 1 << 2,
[OpCode.PUSHT] = 1 << 0,
[OpCode.PUSHF] = 1 << 0,
[OpCode.PUSHA] = 1 << 2,
[OpCode.PUSHNULL] = 1 << 0,
[OpCode.PUSHDATA1] = 1 << 3,
[OpCode.PUSHDATA2] = 1 << 9,
[OpCode.PUSHDATA4] = 1 << 12,
[OpCode.PUSHM1] = 1 << 0,
[OpCode.PUSH0] = 1 << 0,
[OpCode.PUSH1] = 1 << 0,
[OpCode.PUSH2] = 1 << 0,
[OpCode.PUSH3] = 1 << 0,
[OpCode.PUSH4] = 1 << 0,
[OpCode.PUSH5] = 1 << 0,
[OpCode.PUSH6] = 1 << 0,
[OpCode.PUSH7] = 1 << 0,
[OpCode.PUSH8] = 1 << 0,
[OpCode.PUSH9] = 1 << 0,
[OpCode.PUSH10] = 1 << 0,
[OpCode.PUSH11] = 1 << 0,
[OpCode.PUSH12] = 1 << 0,
[OpCode.PUSH13] = 1 << 0,
[OpCode.PUSH14] = 1 << 0,
[OpCode.PUSH15] = 1 << 0,
[OpCode.PUSH16] = 1 << 0,
[OpCode.NOP] = 1 << 0,
[OpCode.JMP] = 1 << 1,
[OpCode.JMP_L] = 1 << 1,
[OpCode.JMPIF] = 1 << 1,
[OpCode.JMPIF_L] = 1 << 1,
[OpCode.JMPIFNOT] = 1 << 1,
[OpCode.JMPIFNOT_L] = 1 << 1,
[OpCode.JMPEQ] = 1 << 1,
[OpCode.JMPEQ_L] = 1 << 1,
[OpCode.JMPNE] = 1 << 1,
[OpCode.JMPNE_L] = 1 << 1,
[OpCode.JMPGT] = 1 << 1,
[OpCode.JMPGT_L] = 1 << 1,
[OpCode.JMPGE] = 1 << 1,
[OpCode.JMPGE_L] = 1 << 1,
[OpCode.JMPLT] = 1 << 1,
[OpCode.JMPLT_L] = 1 << 1,
[OpCode.JMPLE] = 1 << 1,
[OpCode.JMPLE_L] = 1 << 1,
[OpCode.CALL] = 1 << 9,
[OpCode.CALL_L] = 1 << 9,
[OpCode.CALLA] = 1 << 9,
[OpCode.CALLT] = 1 << 15,
[OpCode.ABORT] = 0,
[OpCode.ABORTMSG] = 0,
[OpCode.ASSERT] = 1 << 0,
[OpCode.ASSERTMSG] = 1 << 0,
[OpCode.THROW] = 1 << 9,
[OpCode.TRY] = 1 << 2,
[OpCode.TRY_L] = 1 << 2,
[OpCode.ENDTRY] = 1 << 2,
[OpCode.ENDTRY_L] = 1 << 2,
[OpCode.ENDFINALLY] = 1 << 2,
[OpCode.RET] = 0,
[OpCode.SYSCALL] = 0,
[OpCode.DEPTH] = 1 << 1,
[OpCode.DROP] = 1 << 1,
[OpCode.NIP] = 1 << 1,
[OpCode.XDROP] = 1 << 4,
[OpCode.CLEAR] = 1 << 4,
[OpCode.DUP] = 1 << 1,
[OpCode.OVER] = 1 << 1,
[OpCode.PICK] = 1 << 1,
[OpCode.TUCK] = 1 << 1,
[OpCode.SWAP] = 1 << 1,
[OpCode.ROT] = 1 << 1,
[OpCode.ROLL] = 1 << 4,
[OpCode.REVERSE3] = 1 << 1,
[OpCode.REVERSE4] = 1 << 1,
[OpCode.REVERSEN] = 1 << 4,
[OpCode.INITSSLOT] = 1 << 4,
[OpCode.INITSLOT] = 1 << 6,
[OpCode.LDSFLD0] = 1 << 1,
[OpCode.LDSFLD1] = 1 << 1,
[OpCode.LDSFLD2] = 1 << 1,
[OpCode.LDSFLD3] = 1 << 1,
[OpCode.LDSFLD4] = 1 << 1,
[OpCode.LDSFLD5] = 1 << 1,
[OpCode.LDSFLD6] = 1 << 1,
[OpCode.LDSFLD] = 1 << 1,
[OpCode.STSFLD0] = 1 << 1,
[OpCode.STSFLD1] = 1 << 1,
[OpCode.STSFLD2] = 1 << 1,
[OpCode.STSFLD3] = 1 << 1,
[OpCode.STSFLD4] = 1 << 1,
[OpCode.STSFLD5] = 1 << 1,
[OpCode.STSFLD6] = 1 << 1,
[OpCode.STSFLD] = 1 << 1,
[OpCode.LDLOC0] = 1 << 1,
[OpCode.LDLOC1] = 1 << 1,
[OpCode.LDLOC2] = 1 << 1,
[OpCode.LDLOC3] = 1 << 1,
[OpCode.LDLOC4] = 1 << 1,
[OpCode.LDLOC5] = 1 << 1,
[OpCode.LDLOC6] = 1 << 1,
[OpCode.LDLOC] = 1 << 1,
[OpCode.STLOC0] = 1 << 1,
[OpCode.STLOC1] = 1 << 1,
[OpCode.STLOC2] = 1 << 1,
[OpCode.STLOC3] = 1 << 1,
[OpCode.STLOC4] = 1 << 1,
[OpCode.STLOC5] = 1 << 1,
[OpCode.STLOC6] = 1 << 1,
[OpCode.STLOC] = 1 << 1,
[OpCode.LDARG0] = 1 << 1,
[OpCode.LDARG1] = 1 << 1,
[OpCode.LDARG2] = 1 << 1,
[OpCode.LDARG3] = 1 << 1,
[OpCode.LDARG4] = 1 << 1,
[OpCode.LDARG5] = 1 << 1,
[OpCode.LDARG6] = 1 << 1,
[OpCode.LDARG] = 1 << 1,
[OpCode.STARG0] = 1 << 1,
[OpCode.STARG1] = 1 << 1,
[OpCode.STARG2] = 1 << 1,
[OpCode.STARG3] = 1 << 1,
[OpCode.STARG4] = 1 << 1,
[OpCode.STARG5] = 1 << 1,
[OpCode.STARG6] = 1 << 1,
[OpCode.STARG] = 1 << 1,
[OpCode.NEWBUFFER] = 1 << 8,
[OpCode.MEMCPY] = 1 << 11,
[OpCode.CAT] = 1 << 11,
[OpCode.SUBSTR] = 1 << 11,
[OpCode.LEFT] = 1 << 11,
[OpCode.RIGHT] = 1 << 11,
[OpCode.INVERT] = 1 << 2,
[OpCode.AND] = 1 << 3,
[OpCode.OR] = 1 << 3,
[OpCode.XOR] = 1 << 3,
[OpCode.EQUAL] = 1 << 5,
[OpCode.NOTEQUAL] = 1 << 5,
[OpCode.SIGN] = 1 << 2,
[OpCode.ABS] = 1 << 2,
[OpCode.NEGATE] = 1 << 2,
[OpCode.INC] = 1 << 2,
[OpCode.DEC] = 1 << 2,
[OpCode.ADD] = 1 << 3,
[OpCode.SUB] = 1 << 3,
[OpCode.MUL] = 1 << 3,
[OpCode.DIV] = 1 << 3,
[OpCode.MOD] = 1 << 3,
[OpCode.POW] = 1 << 6,
[OpCode.SQRT] = 1 << 6,
[OpCode.MODMUL] = 1 << 5,
[OpCode.MODPOW] = 1 << 11,
[OpCode.SHL] = 1 << 3,
[OpCode.SHR] = 1 << 3,
[OpCode.NOT] = 1 << 2,
[OpCode.BOOLAND] = 1 << 3,
[OpCode.BOOLOR] = 1 << 3,
[OpCode.NZ] = 1 << 2,
[OpCode.NUMEQUAL] = 1 << 3,
[OpCode.NUMNOTEQUAL] = 1 << 3,
[OpCode.LT] = 1 << 3,
[OpCode.LE] = 1 << 3,
[OpCode.GT] = 1 << 3,
[OpCode.GE] = 1 << 3,
[OpCode.MIN] = 1 << 3,
[OpCode.MAX] = 1 << 3,
[OpCode.WITHIN] = 1 << 3,
[OpCode.PACKMAP] = 1 << 11,
[OpCode.PACKSTRUCT] = 1 << 11,
[OpCode.PACK] = 1 << 11,
[OpCode.UNPACK] = 1 << 11,
[OpCode.NEWARRAY0] = 1 << 4,
[OpCode.NEWARRAY] = 1 << 9,
[OpCode.NEWARRAY_T] = 1 << 9,
[OpCode.NEWSTRUCT0] = 1 << 4,
[OpCode.NEWSTRUCT] = 1 << 9,
[OpCode.NEWMAP] = 1 << 3,
[OpCode.SIZE] = 1 << 2,
[OpCode.HASKEY] = 1 << 6,
[OpCode.KEYS] = 1 << 4,
[OpCode.VALUES] = 1 << 13,
[OpCode.PICKITEM] = 1 << 6,
[OpCode.APPEND] = 1 << 13,
[OpCode.SETITEM] = 1 << 13,
[OpCode.REVERSEITEMS] = 1 << 13,
[OpCode.REMOVE] = 1 << 4,
[OpCode.CLEARITEMS] = 1 << 4,
[OpCode.POPITEM] = 1 << 4,
[OpCode.ISNULL] = 1 << 1,
[OpCode.ISTYPE] = 1 << 1,
[OpCode.CONVERT] = 1 << 13,
};
internal static void RunScript(byte[] script)
{
LoadScript(script).ExecuteBenchmark();
}
internal static BenchmarkEngine RunScriptUntil(byte[] script, OpCode opCode)
{
return LoadScript(script).ExecuteUntil(opCode);
}
internal static BenchmarkEngine LoadScript(byte[] script)
{
var engine = new BenchmarkEngine();
engine.LoadScript(script);
return engine;
}
}
================================================
FILE: benchmarks/Neo.VM.Benchmarks/OpCodes/BenchmarkEngine.cs
================================================
// Copyright (C) 2015-2026 The Neo Project.
//
// BenchmarkEngine.cs file belongs to the neo project and is free
// software distributed under the MIT software license, see the
// accompanying file LICENSE in the main directory of the
// repository or http://www.opensource.org/licenses/mit-license.php
// for more details.
//
// Redistribution and use in source and binary forms with or without
// modifications are permitted.
using Neo.VM.Types;
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace Neo.VM.Benchmarks.OpCodes;
///
/// A simple benchmark engine for .
///
public class BenchmarkEngine : ExecutionEngine
{
private readonly Dictionary _opcodeStats = new();
private readonly Dictionary