diff --git a/src/Nethermind/Directory.Packages.props b/src/Nethermind/Directory.Packages.props
index 7d129079f0f..095f63255ef 100644
--- a/src/Nethermind/Directory.Packages.props
+++ b/src/Nethermind/Directory.Packages.props
@@ -73,6 +73,7 @@
+
diff --git a/src/Nethermind/Nethermind.Api/IBasicApi.cs b/src/Nethermind/Nethermind.Api/IBasicApi.cs
index d6d8d320ef3..f435bb5c77d 100644
--- a/src/Nethermind/Nethermind.Api/IBasicApi.cs
+++ b/src/Nethermind/Nethermind.Api/IBasicApi.cs
@@ -15,6 +15,7 @@
using Nethermind.Core.Timers;
using Nethermind.Crypto;
using Nethermind.Db;
+using Nethermind.Evm.Config;
using Nethermind.KeyStore;
using Nethermind.Logging;
using Nethermind.Serialization.Json;
@@ -33,6 +34,7 @@ public interface IBasicApi
ICryptoRandom CryptoRandom { get; }
IDbProvider? DbProvider { get; set; }
IDbFactory? DbFactory { get; set; }
+ IVMConfig? VMConfig { get; set; }
IEthereumEcdsa? EthereumEcdsa { get; set; }
IJsonSerializer EthereumJsonSerializer { get; set; }
IFileSystem FileSystem { get; set; }
diff --git a/src/Nethermind/Nethermind.Api/NethermindApi.cs b/src/Nethermind/Nethermind.Api/NethermindApi.cs
index b6a3574c212..9a51a0ee903 100644
--- a/src/Nethermind/Nethermind.Api/NethermindApi.cs
+++ b/src/Nethermind/Nethermind.Api/NethermindApi.cs
@@ -57,6 +57,7 @@
using Nethermind.Wallet;
using Nethermind.Sockets;
using Nethermind.Trie;
+using Nethermind.Evm.Config;
using Nethermind.Consensus.Processing.CensorshipDetector;
using Nethermind.Facade.Find;
@@ -114,6 +115,7 @@ public IBlockchainBridge CreateBlockchainBridge()
}
public IAbiEncoder AbiEncoder { get; } = Nethermind.Abi.AbiEncoder.Instance;
+ public IVMConfig? VMConfig { get; set; }
public IBlobTxStorage? BlobTxStorage { get; set; }
public IBlockchainProcessor? BlockchainProcessor { get; set; }
public CompositeBlockPreprocessorStep BlockPreprocessor { get; } = new();
diff --git a/src/Nethermind/Nethermind.Core/Extensions/IntExtensions.cs b/src/Nethermind/Nethermind.Core/Extensions/IntExtensions.cs
index 71505417f89..0648038ae70 100644
--- a/src/Nethermind/Nethermind.Core/Extensions/IntExtensions.cs
+++ b/src/Nethermind/Nethermind.Core/Extensions/IntExtensions.cs
@@ -9,6 +9,11 @@ namespace Nethermind.Core.Extensions;
public static class IntExtensions
{
+ public static bool HasFlag(this int @this, int flag)
+ {
+ return (@this & flag) == flag;
+ }
+
public static string ToHexString(this int @this)
{
return $"0x{@this:x}";
diff --git a/src/Nethermind/Nethermind.Evm.Test/CodeAnalysis/IlEvmTests.cs b/src/Nethermind/Nethermind.Evm.Test/CodeAnalysis/IlEvmTests.cs
new file mode 100644
index 00000000000..860403c6597
--- /dev/null
+++ b/src/Nethermind/Nethermind.Evm.Test/CodeAnalysis/IlEvmTests.cs
@@ -0,0 +1,2172 @@
+// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using FluentAssertions;
+using Nethermind.Core;
+using Nethermind.Core.Extensions;
+using Nethermind.Core.Specs;
+using Nethermind.Core.Test.Builders;
+using Nethermind.Evm.CodeAnalysis;
+using Nethermind.Evm.CodeAnalysis.IL;
+using Nethermind.Evm.Config;
+using Nethermind.Evm.Tracing;
+using Nethermind.Evm.Tracing.GethStyle;
+using Nethermind.Evm.TransactionProcessing;
+using Nethermind.Int256;
+using Nethermind.Logging;
+using Nethermind.Specs;
+using Nethermind.Specs.Forks;
+using Nethermind.State;
+using Nethermind.Trie;
+using Nethermind.Trie.Pruning;
+using NUnit.Framework;
+using Sigil;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Threading.Tasks;
+using static Nethermind.Evm.CodeAnalysis.IL.IlInfo;
+using static Nethermind.Evm.Tracing.GethStyle.Custom.JavaScript.Log;
+using Nethermind.Evm.CodeAnalysis.IL.Patterns;
+using Nethermind.Core.Crypto;
+using Nethermind.Core.Test.Blockchain;
+using Polly;
+using Nethermind.Core.Collections;
+using Nethermind.Specs.Test;
+using System.Threading;
+using Nethermind.Evm.Tracing.GethStyle.Custom.JavaScript;
+
+namespace Nethermind.Evm.Test.CodeAnalysis
+{
+ internal class AbortDestinationPattern : InstructionChunk // for testing
+ {
+ public string Name => nameof(AbortDestinationPattern);
+ public byte[] Pattern => [(byte)Instruction.JUMPDEST, (byte)Instruction.STOP];
+ public byte CallCount { get; set; } = 0;
+ public long GasCost(EvmState vmState, IReleaseSpec spec)
+ {
+ return GasCostOf.JumpDest;
+ }
+
+ public void Invoke(EvmState vmState, IBlockhashProvider blockhashProvider, IWorldState worldState, ICodeInfoRepository codeInfoRepository, IReleaseSpec spec,
+ ref int programCounter,
+ ref long gasAvailable,
+ ref EvmStack stack,
+ ref ILChunkExecutionResult result) where T : struct, VirtualMachine.IIsTracing
+ {
+ CallCount++;
+
+ if (!VirtualMachine.UpdateGas(GasCost(vmState, spec), ref gasAvailable))
+ result.ExceptionType = EvmExceptionType.OutOfGas;
+
+ programCounter += 2;
+ result.ShouldStop = true;
+ }
+ }
+ internal class SomeAfterTwoPush : InstructionChunk
+ {
+ public string Name => nameof(SomeAfterTwoPush);
+ public byte[] Pattern => [96, 96, 01];
+ public byte CallCount { get; set; } = 0;
+
+ public long GasCost(EvmState vmState, IReleaseSpec spec)
+ {
+ long gasCost = GasCostOf.VeryLow * 3;
+ return gasCost;
+ }
+
+ public void Invoke(EvmState vmState, IBlockhashProvider blockhashProvider, IWorldState worldState, ICodeInfoRepository codeInfoRepository, IReleaseSpec spec,
+ ref int programCounter,
+ ref long gasAvailable,
+ ref EvmStack stack,
+ ref ILChunkExecutionResult result) where T : struct, VirtualMachine.IIsTracing
+ {
+ CallCount++;
+
+ if (!VirtualMachine.UpdateGas(GasCost(vmState, spec), ref gasAvailable))
+ result.ExceptionType = EvmExceptionType.OutOfGas;
+
+ UInt256 lhs = vmState.Env.CodeInfo.MachineCode.Span[programCounter + 1];
+ UInt256 rhs = vmState.Env.CodeInfo.MachineCode.Span[programCounter + 3];
+ stack.PushUInt256(lhs + rhs);
+
+ programCounter += 5;
+ }
+ }
+ internal class TestBlockChain : VirtualMachineTestsBase
+ {
+ protected IVMConfig config;
+ public TestBlockChain(IVMConfig config)
+ {
+ this.config = config;
+ Setup();
+ }
+
+ public TestBlockChain()
+ {
+ config = new VMConfig();
+ Setup();
+ }
+ public override void Setup()
+ {
+ base.Setup();
+
+ ILogManager logManager = GetLogManager();
+
+ _blockhashProvider = new TestBlockhashProvider(SpecProvider);
+ Machine = new VirtualMachine(_blockhashProvider, SpecProvider, CodeInfoRepository, logManager, config);
+ _processor = new TransactionProcessor(SpecProvider, TestState, Machine, CodeInfoRepository, logManager);
+
+ var code = Prepare.EvmCode
+ .PushData(23)
+ .PushData(7)
+ .ADD()
+ .MSTORE(0, Enumerable.Range(0, 32).Select(i => (byte)i).ToArray())
+ .RETURN(0, 32)
+ .STOP().Done;
+ TestState.CreateAccount(Address.FromNumber(23), 1000000);
+ TestState.InsertCode(Address.FromNumber(23), code, SpecProvider.GenesisSpec);
+
+ IlAnalyzer.AddPattern();
+ IlAnalyzer.AddPattern();
+ IlAnalyzer.AddPattern();
+ IlAnalyzer.AddPattern();
+ IlAnalyzer.AddPattern();
+ IlAnalyzer.AddPattern();
+
+ IlAnalyzer.AddPattern();
+ //IlAnalyzer.AddPattern();
+ //IlAnalyzer.AddPattern();
+ IlAnalyzer.AddPattern();
+ IlAnalyzer.AddPattern();
+ IlAnalyzer.AddPattern();
+ IlAnalyzer.AddPattern();
+ IlAnalyzer.AddPattern();
+ IlAnalyzer.AddPattern();
+ IlAnalyzer.AddPattern();
+ IlAnalyzer.AddPattern();
+ IlAnalyzer.AddPattern();
+ IlAnalyzer.AddPattern();
+ }
+
+ public void Execute(byte[] bytecode, T tracer, ForkActivation? fork = null, long gasAvailable = 1_000_000)
+ where T : ITxTracer
+ {
+ Execute(tracer, bytecode, fork ?? MainnetSpecProvider.PragueActivation, gasAvailable);
+ }
+
+ public Address InsertCode(byte[] bytecode)
+ {
+ var hashcode = Keccak.Compute(bytecode);
+ var address = new Address(hashcode);
+
+ var spec = Prague.Instance;
+ TestState.CreateAccount(address, 1_000_000_000);
+ TestState.InsertCode(address, bytecode, spec);
+ return address;
+ }
+ public void ForceRunAnalysis(Address address, int mode)
+ {
+ var codeinfo = CodeInfoRepository.GetCachedCodeInfo(TestState, address, Prague.Instance);
+ var initialILMODE = codeinfo.IlInfo.Mode;
+ if(mode.HasFlag(ILMode.JIT_MODE))
+ {
+ IlAnalyzer.StartAnalysis(codeinfo, ILMode.JIT_MODE, config, NullLogger.Instance);
+ }
+
+ if (mode.HasFlag(ILMode.PAT_MODE))
+ {
+ IlAnalyzer.StartAnalysis(codeinfo, ILMode.PAT_MODE, config, NullLogger.Instance);
+ }
+ }
+
+ public Hash256 StateRoot
+ {
+ get
+ {
+ TestState.Commit(Spec);
+ TestState.RecalculateStateRoot();
+ return TestState.StateRoot;
+ }
+ }
+
+ }
+
+ [TestFixture]
+ [NonParallelizable]
+ internal class IlEvmTests : TestBlockChain
+ {
+ private const string AnalyzerField = "_analyzer";
+ private const string PatternField = "_patterns";
+ private const int RepeatCount = 256;
+
+ [SetUp]
+ public override void Setup()
+ {
+ base.Setup();
+
+ base.config = new VMConfig()
+ {
+ IsJitEnabled = true,
+ IsPatternMatchingEnabled = true,
+ AggressiveJitMode = true,
+ BakeInTracingInJitMode = true,
+
+ PatternMatchingThreshold = 4,
+ JittingThreshold = 256,
+ };
+
+ CodeInfoRepository.ClearCache();
+ }
+
+ public static IEnumerable<(Type, byte[])> GePatBytecodesSamples()
+ {
+
+ yield return (typeof(D01P04EQ), Prepare.EvmCode
+ .PUSHx([1, 2, 3, 4])
+ .DUPx(1)
+ .PUSHx([1, 2, 3, 4])
+ .EQ()
+ .PushData(0x1)
+ .Op(Instruction.SSTORE)
+ .Done);
+ yield return (typeof(D01P04GT), Prepare.EvmCode
+ .PUSHx([1, 2, 3, 4])
+ .DUPx(1)
+ .PUSHx([1, 2, 3, 5])
+ .GT()
+ .PushData(0x1)
+ .Op(Instruction.SSTORE)
+ .Done);
+ yield return (typeof(D02MST), Prepare.EvmCode
+ .PUSHx([1])
+ .PUSHx([3])
+ .PUSHx([3])
+ .POP() //to avooid PUSHxDUPx pattern detection
+ .DUPx(2)
+ .MSTORE()
+ .POP()
+ .MLOAD(1)
+ .PushData(0x1)
+ .Op(Instruction.SSTORE)
+ .Done);
+ yield return (typeof(P01D03), Prepare.EvmCode
+ .PUSHx([5])
+ .PUSHx([1])
+ .PUSHx([3])
+ .DUPx(3)
+ .PushData(0x1)
+ .Op(Instruction.SSTORE)
+ .PushData(0x2)
+ .Op(Instruction.SSTORE)
+ .Done);
+ yield return (typeof(P01D02), Prepare.EvmCode
+ .PUSHx([1])
+ .PUSHx([3])
+ .DUPx(2)
+ .PushData(0x1)
+ .Op(Instruction.SSTORE)
+ .PushData(0x2)
+ .Op(Instruction.SSTORE)
+ .Done);
+ yield return (typeof(S02S01), Prepare.EvmCode
+ .PUSHx([5])
+ .PUSHx([1])
+ .PUSHx([3])
+ .SWAPx(2)
+ .SWAPx(1)
+ .PushData(0x1)
+ .Op(Instruction.SSTORE)
+ .PushData(0x2)
+ .Op(Instruction.SSTORE)
+ .Done);
+ yield return (typeof(S02P), Prepare.EvmCode
+ .PUSHx([5])
+ .PUSHx([1])
+ .PUSHx([3])
+ .SWAPx(2)
+ .POP()
+ .Op(Instruction.SSTORE)
+ .Done);
+ yield return (typeof(S01P), Prepare.EvmCode
+ .PUSHx([2])
+ .PUSHx([3])
+ .SWAPx(1)
+ .POP()
+ .PushData(0x1)
+ .Op(Instruction.SSTORE)
+ .Done);
+ yield return (typeof(PJ), Prepare.EvmCode
+ .PUSHx([23])
+ .PUSHx([13])
+ .PUSHx([9])
+ .POP()
+ .JUMP()
+ .JUMPDEST()
+ .PushSingle(3)
+ .MUL()
+ .STOP()
+ .JUMPDEST()
+ .JUMP(8)
+ .Done);
+ yield return (typeof(P01P01SHL), Prepare.EvmCode
+ .PUSHx([2])
+ .PUSHx([3])
+ .Op(Instruction.SHL)
+ .PushData(0x1)
+ .Op(Instruction.SSTORE)
+ .Done);
+ yield return (typeof(PP), Prepare.EvmCode
+ .PushData(((UInt256)3).PaddedBytes(32))
+ .PushData(((UInt256)4).PaddedBytes(32))
+ .PushData(((UInt256)5).PaddedBytes(32))
+ .POP()
+ .POP()
+ .PushData(0x1)
+ .Op(Instruction.SSTORE)
+ .Done);
+ yield return (typeof(EmulatedStaticCJump), Prepare.EvmCode
+ .PUSHx([1])
+ .PUSHx([0, 8])
+ .JUMPI()
+ .INVALID()
+ .JUMPDEST()
+ .Done);
+ yield return (typeof(EmulatedStaticJump), Prepare.EvmCode
+ .PUSHx([0, 6])
+ .JUMP()
+ .INVALID()
+ .JUMPDEST()
+ .Done);
+ yield return (typeof(MethodSelector), Prepare.EvmCode
+ .PushData(23)
+ .PushData(32)
+ .MSTORE()
+ .CALLVALUE()
+ .DUPx(1)
+ .PushData(32)
+ .MLOAD()
+ .SSTORE()
+ .Done);
+ yield return (typeof(IsContractCheck), Prepare.EvmCode
+ .ADDRESS()
+ .EXTCODESIZE()
+ .DUPx(1)
+ .ISZERO()
+ .SSTORE()
+ .Done);
+ }
+
+ public static IEnumerable<(Instruction?, byte[], EvmExceptionType)> GeJitBytecodesSamples()
+ {
+ yield return (Instruction.PUSH32, Prepare.EvmCode
+ .PushSingle(23)
+ .PushSingle(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.ISZERO, Prepare.EvmCode
+ .ISZERO(7)
+ .PushData(7)
+ .SSTORE()
+ .ISZERO(0)
+ .PushData(1)
+ .SSTORE()
+ .ISZERO(UInt256.MaxValue)
+ .PushData(23)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.SUB, Prepare.EvmCode
+ .PushSingle(23)
+ .PushSingle(7)
+ .SUB()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.ADD, Prepare.EvmCode
+ .PushSingle(23)
+ .PushSingle(7)
+ .ADD()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.ADDMOD, Prepare.EvmCode
+ .PushSingle(23)
+ .PushSingle(7)
+ .PushSingle(5)
+ .ADDMOD()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.MUL, Prepare.EvmCode
+ .PushSingle(23)
+ .PushSingle(7)
+ .MUL()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.EXP, Prepare.EvmCode
+ .PushSingle(0)
+ .PushSingle(7)
+ .EXP()
+ .PushData(2)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.EXP, Prepare.EvmCode
+ .PushSingle(1)
+ .PushSingle(7)
+ .EXP()
+ .PushData(3)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.EXP, Prepare.EvmCode
+ .PushSingle(1)
+ .PushSingle(0)
+ .EXP()
+ .PushData(4)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.EXP, Prepare.EvmCode
+ .PushSingle(1)
+ .PushSingle(1)
+ .EXP()
+ .PushData(5)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.MOD, Prepare.EvmCode
+ .PushSingle(23)
+ .PushSingle(7)
+ .MOD()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.DIV, Prepare.EvmCode
+ .PushSingle(23)
+ .PushSingle(7)
+ .DIV()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.MSTORE | Instruction.MLOAD, Prepare.EvmCode
+ .MSTORE(0, ((UInt256)23).PaddedBytes(32))
+ .MLOAD(0)
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.MSTORE | Instruction.MLOAD, Prepare.EvmCode
+ .MSTORE(123, ((UInt256)23).PaddedBytes(32))
+ .MLOAD(0)
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.MSTORE | Instruction.MLOAD, Prepare.EvmCode
+ .MSTORE(32, ((UInt256)23).PaddedBytes(32))
+ .MLOAD(0)
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.MSTORE | Instruction.MLOAD, Prepare.EvmCode
+ .MSTORE(0, ((UInt256)0).PaddedBytes(32))
+ .MLOAD(0)
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.MSTORE | Instruction.MLOAD, Prepare.EvmCode
+ .MSTORE(123, ((UInt256)0).PaddedBytes(32))
+ .MLOAD(123)
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.MSTORE | Instruction.MLOAD, Prepare.EvmCode
+ .MSTORE(32, ((UInt256)0).PaddedBytes(32))
+ .MLOAD(32)
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.MSTORE8, Prepare.EvmCode
+ .MSTORE8(0, ((UInt256)23).PaddedBytes(32))
+ .MLOAD(0)
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.MSTORE8, Prepare.EvmCode
+ .MSTORE8(123, ((UInt256)23).PaddedBytes(32))
+ .MLOAD(123)
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.MSTORE8, Prepare.EvmCode
+ .MSTORE8(32, ((UInt256)23).PaddedBytes(32))
+ .MLOAD(32)
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.MSTORE8, Prepare.EvmCode
+ .MSTORE8(0, UInt256.MaxValue.PaddedBytes(32))
+ .MLOAD(0)
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.MSTORE8, Prepare.EvmCode
+ .MSTORE8(123, UInt256.MaxValue.PaddedBytes(32))
+ .MLOAD(123)
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.MSTORE8, Prepare.EvmCode
+ .MSTORE8(32, UInt256.MaxValue.PaddedBytes(32))
+ .MLOAD(32)
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.MCOPY, Prepare.EvmCode
+ .MSTORE(0, ((UInt256)23).PaddedBytes(32))
+ .MCOPY(32, 0, 32)
+ .MLOAD(32)
+ .MLOAD(0)
+ .EQ()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.MCOPY, Prepare.EvmCode
+ .MSTORE(123, ((UInt256)23).PaddedBytes(32))
+ .MCOPY(32, 123, 32)
+ .MLOAD(32)
+ .MLOAD(0)
+ .EQ()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.MCOPY, Prepare.EvmCode
+ .MSTORE(32, ((UInt256)23).PaddedBytes(32))
+ .MCOPY(32, 123, 32)
+ .MLOAD(32)
+ .MLOAD(0)
+ .EQ()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.MCOPY, Prepare.EvmCode
+ .MSTORE(0, ((UInt256)0).PaddedBytes(32))
+ .MCOPY(32, 0, 32)
+ .MLOAD(32)
+ .MLOAD(0)
+ .EQ()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.MCOPY, Prepare.EvmCode
+ .MSTORE(123, ((UInt256)0).PaddedBytes(32))
+ .MCOPY(32, 123, 32)
+ .MLOAD(32)
+ .MLOAD(123)
+ .EQ()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.MCOPY, Prepare.EvmCode
+ .MSTORE(32, ((UInt256)0).PaddedBytes(32))
+ .MCOPY(0, 32, 32)
+ .MLOAD(32)
+ .MLOAD(0)
+ .EQ()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.MCOPY, Prepare.EvmCode
+ .MSTORE(32, ((UInt256)0).PaddedBytes(32))
+ .MCOPY(32, 32, 32)
+ .MLOAD(32)
+ .PushSingle((UInt256)0)
+ .EQ()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.MCOPY, Prepare.EvmCode
+ .MSTORE(32, ((UInt256)23).PaddedBytes(32))
+ .MCOPY(32, 32, 32)
+ .MLOAD(32)
+ .PushSingle((UInt256)23)
+ .EQ()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.EQ, Prepare.EvmCode
+ .PushSingle(23)
+ .PushSingle(7)
+ .EQ()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.GT, Prepare.EvmCode
+ .PushSingle(7)
+ .PushSingle(23)
+ .GT()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.GT, Prepare.EvmCode
+ .PushSingle(23)
+ .PushSingle(7)
+ .GT()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.GT, Prepare.EvmCode
+ .PushSingle(17)
+ .PushSingle(17)
+ .GT()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.LT, Prepare.EvmCode
+ .PushSingle(23)
+ .PushSingle(7)
+ .LT()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.LT, Prepare.EvmCode
+ .PushSingle(7)
+ .PushSingle(23)
+ .LT()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.LT, Prepare.EvmCode
+ .PushSingle(17)
+ .PushSingle(17)
+ .LT()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.NOT, Prepare.EvmCode
+ .PushSingle(1)
+ .NOT()
+ .PushData(1)
+ .SSTORE()
+ .PushSingle(0)
+ .NOT()
+ .PushData(1)
+ .SSTORE()
+ .PushSingle(UInt256.MaxValue)
+ .NOT()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.BLOBHASH, Prepare.EvmCode
+ .PushSingle(0)
+ .BLOBHASH()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.BLOCKHASH, Prepare.EvmCode
+ .BLOCKHASH(0)
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.CALLDATACOPY, Prepare.EvmCode
+ .CALLDATACOPY(0, 0, 32)
+ .MLOAD(0)
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.CALLDATALOAD, Prepare.EvmCode
+ .CALLDATALOAD(0)
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.MSIZE, Prepare.EvmCode
+ .MSIZE()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.GASPRICE, Prepare.EvmCode
+ .GASPRICE()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.CODESIZE, Prepare.EvmCode
+ .CODESIZE()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.PC, Prepare.EvmCode
+ .PC()
+ .PushData(1)
+ .SSTORE()
+ .PC()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.COINBASE, Prepare.EvmCode
+ .COINBASE()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.TIMESTAMP, Prepare.EvmCode
+ .TIMESTAMP()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.NUMBER, Prepare.EvmCode
+ .NUMBER()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.GASLIMIT, Prepare.EvmCode
+ .GASLIMIT()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.CALLER, Prepare.EvmCode
+ .CALLER()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.ADDRESS, Prepare.EvmCode
+ .ADDRESS()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.ORIGIN, Prepare.EvmCode
+ .ORIGIN()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.CALLVALUE, Prepare.EvmCode
+ .CALLVALUE()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.CHAINID, Prepare.EvmCode
+ .CHAINID()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.GAS, Prepare.EvmCode
+ .PushData(23)
+ .PushData(46)
+ .ADD()
+ .POP()
+ .GAS()
+ .PushData(1)
+ .SSTORE()
+ .PushData(23)
+ .PushData(46)
+ .ADD()
+ .POP()
+ .GAS()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.RETURNDATASIZE, Prepare.EvmCode
+ .RETURNDATASIZE()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.BASEFEE, Prepare.EvmCode
+ .BASEFEE()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.RETURN, Prepare.EvmCode
+ .StoreDataInMemory(0, [2, 3, 5, 7])
+ .RETURN(0, 32)
+ .MLOAD(0)
+ .PushData(1)
+ .SSTORE().Done, EvmExceptionType.None);
+
+ yield return (Instruction.REVERT, Prepare.EvmCode
+ .StoreDataInMemory(0, [2, 3, 5, 7])
+ .REVERT(0, 32)
+ .MLOAD(0)
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.CALLDATASIZE, Prepare.EvmCode
+ .CALLDATASIZE()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.JUMPI | Instruction.JUMPDEST, Prepare.EvmCode
+ .PushSingle(23)
+ .PushSingle(1)
+ .JUMPI(9)
+ .PushSingle(3)
+ .JUMPDEST()
+ .PushSingle(0)
+ .MUL()
+ .GAS()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+
+ yield return (Instruction.JUMPI | Instruction.JUMPDEST, Prepare.EvmCode
+ .PushSingle(23)
+ .PushSingle(0)
+ .JUMPI(9)
+ .PushSingle(3)
+ .JUMPDEST()
+ .PushSingle(0)
+ .MUL()
+ .GAS()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.JUMP | Instruction.JUMPDEST, Prepare.EvmCode
+ .PushSingle(23)
+ .JUMP(14)
+ .JUMPDEST()
+ .PushSingle(3)
+ .MUL()
+ .GAS()
+ .PUSHx([1])
+ .SSTORE()
+ .STOP()
+ .JUMPDEST()
+ .JUMP(5)
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.SHL, Prepare.EvmCode
+ .PushSingle(23)
+ .PushSingle(1)
+ .SHL()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.SHL, Prepare.EvmCode
+ .PushSingle(23)
+ .PushSingle(32)
+ .SHL()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.SHR, Prepare.EvmCode
+ .PushSingle(23)
+ .PushSingle(1)
+ .SHR()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.SHR, Prepare.EvmCode
+ .PushSingle(23)
+ .PushSingle(32)
+ .SHR()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.SAR, Prepare.EvmCode
+ .PushSingle(23)
+ .PushSingle(0)
+ .SAR()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.SAR, Prepare.EvmCode
+ .PushSingle(0)
+ .PushSingle(23)
+ .SAR()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.SAR, Prepare.EvmCode
+ .PushSingle(23)
+ .PushSingle(17)
+ .SAR()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.SAR, Prepare.EvmCode
+ .PushSingle(23)
+ .PushSingle((UInt256)((Int256.Int256)(-1)))
+ .SAR()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.SAR, Prepare.EvmCode
+ .PushSingle(23)
+ .PushSingle((UInt256)((Int256.Int256)(-1)))
+ .SAR()
+ .PushSingle((UInt256)((Int256.Int256)(1)))
+ .SAR()
+ .PushSingle(23)
+ .EQ()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.AND, Prepare.EvmCode
+ .PushSingle(23)
+ .PushSingle(1)
+ .AND()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.AND, Prepare.EvmCode
+ .PushSingle(0)
+ .PushSingle(UInt256.MaxValue)
+ .AND()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.AND, Prepare.EvmCode
+ .PushSingle(UInt256.MaxValue)
+ .PushSingle(0)
+ .AND()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.OR, Prepare.EvmCode
+ .PushSingle(23)
+ .PushSingle(1)
+ .OR()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.OR, Prepare.EvmCode
+ .PushSingle(0)
+ .PushSingle(UInt256.MaxValue)
+ .OR()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.OR, Prepare.EvmCode
+ .PushSingle(UInt256.MaxValue)
+ .PushSingle(0)
+ .OR()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.XOR, Prepare.EvmCode
+ .PushSingle(23)
+ .PushSingle(1)
+ .XOR()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.SLT, Prepare.EvmCode
+ .PushSingle(17)
+ .PushData(23)
+ .SLT()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.SLT, Prepare.EvmCode
+ .PushData(23)
+ .PushSingle(17)
+ .SLT()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.SLT, Prepare.EvmCode
+ .PushData(17)
+ .PushSingle(17)
+ .SLT()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.SGT, Prepare.EvmCode
+ .PushData(23)
+ .PushData(17)
+ .SGT()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.SGT, Prepare.EvmCode
+ .PushData(17)
+ .PushData(17)
+ .SGT()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.SGT, Prepare.EvmCode
+ .PushData(17)
+ .PushData(23)
+ .SGT()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.BYTE, Prepare.EvmCode
+ .BYTE(0, ((UInt256)(23)).PaddedBytes(32))
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.BYTE, Prepare.EvmCode
+ .BYTE(16, UInt256.MaxValue.PaddedBytes(32))
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.BYTE, Prepare.EvmCode
+ .BYTE(16, ((UInt256)(23)).PaddedBytes(32))
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.JUMP | Instruction.JUMPDEST, Prepare.EvmCode
+ .JUMP(31)
+ .INVALID()
+ // this assumes that the code segment is jumping to another segment beyond it's boundaries
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.LOG0, Prepare.EvmCode
+ .PushData(SampleHexData1.PadLeft(64, '0'))
+ .PushData(0)
+ .Op(Instruction.MSTORE)
+ .LOGx(0, 0, 64)
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.LOG1, Prepare.EvmCode
+ .PushData(SampleHexData1.PadLeft(64, '0'))
+ .PushData(0)
+ .Op(Instruction.MSTORE)
+ .PushData(TestItem.KeccakA.Bytes.ToArray())
+ .LOGx(1, 0, 64)
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.LOG2, Prepare.EvmCode
+ .PushData(SampleHexData2.PadLeft(64, '0'))
+ .PushData(0)
+ .Op(Instruction.MSTORE)
+ .PushData(TestItem.KeccakA.Bytes.ToArray())
+ .PushData(TestItem.KeccakB.Bytes.ToArray())
+ .LOGx(2, 0, 64)
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.LOG3, Prepare.EvmCode
+ .PushData(SampleHexData1.PadLeft(64, '0'))
+ .PushData(0)
+ .Op(Instruction.MSTORE)
+ .PushData(TestItem.KeccakA.Bytes.ToArray())
+ .PushData(TestItem.KeccakB.Bytes.ToArray())
+ .PushData(TestItem.KeccakC.Bytes.ToArray())
+ .LOGx(3, 0, 64)
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.LOG4, Prepare.EvmCode
+ .PushData(SampleHexData1.PadLeft(64, '0'))
+ .PushData(0)
+ .Op(Instruction.MSTORE)
+ .PushData(TestItem.KeccakA.Bytes.ToArray())
+ .PushData(TestItem.KeccakB.Bytes.ToArray())
+ .PushData(TestItem.KeccakC.Bytes.ToArray())
+ .PushData(TestItem.KeccakD.Bytes.ToArray())
+ .LOGx(4, 0, 64)
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.TSTORE | Instruction.TLOAD, Prepare.EvmCode
+ .PushData(23)
+ .PushData(7)
+ .TSTORE()
+ .PushData(7)
+ .TLOAD()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.SSTORE | Instruction.SLOAD, Prepare.EvmCode
+ .PushData(23)
+ .PushData(7)
+ .SSTORE()
+ .PushData(7)
+ .SLOAD()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.EXTCODESIZE, Prepare.EvmCode
+ .EXTCODESIZE(Address.FromNumber(23))
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.EXTCODEHASH, Prepare.EvmCode
+ .EXTCODEHASH(Address.FromNumber(23))
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.EXTCODECOPY, Prepare.EvmCode
+ .EXTCODECOPY(Address.FromNumber(23), 0, 0, 32)
+ .MLOAD(0)
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.BALANCE, Prepare.EvmCode
+ .BALANCE(Address.FromNumber(23))
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.SELFBALANCE, Prepare.EvmCode
+ .SELFBALANCE()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.INVALID, Prepare.EvmCode
+ .INVALID()
+ .PushData(0)
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.BadInstruction);
+
+ yield return (Instruction.STOP, Prepare.EvmCode
+ .STOP()
+ .PushData(0)
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.POP, Prepare.EvmCode
+ .PUSHx()
+ .POP()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.POP | Instruction.INVALID, Prepare.EvmCode
+ .POP()
+ .POP()
+ .POP()
+ .POP()
+ .Done, EvmExceptionType.StackUnderflow);
+
+
+ for (byte opcode = (byte)Instruction.DUP1; opcode <= (byte)Instruction.DUP16; opcode++)
+ {
+ int n = opcode - (byte)Instruction.DUP1 + 1;
+ var test = Prepare.EvmCode;
+ for (int i = 0; i < n; i++)
+ {
+ test.PushData(i);
+ }
+ test.Op((Instruction)opcode)
+ .PushData(1)
+ .SSTORE();
+
+ yield return ((Instruction)opcode, test.Done, EvmExceptionType.None);
+ }
+
+ for (byte opcode = (byte)Instruction.PUSH0; opcode <= (byte)Instruction.PUSH32; opcode++)
+ {
+ int n = opcode - (byte)Instruction.PUSH0;
+ byte[] args = n == 0 ? null : Enumerable.Range(0, n).Select(i => (byte)i).ToArray();
+
+ yield return ((Instruction)opcode, Prepare.EvmCode.PUSHx(args)
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+ }
+
+ for (byte opcode = (byte)Instruction.SWAP1; opcode <= (byte)Instruction.SWAP16; opcode++)
+ {
+ int n = opcode - (byte)Instruction.SWAP1 + 2;
+ var test = Prepare.EvmCode;
+ for (int i = 0; i < n; i++)
+ {
+ test.PushData(i);
+ }
+ test.Op((Instruction)opcode)
+ .PushData(1)
+ .SSTORE();
+
+ yield return ((Instruction)opcode, test.Done, EvmExceptionType.None);
+ }
+
+ yield return (Instruction.SDIV, Prepare.EvmCode
+ .PushData(23)
+ .PushData(7)
+ .SDIV()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.SMOD, Prepare.EvmCode
+ .PushData(23)
+ .PushData(7)
+ .SMOD()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.CODECOPY, Prepare.EvmCode
+ .PushData(0)
+ .PushData(32)
+ .PushData(7)
+ .CODECOPY()
+ .MLOAD(0)
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.MULMOD, Prepare.EvmCode
+ .PushData(23)
+ .PushData(3)
+ .PushData(7)
+ .MULMOD()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.KECCAK256, Prepare.EvmCode
+ .MSTORE(0, Enumerable.Range(0, 16).Select(i => (byte)i).ToArray())
+ .PushData(0)
+ .PushData(16)
+ .KECCAK256()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.PREVRANDAO, Prepare.EvmCode
+ .PREVRANDAO()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.RETURNDATACOPY, Prepare.EvmCode
+ .PushData(0)
+ .PushData(32)
+ .PushData(0)
+ .RETURNDATACOPY()
+ .MLOAD(0)
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.BLOBBASEFEE, Prepare.EvmCode
+ .Op(Instruction.BLOBBASEFEE)
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.SIGNEXTEND, Prepare.EvmCode
+ .PushData(1024)
+ .PushData(16)
+ .SIGNEXTEND()
+ .PushData(1)
+ .SSTORE()
+ .Done, EvmExceptionType.None);
+
+ yield return (Instruction.INVALID, Prepare.EvmCode
+ .JUMPDEST()
+ .MUL(23, 3)
+ .POP()
+ .JUMP(0)
+ .Done, EvmExceptionType.OutOfGas);
+
+ yield return (Instruction.INVALID, Prepare.EvmCode
+ .JUMPDEST()
+ .PUSHx()
+ .DUPx(1)
+ .DUPx(1)
+ .DUPx(1)
+ .DUPx(1)
+ .DUPx(1)
+ .DUPx(1)
+ .DUPx(1)
+ .JUMP(0)
+ .Done, EvmExceptionType.StackOverflow);
+
+ yield return (Instruction.INVALID, Prepare.EvmCode
+ .JUMPDEST()
+ .MUL(23)
+ .JUMP(0)
+ .Done, EvmExceptionType.StackUnderflow);
+ }
+
+ [Test]
+ public void All_Stateless_Opcodes_Are_Covered_in_JIT_Tests()
+ {
+ List instructions = System.Enum.GetValues().ToList();
+ instructions.Remove(Instruction.MSTORE);
+ instructions.Remove(Instruction.MLOAD);
+ instructions.Remove(Instruction.SSTORE);
+ instructions.Remove(Instruction.SLOAD);
+ instructions.Remove(Instruction.TSTORE);
+ instructions.Remove(Instruction.TLOAD);
+ instructions.Remove(Instruction.JUMP);
+ instructions.Remove(Instruction.JUMPI);
+ instructions.Remove(Instruction.JUMPDEST);
+
+ instructions.Add(Instruction.MSTORE | Instruction.MLOAD);
+ instructions.Add(Instruction.TSTORE | Instruction.TLOAD);
+ instructions.Add(Instruction.SSTORE | Instruction.SLOAD);
+ instructions.Add(Instruction.JUMP | Instruction.JUMPDEST);
+ instructions.Add(Instruction.JUMPI | Instruction.JUMPDEST);
+
+ var tests = GeJitBytecodesSamples().Select(test => test.Item1);
+
+
+
+ List notCovered = new List();
+ foreach (var opcode in instructions)
+ {
+ if (!opcode.IsStateful() && !tests.Contains(opcode))
+ {
+ notCovered.Add(opcode);
+ }
+ }
+
+ Assert.That(notCovered.Count, Is.EqualTo(0), $"[{String.Join(", ", notCovered)}]");
+ }
+
+ [Test]
+ public void Pattern_Analyzer_Find_All_Instance_Of_Pattern()
+ {
+ byte[] bytecode =
+ Prepare.EvmCode
+ .PushSingle(23)
+ .PushSingle(7)
+ .ADD()
+ .PushSingle(42)
+ .PushSingle(5)
+ .ADD()
+ .Done;
+
+ CodeInfo codeInfo = new CodeInfo(bytecode, TestItem.AddressA);
+
+ IlAnalyzer.StartAnalysis(codeInfo, ILMode.PAT_MODE, config, NullLogger.Instance);
+
+ codeInfo.IlInfo.Chunks.Count.Should().Be(2);
+ }
+
+
+ [Test]
+ public void JIT_Analyzer_Compiles_stateless_bytecode_chunk()
+ {
+ byte[] bytecode =
+ Prepare.EvmCode
+ .PushSingle(23)
+ .PushSingle(7)
+ .ADD()
+ .PushSingle(42)
+ .PushSingle(5)
+ .ADD()
+ .Call(Address.FromNumber(23), 10000)
+ .PushSingle(23)
+ .PushSingle(7)
+ .ADD()
+ .PushSingle(42)
+ .PushSingle(5)
+ .ADD()
+ .STOP()
+ .Done;
+
+ CodeInfo codeInfo = new CodeInfo(bytecode, TestItem.AddressA);
+
+ IlAnalyzer.StartAnalysis(codeInfo, IlInfo.ILMode.JIT_MODE, config, NullLogger.Instance);
+
+ codeInfo.IlInfo.Segments.Count.Should().Be(2);
+ }
+
+ [Test]
+ public void Execution_Swap_Happens_When_Pattern_Occurs()
+ {
+ TestBlockChain enhancedChain = new TestBlockChain(new VMConfig
+ {
+ PatternMatchingThreshold = 1,
+ IsPatternMatchingEnabled = true,
+ JittingThreshold = int.MaxValue,
+ IsJitEnabled = false,
+ AggressiveJitMode = false,
+ AnalysisQueueMaxSize = 1,
+ });
+
+ var pattern1 = IlAnalyzer.GetPatternHandler();
+ var pattern2 = IlAnalyzer.GetPatternHandler();
+ var pattern3 = IlAnalyzer.GetPatternHandler();
+
+ byte[] bytecode =
+ Prepare.EvmCode
+ .JUMPDEST()
+ .PushSingle(1000)
+ .GAS()
+ .LT()
+ .PUSHx([0, 26])
+ .JUMPI()
+ .PushSingle(23)
+ .PushSingle(7)
+ .ADD()
+ .POP()
+ .PushSingle(42)
+ .PushSingle(5)
+ .ADD()
+ .POP()
+ .PUSHx([0, 0])
+ .JUMP()
+ .JUMPDEST()
+ .STOP()
+ .Done;
+
+ /*
+ var hashcode = Keccak.Compute(bytecode);
+ var address = new Address(hashcode);
+ var spec = Prague.Instance;
+ TestState.CreateAccount(address, 1000000);
+ TestState.InsertCode(address, bytecode, spec);
+ */
+ var accumulatedTraces = new List();
+ for (int i = 0; i < RepeatCount ; i++)
+ {
+ var tracer = new GethLikeTxMemoryTracer(GethTraceOptions.Default);
+ enhancedChain.Execute(bytecode, tracer);
+ var traces = tracer.BuildResult().Entries.Where(tr => tr.IsPrecompiled is not null && !tr.IsPrecompiled.Value).ToList();
+ accumulatedTraces.AddRange(traces);
+ }
+
+ Assert.That(accumulatedTraces.Count, Is.GreaterThan(0));
+ }
+
+ [Test]
+ public void Execution_Swap_Happens_When_Segments_are_compiled()
+ {
+ TestBlockChain enhancedChain = new TestBlockChain(new VMConfig
+ {
+ PatternMatchingThreshold = int.MaxValue,
+ IsPatternMatchingEnabled = false,
+ AnalysisQueueMaxSize = 1,
+ JittingThreshold = 1,
+ IsJitEnabled = true,
+ AggressiveJitMode = false
+ });
+
+ byte[] bytecode =
+ Prepare.EvmCode
+ .JUMPDEST()
+ .PushSingle(1000)
+ .GAS()
+ .LT()
+ .PUSHx([0, 26])
+ .JUMPI()
+ .PushSingle(23)
+ .PushSingle(7)
+ .ADD()
+ .POP()
+ .PushSingle(42)
+ .PushSingle(5)
+ .ADD()
+ .POP()
+ .PUSHx([0, 0])
+ .JUMP()
+ .JUMPDEST()
+ .STOP()
+ .Done;
+
+ var accumulatedTraces = new List();
+ for (int i = 0; i < RepeatCount; i++)
+ {
+ var tracer = new GethLikeTxMemoryTracer(GethTraceOptions.Default);
+ enhancedChain.Execute(bytecode, tracer);
+ var traces = tracer.BuildResult().Entries.Where(tr => tr.IsPrecompiled is not null && tr.IsPrecompiled.Value).ToList();
+ accumulatedTraces.AddRange(traces);
+ }
+
+ Assert.That(accumulatedTraces.Count, Is.GreaterThan(0));
+ }
+
+ [Test]
+ public void All_Opcodes_Have_Metadata()
+ {
+ Instruction[] instructions = System.Enum.GetValues();
+ foreach (var opcode in instructions)
+ {
+ Assert.That(OpcodeMetadata.Operations.ContainsKey(opcode), Is.True);
+ }
+ }
+
+ [Test, TestCaseSource(nameof(GeJitBytecodesSamples))]
+ public void ILVM_JIT_Execution_Equivalence_Tests((Instruction? opcode, byte[] bytecode, EvmExceptionType _) testcase)
+ {
+ TestBlockChain standardChain = new TestBlockChain(new VMConfig());
+ var address = standardChain.InsertCode(testcase.bytecode);
+ TestBlockChain enhancedChain = new TestBlockChain(new VMConfig
+ {
+ PatternMatchingThreshold = int.MaxValue,
+ IsPatternMatchingEnabled = false,
+ BakeInTracingInJitMode = true,
+ JittingThreshold = 1,
+ AnalysisQueueMaxSize = 1,
+ IsJitEnabled = true
+ });
+ enhancedChain.InsertCode(testcase.bytecode);
+
+ GethTraceOptions tracerOptions = new GethTraceOptions
+ {
+ EnableMemory = true,
+ };
+
+ var tracer1 = new GethLikeTxMemoryTracer(tracerOptions);
+ var tracer2 = new GethLikeTxMemoryTracer(tracerOptions);
+
+ var bytecode = Prepare.EvmCode
+ .Call(address, 750_000)
+ .STOP()
+ .Done;
+
+ standardChain.Execute(bytecode, tracer1);
+
+ enhancedChain.ForceRunAnalysis(address, ILMode.JIT_MODE);
+
+ enhancedChain.Execute(bytecode, tracer2);
+
+ var normal_traces = tracer1.BuildResult();
+ var ilvm_traces = tracer2.BuildResult();
+
+ var actual = standardChain.StateRoot;
+ var expected = enhancedChain.StateRoot;
+
+ var enhancedHasIlvmTraces = ilvm_traces.Entries.Where(tr => tr.SegmentID is not null).Any();
+ var normalHasIlvmTraces = normal_traces.Entries.Where(tr => tr.SegmentID is not null).Any();
+
+ if (testcase.opcode is not null)
+ {
+ Assert.That(enhancedHasIlvmTraces, Is.True);
+ Assert.That(normalHasIlvmTraces, Is.False);
+ }
+ Assert.That(actual, Is.EqualTo(expected));
+ }
+
+ [Test, TestCaseSource(nameof(GePatBytecodesSamples))]
+ public void ILVM_Pat_Execution_Equivalence_Tests((Type opcode, byte[] bytecode) testcase)
+ {
+ TestBlockChain standardChain = new TestBlockChain(new VMConfig());
+ var address = standardChain.InsertCode(testcase.bytecode);
+ TestBlockChain enhancedChain = new TestBlockChain(new VMConfig
+ {
+ PatternMatchingThreshold = 1,
+ IsPatternMatchingEnabled = true,
+ JittingThreshold = int.MaxValue,
+ AnalysisQueueMaxSize = 1,
+ IsJitEnabled = false
+ });
+ enhancedChain.InsertCode(testcase.bytecode);
+
+ var tracer1 = new GethLikeTxMemoryTracer(GethTraceOptions.Default);
+ var tracer2 = new GethLikeTxMemoryTracer(GethTraceOptions.Default);
+
+ var bytecode =
+ Prepare.EvmCode
+ .Call(address, 100000)
+ .STOP()
+ .Done;
+
+ standardChain.Execute(bytecode, tracer1, (ForkActivation)10000000000);
+
+ enhancedChain.ForceRunAnalysis(address, ILMode.PAT_MODE);
+
+ enhancedChain.Execute(bytecode, tracer2, (ForkActivation)10000000000);
+
+ var normal_traces = tracer1.BuildResult();
+ var ilvm_traces = tracer2.BuildResult();
+
+ var actual = standardChain.StateRoot;
+ var expected = enhancedChain.StateRoot;
+
+ var enhancedHasIlvmTraces = ilvm_traces.Entries.Where(tr => tr.SegmentID is not null).Any();
+ var normalHasIlvmTraces = normal_traces.Entries.Where(tr => tr.SegmentID is not null).Any();
+
+ if (testcase.opcode is not null)
+ {
+ Assert.That(enhancedHasIlvmTraces, Is.True);
+ Assert.That(normalHasIlvmTraces, Is.False);
+ }
+ Assert.That(actual, Is.EqualTo(expected));
+ }
+
+ [Test]
+ public void JIT_Mode_Segment_Has_Jump_Into_Another_Segment_Agressive_Mode_On()
+ {
+ TestBlockChain enhancedChain = new TestBlockChain(new VMConfig
+ {
+ PatternMatchingThreshold = 1,
+ IsPatternMatchingEnabled = false,
+ JittingThreshold = 1,
+ AnalysisQueueMaxSize = 1,
+ IsJitEnabled = true,
+ AggressiveJitMode = true,
+ });
+
+ var aux = enhancedChain.InsertCode(Prepare.EvmCode
+ .PushData(23)
+ .PushData(7)
+ .ADD()
+ .STOP().Done);
+
+ Address main = enhancedChain.InsertCode(
+ Prepare.EvmCode
+ .JUMPDEST()
+ .PushSingle(1000)
+ .GAS()
+ .LT()
+ .JUMPI(59)
+ .PushSingle(23)
+ .PushSingle(7)
+ .ADD()
+ .POP()
+ .Call(aux, 100)
+ .POP()
+ .PushSingle(42)
+ .PushSingle(5)
+ .ADD()
+ .POP()
+ .JUMP(0)
+ .JUMPDEST()
+ .STOP()
+ .Done);
+
+ byte[] driver =
+ Prepare.EvmCode
+ .Call(main, 1_000_000)
+ .Done;
+
+ enhancedChain.ForceRunAnalysis(main, ILMode.JIT_MODE);
+ enhancedChain.ForceRunAnalysis(aux, ILMode.JIT_MODE);
+
+ var tracer = new GethLikeTxMemoryTracer(GethTraceOptions.Default);
+ enhancedChain.Execute(driver, tracer);
+ var traces = tracer.BuildResult().Entries.Where(tr => tr.SegmentID is not null).ToList();
+
+
+ // in the last stint gas is almost below 1000
+ // it executes segment 0 (0..47)
+ // then calls address 23 (segment 0..5 since it is precompiled as well)
+ // then it executes segment 49..60 which ends in jump back to pc = 0
+ // then it executes segment 0..46 again but this time gas is below 1000
+ // it ends jumping to pc = 59 (which occurs in segment 49..60)
+ // so the last segment executed is (49..60)
+
+ string[] desiredTracePattern = new[]
+ {
+ $"ILEVM_PRECOMPILED_({main})[0..47]",
+ $"ILEVM_PRECOMPILED_({aux})[0..5]",
+ $"ILEVM_PRECOMPILED_({main})[49..60]",
+ $"ILEVM_PRECOMPILED_({main})[0..47]",
+ $"ILEVM_PRECOMPILED_({main})[49..60]",
+ };
+
+ string[] actualTracePattern = traces.TakeLast(5).Select(tr => tr.SegmentID).ToArray();
+ Assert.That(actualTracePattern, Is.EqualTo(desiredTracePattern));
+ }
+
+ [Test]
+ public void JIT_Mode_Segment_Has_Jump_Into_Another_Segment_Agressive_Mode_Off()
+ {
+ TestBlockChain enhancedChain = new TestBlockChain(new VMConfig
+ {
+ PatternMatchingThreshold = 2,
+ AnalysisQueueMaxSize = 1,
+ IsPatternMatchingEnabled = true,
+ JittingThreshold = 1,
+ IsJitEnabled = true,
+ AggressiveJitMode = false,
+ BakeInTracingInJitMode = true
+ });
+
+ var aux = enhancedChain.InsertCode(Prepare.EvmCode
+ .PushData(23)
+ .PushData(7)
+ .ADD()
+ .STOP().Done);
+
+ Address main = enhancedChain.InsertCode(
+ Prepare.EvmCode
+ .JUMPDEST()
+ .PushSingle(1000)
+ .GAS()
+ .LT()
+ .JUMPI(59)
+ .PushSingle(23)
+ .PushSingle(7)
+ .ADD()
+ .POP()
+ .Call(aux, 100)
+ .POP()
+ .PushSingle(42)
+ .PushSingle(5)
+ .ADD()
+ .POP()
+ .JUMP(0)
+ .JUMPDEST()
+ .STOP()
+ .Done);
+
+ byte[] driver =
+ Prepare.EvmCode
+ .Call(main, 1_000_000)
+ .Done;
+
+ enhancedChain.ForceRunAnalysis(main, ILMode.PAT_MODE | ILMode.JIT_MODE);
+
+ enhancedChain.ForceRunAnalysis(aux, ILMode.PAT_MODE | ILMode.JIT_MODE);
+
+ var tracer = new GethLikeTxMemoryTracer(GethTraceOptions.Default);
+ enhancedChain.Execute(driver, tracer);
+ var traces = tracer.BuildResult().Entries.Where(tr => tr.SegmentID is not null).ToList();
+
+ // in the last stint gas is almost below 1000
+ // it executes segment 0 (0..47)
+ // then calls address 23 (segment 0..5 since it is precompiled as well)
+ // then it executes segment 49..60 which ends in jump back to pc = 0
+ // then it executes segment 0..47 again but this time gas is below 1000
+ // it ends jumping to pc = 59 (which is index of AbortDestinationPattern)
+ // so the last segment executed is AbortDestinationPattern
+
+ string[] desiredTracePattern = new[]
+ {
+ $"ILEVM_PRECOMPILED_({main})[0..47]",
+ $"ILEVM_PRECOMPILED_({aux})[0..5]",
+ $"ILEVM_PRECOMPILED_({main})[49..60]",
+ $"ILEVM_PRECOMPILED_({main})[0..47]",
+ $"AbortDestinationPattern",
+ };
+
+ string[] actualTracePattern = traces.TakeLast(5).Select(tr => tr.SegmentID).ToArray();
+ Assert.That(actualTracePattern, Is.EqualTo(desiredTracePattern));
+ }
+
+ [Test]
+ public void JIT_Mode_Segment_Has_Jump_Into_Another_Segment_Agressive_Mode_On_Equiv()
+ {
+ TestBlockChain enhancedChain = new TestBlockChain(new VMConfig
+ {
+ PatternMatchingThreshold = 1,
+ IsPatternMatchingEnabled = false,
+ JittingThreshold = 1,
+ AnalysisQueueMaxSize = 1,
+ IsJitEnabled = true,
+ AggressiveJitMode = true,
+ });
+
+ TestBlockChain standardChain = new TestBlockChain(new VMConfig());
+
+ var auxCode = Prepare.EvmCode
+ .PushData(23)
+ .PushData(7)
+ .ADD()
+ .STOP().Done;
+
+ var aux = enhancedChain.InsertCode(auxCode);
+ standardChain.InsertCode(auxCode);
+
+ var maincode = Prepare.EvmCode
+ .JUMPDEST()
+ .PushSingle(1000)
+ .GAS()
+ .LT()
+ .JUMPI(59)
+ .PushSingle(23)
+ .PushSingle(7)
+ .ADD()
+ .POP()
+ .Call(aux, 100)
+ .POP()
+ .PushSingle(42)
+ .PushSingle(5)
+ .ADD()
+ .POP()
+ .JUMP(0)
+ .JUMPDEST()
+ .STOP()
+ .Done;
+
+ Address main = enhancedChain.InsertCode(maincode);
+ standardChain.InsertCode(maincode);
+
+ var tracer1 = new GethLikeTxMemoryTracer(GethTraceOptions.Default);
+ var tracer2 = new GethLikeTxMemoryTracer(GethTraceOptions.Default);
+
+ var bytecode =
+ Prepare.EvmCode
+ .Call(main, 100000)
+ .STOP()
+ .Done;
+
+ standardChain.Execute(bytecode, tracer1, (ForkActivation)10000000000);
+
+ enhancedChain.ForceRunAnalysis(main, ILMode.JIT_MODE);
+
+ enhancedChain.Execute(bytecode, tracer2, (ForkActivation)10000000000);
+
+ var normal_traces = tracer1.BuildResult();
+ var ilvm_traces = tracer2.BuildResult();
+
+ var actual = standardChain.StateRoot;
+ var expected = enhancedChain.StateRoot;
+
+ var enhancedHasIlvmTraces = ilvm_traces.Entries.Where(tr => tr.SegmentID is not null).Any();
+ var normalHasIlvmTraces = normal_traces.Entries.Where(tr => tr.SegmentID is not null).Any();
+
+ Assert.That(enhancedHasIlvmTraces, Is.True);
+ Assert.That(normalHasIlvmTraces, Is.False);
+ Assert.That(actual, Is.EqualTo(expected));
+ }
+
+ [Test]
+ public void JIT_Mode_Segment_Has_Jump_Into_Another_Segment_Agressive_Mode_Off_Equiv()
+ {
+ TestBlockChain enhancedChain = new TestBlockChain(new VMConfig
+ {
+ PatternMatchingThreshold = 2,
+ AnalysisQueueMaxSize = 1,
+ IsPatternMatchingEnabled = true,
+ JittingThreshold = 1,
+ IsJitEnabled = true,
+ AggressiveJitMode = false,
+ BakeInTracingInJitMode = true
+ });
+
+
+ TestBlockChain standardChain = new TestBlockChain(new VMConfig());
+
+ var auxCode = Prepare.EvmCode
+ .PushData(23)
+ .PushData(7)
+ .ADD()
+ .STOP().Done;
+
+ var aux = enhancedChain.InsertCode(auxCode);
+ standardChain.InsertCode(auxCode);
+
+ var maincode = Prepare.EvmCode
+ .JUMPDEST()
+ .PushSingle(1000)
+ .GAS()
+ .LT()
+ .JUMPI(59)
+ .PushSingle(23)
+ .PushSingle(7)
+ .ADD()
+ .POP()
+ .Call(aux, 100)
+ .POP()
+ .PushSingle(42)
+ .PushSingle(5)
+ .ADD()
+ .POP()
+ .JUMP(0)
+ .JUMPDEST()
+ .STOP()
+ .Done;
+
+ Address main = enhancedChain.InsertCode(maincode);
+ standardChain.InsertCode(maincode);
+
+ var tracer1 = new GethLikeTxMemoryTracer(GethTraceOptions.Default);
+ var tracer2 = new GethLikeTxMemoryTracer(GethTraceOptions.Default);
+
+ var bytecode =
+ Prepare.EvmCode
+ .Call(main, 100000)
+ .STOP()
+ .Done;
+
+ standardChain.Execute(bytecode, tracer1, (ForkActivation)10000000000);
+
+ enhancedChain.ForceRunAnalysis(main, ILMode.JIT_MODE);
+
+ enhancedChain.Execute(bytecode, tracer2, (ForkActivation)10000000000);
+
+ var normal_traces = tracer1.BuildResult();
+ var ilvm_traces = tracer2.BuildResult();
+
+ var actual = standardChain.StateRoot;
+ var expected = enhancedChain.StateRoot;
+
+ var enhancedHasIlvmTraces = ilvm_traces.Entries.Where(tr => tr.SegmentID is not null).Any();
+ var normalHasIlvmTraces = normal_traces.Entries.Where(tr => tr.SegmentID is not null).Any();
+
+ Assert.That(enhancedHasIlvmTraces, Is.True);
+ Assert.That(normalHasIlvmTraces, Is.False);
+ Assert.That(actual, Is.EqualTo(expected));
+ }
+
+ [Test]
+ public void JIT_invalid_opcode_results_in_failure()
+ {
+ TestBlockChain enhancedChain = new TestBlockChain(new VMConfig
+ {
+ PatternMatchingThreshold = 1,
+ IsPatternMatchingEnabled = false,
+ JittingThreshold = 1,
+ IsJitEnabled = true,
+ AnalysisQueueMaxSize = 1,
+ AggressiveJitMode = false
+ });
+
+ Address main = enhancedChain.InsertCode(
+ Prepare.EvmCode
+ .PUSHx() // PUSH0
+ .POP()
+ .STOP()
+ .Done);
+
+ byte[] driver =
+ Prepare.EvmCode
+ .Call(main, 1000)
+ .JUMPI(17)
+ .INVALID()
+ .JUMPDEST()
+ .STOP()
+ .Done;
+
+ enhancedChain.ForceRunAnalysis(main, ILMode.JIT_MODE);
+ var tracer = new GethLikeTxMemoryTracer(GethTraceOptions.Default);
+ enhancedChain.Execute(driver, tracer, (ForkActivation?)(MainnetSpecProvider.ByzantiumBlockNumber, 0));
+ var traces = tracer.BuildResult();
+
+ var HasIlvmTraces = traces.Entries.Where(tr => tr.SegmentID is not null).Any();
+ var hasFailed = traces.Failed;
+ Assert.That(HasIlvmTraces, Is.True);
+ Assert.That(hasFailed, Is.True);
+ }
+
+ [Test]
+ public void Pure_Opcode_Emition_Coveraga()
+ {
+ Instruction[] instructions =
+ System.Enum.GetValues()
+ .Where(opcode => !opcode.IsStateful())
+ .ToArray();
+
+
+ List<(Instruction, Exception)> notYetImplemented = [];
+ foreach (var instruction in instructions)
+ {
+ string name = $"ILEVM_TEST_{instruction}";
+ OpcodeInfo opcode = new OpcodeInfo(0, instruction, null);
+ try
+ {
+ ILCompiler.CompileSegment(name, [opcode], [], config);
+ }
+ catch (NotSupportedException nse)
+ {
+ notYetImplemented.Add((instruction, nse));
+ }
+ catch (Exception)
+ {
+ }
+ }
+
+ string missingOpcodes = String.Join("; ", notYetImplemented.Select(op => op.Item1.ToString()));
+ Assert.That(notYetImplemented.Count == 0, $"{notYetImplemented.Count} opcodes missing: [{missingOpcodes}]");
+ }
+
+
+ [Test]
+ public void ILAnalyzer_Initialize_Add_All_Patterns()
+ {
+ IlAnalyzer.Initialize();
+ // get static field _patterns from IlAnalyzer
+ var patterns = typeof(IlAnalyzer).GetField(PatternField, BindingFlags.NonPublic | BindingFlags.Static).GetValue(null) as Dictionary;
+
+ Assert.That(patterns.Count, Is.GreaterThan(0));
+ }
+
+ [Test, TestCaseSource(nameof(GeJitBytecodesSamples))]
+ public void Ensure_Evm_ILvm_Compatibility((Instruction? opcode, byte[] bytecode, EvmExceptionType exceptionType) testcase)
+ {
+ var codeInfo = new CodeInfo(testcase.bytecode, TestItem.AddressA);
+ var blkExCtx = new BlockExecutionContext(BuildBlock(MainnetSpecProvider.CancunActivation, SenderRecipientAndMiner.Default).Header);
+ var txExCtx = new TxExecutionContext(blkExCtx, TestItem.AddressA, 23, [TestItem.KeccakH.Bytes.ToArray()], CodeInfoRepository);
+ var envExCtx = new ExecutionEnvironment(codeInfo, Recipient, Sender, Contract, new ReadOnlyMemory([1, 2, 3, 4, 5, 6, 7]), txExCtx, 23, 7);
+ var stack = new byte[1024 * 32];
+ var inputBuffer = envExCtx.InputData;
+ var returnBuffer =
+ new ReadOnlyMemory(Enumerable.Range(0, 32)
+ .Select(i => (byte)i).ToArray());
+
+ TestState.CreateAccount(Address.FromNumber(1), 1000000);
+ TestState.InsertCode(Address.FromNumber(1), testcase.bytecode, Prague.Instance);
+
+ var state = new EvmState(
+ 750_000,
+ new ExecutionEnvironment(codeInfo, Address.FromNumber(1), Address.FromNumber(1), Address.FromNumber(1), ReadOnlyMemory.Empty, txExCtx, 0, 0),
+ ExecutionType.CALL,
+ Snapshot.Empty);
+
+ IVirtualMachine evm = typeof(VirtualMachine).GetField("_evm", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(Machine) as IVirtualMachine;
+
+ state.InitStacks();
+
+ var tracer = new GethLikeTxMemoryTracer(GethTraceOptions.Default);
+
+ ILEvmState iLEvmState = new ILEvmState(SpecProvider.ChainId, state, EvmExceptionType.None, 0, 100000, ref returnBuffer);
+ var metadata = IlAnalyzer.StripByteCode(testcase.bytecode);
+ var ctx = ILCompiler.CompileSegment("ILEVM_TEST", metadata.Item1, metadata.Item2, config);
+ ctx.PrecompiledSegment(ref iLEvmState, _blockhashProvider, TestState, CodeInfoRepository, Prague.Instance, tracer, ctx.Data);
+
+ Assert.That(iLEvmState.EvmException == testcase.exceptionType);
+ }
+
+
+ [Test, TestCaseSource(nameof(GeJitBytecodesSamples))]
+ public void Test_ILVM_Trace_Mode((Instruction? opcode, byte[] bytecode, EvmExceptionType exceptionType) testcase)
+ {
+ var codeInfo = new CodeInfo(testcase.bytecode, TestItem.AddressA);
+ var blkExCtx = new BlockExecutionContext(BuildBlock(MainnetSpecProvider.CancunActivation, SenderRecipientAndMiner.Default).Header);
+ var txExCtx = new TxExecutionContext(blkExCtx, TestItem.AddressA, 23, [TestItem.KeccakH.Bytes.ToArray()], CodeInfoRepository);
+ var envExCtx = new ExecutionEnvironment(codeInfo, Recipient, Sender, Contract, new ReadOnlyMemory([1, 2, 3, 4, 5, 6, 7]), txExCtx, 23, 7);
+ var stack = new byte[1024 * 32];
+ var inputBuffer = envExCtx.InputData;
+ var returnBuffer =
+ new ReadOnlyMemory(Enumerable.Range(0, 32)
+ .Select(i => (byte)i).ToArray());
+
+ TestState.CreateAccount(Address.FromNumber(1), 1000000);
+ TestState.InsertCode(Address.FromNumber(1), testcase.bytecode, Prague.Instance);
+
+ var state = new EvmState(
+ 750_000,
+ new ExecutionEnvironment(codeInfo, Address.FromNumber(1), Address.FromNumber(1), Address.FromNumber(1), ReadOnlyMemory.Empty, txExCtx, 0, 0),
+ ExecutionType.CALL,
+ Snapshot.Empty);
+
+ IVirtualMachine evm = typeof(VirtualMachine).GetField("_evm", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(Machine) as IVirtualMachine;
+
+ state.InitStacks();
+
+ var tracer = new GethLikeTxMemoryTracer(GethTraceOptions.Default);
+
+ ILEvmState iLEvmState = new ILEvmState(SpecProvider.ChainId, state, EvmExceptionType.None, 0, 100000, ref returnBuffer);
+ var metadata = IlAnalyzer.StripByteCode(testcase.bytecode);
+ var ctx = ILCompiler.CompileSegment("ILEVM_TEST", metadata.Item1, metadata.Item2, config);
+ ctx.PrecompiledSegment(ref iLEvmState, _blockhashProvider, TestState, CodeInfoRepository, Prague.Instance, tracer, ctx.Data);
+
+ var tracedOpcodes = tracer.BuildResult().Entries;
+
+ if (testcase.opcode is not null)
+ {
+ Assert.That(tracedOpcodes.Count, Is.GreaterThan(0));
+ }
+ else
+ {
+ Assert.That(tracedOpcodes.Count, Is.EqualTo(0));
+ }
+ }
+
+ [Test, TestCaseSource(nameof(GeJitBytecodesSamples))]
+ public void Test_ILVM_Trace_Mode_Has_0_Traces_When_TraceInstructions_Is_Off((Instruction? opcode, byte[] bytecode, EvmExceptionType exceptionType) testcase)
+ {
+ var codeInfo = new CodeInfo(testcase.bytecode, TestItem.AddressA);
+ var blkExCtx = new BlockExecutionContext(BuildBlock(MainnetSpecProvider.CancunActivation, SenderRecipientAndMiner.Default).Header);
+ var txExCtx = new TxExecutionContext(blkExCtx, TestItem.AddressA, 23, [TestItem.KeccakH.Bytes.ToArray()], CodeInfoRepository);
+ var envExCtx = new ExecutionEnvironment(codeInfo, Recipient, Sender, Contract, new ReadOnlyMemory([1, 2, 3, 4, 5, 6, 7]), txExCtx, 23, 7);
+ var stack = new byte[1024 * 32];
+ var inputBuffer = envExCtx.InputData;
+ var returnBuffer =
+ new ReadOnlyMemory(Enumerable.Range(0, 32)
+ .Select(i => (byte)i).ToArray());
+
+ TestState.CreateAccount(Address.FromNumber(1), 1000000);
+ TestState.InsertCode(Address.FromNumber(1), testcase.bytecode, Prague.Instance);
+
+ var state = new EvmState(
+ 750_000,
+ new ExecutionEnvironment(codeInfo, Address.FromNumber(1), Address.FromNumber(1), Address.FromNumber(1), ReadOnlyMemory.Empty, txExCtx, 0, 0),
+ ExecutionType.CALL,
+ Snapshot.Empty);
+
+ IVirtualMachine evm = typeof(VirtualMachine).GetField("_evm", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(Machine) as IVirtualMachine;
+
+ state.InitStacks();
+
+ var tracer = new GethLikeTxMemoryTracer(GethTraceOptions.Default);
+
+ ILEvmState iLEvmState = new ILEvmState(SpecProvider.ChainId, state, EvmExceptionType.None, 0, 100000, ref returnBuffer);
+ var metadata = IlAnalyzer.StripByteCode(testcase.bytecode);
+ var ctx = ILCompiler.CompileSegment("ILEVM_TEST", metadata.Item1, metadata.Item2, config);
+ ctx.PrecompiledSegment(ref iLEvmState, _blockhashProvider, TestState, CodeInfoRepository, Prague.Instance, NullTxTracer.Instance, ctx.Data);
+
+ var tracedOpcodes = tracer.BuildResult().Entries;
+
+ Assert.That(tracedOpcodes.Count, Is.EqualTo(0));
+ }
+ }
+}
diff --git a/src/Nethermind/Nethermind.Evm.Test/EvmPooledMemoryTests.cs b/src/Nethermind/Nethermind.Evm.Test/EvmPooledMemoryTests.cs
index 33c7eb093cc..3b7b05e2b5c 100644
--- a/src/Nethermind/Nethermind.Evm.Test/EvmPooledMemoryTests.cs
+++ b/src/Nethermind/Nethermind.Evm.Test/EvmPooledMemoryTests.cs
@@ -232,6 +232,10 @@ public class MyTracer : ITxTracer, IDisposable
|| IsTracingFees
|| IsTracingLogs;
+ bool IILVMTracer.IsTracingPredefinedPatterns => true;
+
+ bool IILVMTracer.IsTracingCompiledSegments => true;
+
public string lastmemline;
public void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEntry[] logs, Hash256 stateRoot = null)
@@ -389,4 +393,12 @@ public void ReportFees(UInt256 fees, UInt256 burntFees)
}
public void Dispose() { }
+
+ public void ReportPredefinedPatternExecution(long gas, int pc, string segmentID, in ExecutionEnvironment env)
+ {
+ }
+
+ public void ReportCompiledSegmentExecution(long gas, int pc, string segmentId, in ExecutionEnvironment env)
+ {
+ }
}
diff --git a/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTestsBase.cs b/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTestsBase.cs
index d1eb75997f7..6436859dffa 100644
--- a/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTestsBase.cs
+++ b/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTestsBase.cs
@@ -19,23 +19,25 @@
using Nethermind.State;
using Nethermind.Trie.Pruning;
using NUnit.Framework;
+using Nethermind.Evm.Config;
namespace Nethermind.Evm.Test;
public class VirtualMachineTestsBase
{
- protected const string SampleHexData1 = "a01234";
- protected const string SampleHexData2 = "b15678";
- protected const string HexZero = "00";
- protected const long DefaultBlockGasLimit = 8000000;
+ public const string SampleHexData1 = "a01234";
+ public const string SampleHexData2 = "b15678";
+ public const string HexZero = "00";
+ public const long DefaultBlockGasLimit = 8000000;
- private IEthereumEcdsa _ethereumEcdsa;
+ protected IEthereumEcdsa _ethereumEcdsa;
+ protected IBlockhashProvider _blockhashProvider;
protected ITransactionProcessor _processor;
- private IDb _stateDb;
+ protected IDb _stateDb;
- protected VirtualMachine Machine { get; private set; }
- protected CodeInfoRepository CodeInfoRepository { get; private set; }
- protected IWorldState TestState { get; private set; }
+ protected VirtualMachine Machine { get; set; }
+ protected CodeInfoRepository CodeInfoRepository { get; set; }
+ protected IWorldState TestState { get; set; }
protected static Address Contract { get; } = new("0xd75a3a95360e44a3874e691fb48d77855f127069");
protected static Address Sender { get; } = TestItem.AddressA;
protected static Address Recipient { get; } = TestItem.AddressB;
@@ -66,9 +68,9 @@ public virtual void Setup()
ITrieStore trieStore = new TrieStore(_stateDb, logManager);
TestState = new WorldState(trieStore, codeDb, logManager);
_ethereumEcdsa = new EthereumEcdsa(SpecProvider.ChainId);
- IBlockhashProvider blockhashProvider = new TestBlockhashProvider(SpecProvider);
+ _blockhashProvider = new TestBlockhashProvider(SpecProvider);
CodeInfoRepository = new CodeInfoRepository();
- Machine = new VirtualMachine(blockhashProvider, SpecProvider, CodeInfoRepository, logManager);
+ Machine = new VirtualMachine(_blockhashProvider, SpecProvider, CodeInfoRepository, logManager);
_processor = new TransactionProcessor(SpecProvider, TestState, Machine, CodeInfoRepository, logManager);
}
@@ -154,9 +156,9 @@ protected T ExecuteBlock(T tracer, byte[] code, ForkActivation? forkActivatio
return tracer;
}
- protected T Execute(T tracer, byte[] code, ForkActivation? forkActivation = null) where T : ITxTracer
+ protected T Execute(T tracer, byte[] code, ForkActivation? forkActivation = null, long gasLimit = 100000) where T : ITxTracer
{
- (Block block, Transaction transaction) = PrepareTx(forkActivation ?? Activation, 100000, code);
+ (Block block, Transaction transaction) = PrepareTx(forkActivation ?? Activation, gasLimit, code);
_processor.Execute(transaction, block.Header, tracer);
return tracer;
}
diff --git a/src/Nethermind/Nethermind.Evm/ByteCodeBuilderExtensions.cs b/src/Nethermind/Nethermind.Evm/ByteCodeBuilderExtensions.cs
index b94b33475f3..10b9889fd4d 100644
--- a/src/Nethermind/Nethermind.Evm/ByteCodeBuilderExtensions.cs
+++ b/src/Nethermind/Nethermind.Evm/ByteCodeBuilderExtensions.cs
@@ -112,8 +112,8 @@ public static Prepare SELFDESTRUCT(this Prepare @this, Address? address = null)
public static Prepare EXTCODEHASH(this Prepare @this, Address? address = null)
=> @this.PushSingle(address)
.Op(Instruction.EXTCODEHASH);
- public static Prepare PUSHx(this Prepare @this, byte[] args)
- => @this.PushData(args);
+ public static Prepare PUSHx(this Prepare @this, byte[] args = null)
+ => args is null ? @this.Op(Instruction.PUSH0) : @this.PushData(args);
public static Prepare MLOAD(this Prepare @this, UInt256? pos = null)
=> @this.PushSingle(pos)
.Op(Instruction.MLOAD);
diff --git a/src/Nethermind/Nethermind.Evm/CodeAnalysis/CodeInfo.cs b/src/Nethermind/Nethermind.Evm/CodeAnalysis/CodeInfo.cs
index e1bb762bceb..33e8e898562 100644
--- a/src/Nethermind/Nethermind.Evm/CodeAnalysis/CodeInfo.cs
+++ b/src/Nethermind/Nethermind.Evm/CodeAnalysis/CodeInfo.cs
@@ -3,27 +3,62 @@
using System;
using System.Threading;
-
+using Nethermind.Evm.CodeAnalysis.IL;
+using System.Runtime.CompilerServices;
using Nethermind.Evm.Precompiles;
-
+using Nethermind.Evm.Tracing;
+using Nethermind.Core.Crypto;
+using Nethermind.Evm.Config;
+using Nethermind.Logging;
+using ILMode = int;
+using Nethermind.Core;
+using Nethermind.Core.Extensions;
namespace Nethermind.Evm.CodeAnalysis
{
public class CodeInfo : IThreadPoolWorkItem
{
+ public Address? Address { get; init; }
public ReadOnlyMemory MachineCode { get; }
public IPrecompile? Precompile { get; set; }
+
+
+ // IL-EVM
+ private int _callCount;
+
+ public void NoticeExecution(IVMConfig vmConfig, ILogger logger)
+ {
+ // IL-EVM info already created
+ if (_callCount > Math.Max(vmConfig.JittingThreshold, vmConfig.PatternMatchingThreshold))
+ return;
+
+ Interlocked.Increment(ref _callCount);
+ // use Interlocked just in case of concurrent execution to run it only once
+ ILMode mode = vmConfig.IsJitEnabled && _callCount == vmConfig.JittingThreshold
+ ? IlInfo.ILMode.JIT_MODE
+ : vmConfig.IsPatternMatchingEnabled && _callCount == vmConfig.PatternMatchingThreshold
+ ? IlInfo.ILMode.PAT_MODE
+ : IlInfo.ILMode.NO_ILVM;
+
+ if (mode == IlInfo.ILMode.NO_ILVM || IlInfo.Mode.HasFlag(mode))
+ return;
+
+ IlAnalyzer.Enqueue(this, mode, vmConfig, logger);
+
+ }
private readonly JumpDestinationAnalyzer _analyzer;
private static readonly JumpDestinationAnalyzer _emptyAnalyzer = new(Array.Empty());
- public static CodeInfo Empty { get; } = new CodeInfo(Array.Empty());
+ public static CodeInfo Empty { get; } = new CodeInfo(Array.Empty(), null);
- public CodeInfo(byte[] code)
+ public CodeInfo(byte[] code, Address source = null)
{
+ Address = source;
MachineCode = code;
_analyzer = code.Length == 0 ? _emptyAnalyzer : new JumpDestinationAnalyzer(code);
}
- public CodeInfo(ReadOnlyMemory code)
+ public CodeInfo(ReadOnlyMemory code, Address source = null)
{
+ Address = source;
MachineCode = code;
_analyzer = code.Length == 0 ? _emptyAnalyzer : new JumpDestinationAnalyzer(code);
}
@@ -31,8 +66,14 @@ public CodeInfo(ReadOnlyMemory code)
public bool IsPrecompile => Precompile is not null;
public bool IsEmpty => ReferenceEquals(_analyzer, _emptyAnalyzer) && !IsPrecompile;
- public CodeInfo(IPrecompile precompile)
+ ///
+ /// Gets information whether this code info has IL-EVM optimizations ready.
+ ///
+ internal IlInfo? IlInfo { get; set; } = IlInfo.Empty;
+
+ public CodeInfo(IPrecompile precompile, Address source)
{
+ Address = source;
Precompile = precompile;
MachineCode = Array.Empty();
_analyzer = _emptyAnalyzer;
diff --git a/src/Nethermind/Nethermind.Evm/CodeAnalysis/IL/ILCompiler.cs b/src/Nethermind/Nethermind.Evm/CodeAnalysis/IL/ILCompiler.cs
new file mode 100644
index 00000000000..610b7bc9cb1
--- /dev/null
+++ b/src/Nethermind/Nethermind.Evm/CodeAnalysis/IL/ILCompiler.cs
@@ -0,0 +1,2567 @@
+// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using Nethermind.Core;
+using Nethermind.Core.Crypto;
+using Nethermind.Core.Extensions;
+using Nethermind.Core.Specs;
+using Nethermind.Evm.Config;
+using Nethermind.Evm.IL;
+using Nethermind.Evm.Tracing;
+using Nethermind.Int256;
+using Nethermind.State;
+using Sigil;
+using System;
+using System.Buffers.Binary;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.Intrinsics;
+using static Nethermind.Evm.IL.EmitExtensions;
+using Label = Sigil.Label;
+
+namespace Nethermind.Evm.CodeAnalysis.IL;
+internal class ILCompiler
+{
+ public delegate void ExecuteSegment(ref ILEvmState vmstate, IBlockhashProvider blockhashProvider, IWorldState worldState, ICodeInfoRepository codeInfoRepository, IReleaseSpec spec, ITxTracer trace, byte[][] immediatesData);
+
+ private const int VMSTATE_INDEX = 0;
+ private const int BLOCKHASH_PROVIDER_INDEX = 1;
+ private const int WORLD_STATE_INDEX = 2;
+ private const int CODE_INFO_REPOSITORY_INDEX = 3;
+ private const int SPEC_INDEX = 4;
+ private const int TXTRACER_INDEX = 5;
+ private const int IMMEDIATES_DATA_INDEX = 6;
+
+ public class SegmentExecutionCtx
+ {
+ public string Name => PrecompiledSegment.Method.Name;
+ public ExecuteSegment PrecompiledSegment;
+ public byte[][] Data;
+ public ushort[] JumpDestinations;
+ }
+ public static SegmentExecutionCtx CompileSegment(string segmentName, OpcodeInfo[] code, byte[][] data, IVMConfig config)
+ {
+ // code is optimistic assumes stack underflow and stack overflow to not occure (WE NEED EOF FOR THIS)
+ // Note(Ayman) : What stops us from adopting stack analysis from EOF in ILVM?
+ // Note(Ayman) : verify all endianness arguments and bytes
+
+ Emit method = Emit.NewDynamicMethod(segmentName, doVerify: true, strictBranchVerification: true);
+
+ ushort[] jumpdests = EmitSegmentBody(method, code, config.BakeInTracingInJitMode);
+ ExecuteSegment dynEmitedDelegate = method.CreateDelegate();
+ return new SegmentExecutionCtx
+ {
+ PrecompiledSegment = dynEmitedDelegate,
+ Data = data,
+ JumpDestinations = jumpdests
+ };
+ }
+
+ private static ushort[] EmitSegmentBody(Emit method, OpcodeInfo[] code, bool bakeInTracerCalls)
+ {
+ using Local jmpDestination = method.DeclareLocal(typeof(int));
+ using Local consumeJumpCondition = method.DeclareLocal(typeof(int));
+
+ using Local address = method.DeclareLocal(typeof(Address));
+
+ using Local hash256 = method.DeclareLocal(typeof(Hash256));
+
+ using Local uint256A = method.DeclareLocal(typeof(UInt256));
+ using Local uint256B = method.DeclareLocal(typeof(UInt256));
+ using Local uint256C = method.DeclareLocal(typeof(UInt256));
+ using Local uint256R = method.DeclareLocal(typeof(UInt256));
+
+ using Local localReadOnlyMemory = method.DeclareLocal(typeof(ReadOnlyMemory));
+ using Local localReadonOnlySpan = method.DeclareLocal(typeof(ReadOnlySpan));
+ using Local localZeroPaddedSpan = method.DeclareLocal(typeof(ZeroPaddedSpan));
+ using Local localSpan = method.DeclareLocal(typeof(Span));
+ using Local localMemory = method.DeclareLocal(typeof(Memory));
+ using Local localArray = method.DeclareLocal(typeof(byte[]));
+ using Local uint64A = method.DeclareLocal(typeof(ulong));
+
+ using Local uint32A = method.DeclareLocal(typeof(uint));
+ using Local uint32B = method.DeclareLocal(typeof(uint));
+ using Local int64A = method.DeclareLocal(typeof(long));
+ using Local int64B = method.DeclareLocal(typeof(long));
+ using Local byte8A = method.DeclareLocal(typeof(byte));
+ using Local lbool = method.DeclareLocal(typeof(bool));
+ using Local byte8B = method.DeclareLocal(typeof(byte));
+ using Local buffer = method.DeclareLocal(typeof(byte*));
+
+ using Local storageCell = method.DeclareLocal(typeof(StorageCell));
+
+ using Local gasAvailable = method.DeclareLocal(typeof(long));
+ using Local programCounter = method.DeclareLocal(typeof(ushort));
+
+ using Local stack = method.DeclareLocal(typeof(Span));
+ using Local head = method.DeclareLocal(typeof(int));
+
+
+ Dictionary evmExceptionLabels = new();
+
+ foreach (var exception in Enum.GetValues())
+ {
+ evmExceptionLabels.Add(exception, method.DefineLabel());
+ }
+
+ Label exit = method.DefineLabel(); // the label just before return
+ Label jumpTable = method.DefineLabel(); // jump table
+ Label isContinuation = method.DefineLabel(); // jump table
+ Label ret = method.DefineLabel();
+
+ // allocate stack
+ method.LoadArgument(VMSTATE_INDEX);
+ method.Duplicate();
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.Stack)));
+ method.Call(GetCastMethodInfo());
+ method.StoreLocal(stack);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.StackHead)));
+ method.StoreLocal(head);
+
+ // set gas to local
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.GasAvailable)));
+ method.Convert();
+ method.StoreLocal(gasAvailable);
+
+ // set pc to local
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.ProgramCounter)));
+ method.StoreLocal(programCounter);
+
+ // if last ilvmstate was a jump
+ method.LoadLocal(programCounter);
+ method.LoadConstant(code[0].ProgramCounter);
+ method.CompareEqual();
+ method.BranchIfFalse(isContinuation);
+
+ Dictionary jumpDestinations = new();
+
+ var costs = BuildCostLookup(code);
+
+ // Idea(Ayman) : implement every opcode as a method, and then inline the IL of the method in the main method
+ for (int i = 0; i < code.Length; i++)
+ {
+ OpcodeInfo op = code[i];
+ if (op.Operation is Instruction.JUMPDEST)
+ {
+ // mark the jump destination
+ jumpDestinations[op.ProgramCounter] = method.DefineLabel();
+ method.MarkLabel(jumpDestinations[op.ProgramCounter]);
+ method.LoadConstant(op.ProgramCounter);
+ method.StoreLocal(programCounter);
+ }
+
+
+ if (bakeInTracerCalls)
+ {
+ EmitCallToStartInstructionTrace(method, gasAvailable, head, op);
+ }
+
+ // check if opcode is activated in current spec
+ method.LoadArgument(SPEC_INDEX);
+ method.LoadConstant((byte)op.Operation);
+ method.Call(typeof(InstructionExtensions).GetMethod(nameof(InstructionExtensions.IsEnabled)));
+ method.BranchIfFalse(evmExceptionLabels[EvmExceptionType.BadInstruction]);
+
+ if (!bakeInTracerCalls) {
+ if (costs.ContainsKey(op.ProgramCounter) && costs[op.ProgramCounter] > 0)
+ {
+ method.LoadLocal(gasAvailable);
+ method.LoadConstant(costs[op.ProgramCounter]);
+ method.BranchIfLess(evmExceptionLabels[EvmExceptionType.OutOfGas]);
+
+ method.LoadLocal(gasAvailable);
+ method.LoadConstant(costs[op.ProgramCounter]);
+ method.Subtract();
+ method.StoreLocal(gasAvailable);
+ }
+ } else
+ {
+ method.LoadLocal(gasAvailable);
+ method.LoadConstant(op.Metadata.GasCost);
+ method.Subtract();
+ method.Duplicate();
+ method.StoreLocal(gasAvailable);
+ method.LoadConstant((long)0);
+ method.BranchIfLess(evmExceptionLabels[EvmExceptionType.OutOfGas]);
+ }
+
+ if (i == code.Length - 1)
+ {
+ method.LoadConstant(op.ProgramCounter + op.Metadata.AdditionalBytes);
+ method.StoreLocal(programCounter);
+ }
+
+ if (op.Metadata.StackBehaviorPop > 0)
+ {
+ method.LoadLocal(head);
+ method.LoadConstant(op.Metadata.StackBehaviorPop);
+ method.BranchIfLess(evmExceptionLabels[EvmExceptionType.StackUnderflow]);
+ }
+
+ if (op.Metadata.StackBehaviorPush > 0)
+ {
+ int delta = op.Metadata.StackBehaviorPush - op.Metadata.StackBehaviorPop;
+ method.LoadLocal(head);
+ method.LoadConstant(delta);
+ method.Add();
+ method.LoadConstant(EvmStack.MaxStackSize);
+ method.BranchIfGreaterOrEqual(evmExceptionLabels[EvmExceptionType.StackOverflow]);
+ }
+
+ // else emit
+ switch (op.Operation)
+ {
+ case Instruction.JUMPDEST:
+ // we do nothing
+ break;
+ case Instruction.STOP:
+ {
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadConstant(true);
+ method.StoreField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.ShouldStop)));
+ method.FakeBranch(ret);
+ }
+ break;
+ case Instruction.CHAINID:
+ {
+ method.CleanAndLoadWord(stack, head);
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.ChainId)));
+ method.Call(Word.SetULong0);
+ method.StackPush(head);
+ }
+ break;
+ case Instruction.NOT:
+ {
+ var refWordToRefByteMethod = GetAsMethodInfo();
+ var readVector256Method = GetReadUnalignedMethodInfo>();
+ var writeVector256Method = GetWriteUnalignedMethodInfo>();
+ var notVector256Method = typeof(Vector256)
+ .GetMethod(nameof(Vector256.OnesComplement), BindingFlags.Public | BindingFlags.Static)!
+ .MakeGenericMethod(typeof(byte));
+
+ method.StackLoadPrevious(stack, head, 1);
+ method.Call(refWordToRefByteMethod);
+ method.Duplicate();
+ method.Call(readVector256Method);
+ method.Call(notVector256Method);
+ method.Call(writeVector256Method);
+ }
+ break;
+ case Instruction.JUMP:
+ {
+ // we jump into the jump table
+ if (bakeInTracerCalls)
+ {
+ EmitCallToEndInstructionTrace(method, gasAvailable);
+ }
+ method.FakeBranch(jumpTable);
+ }
+ break;
+ case Instruction.JUMPI:
+ {// consume the jump condition
+ Label noJump = method.DefineLabel();
+ method.StackLoadPrevious(stack, head, 2);
+ method.Call(Word.GetIsZero);
+ // if the jump condition is false, we do not jump
+ method.BranchIfTrue(noJump);
+
+ // load the jump address
+ method.LoadConstant(1);
+ method.StoreLocal(consumeJumpCondition);
+
+ // we jump into the jump table
+
+ if (bakeInTracerCalls)
+ {
+ EmitCallToEndInstructionTrace(method, gasAvailable);
+ }
+ method.Branch(jumpTable);
+
+ method.MarkLabel(noJump);
+ method.StackPop(head, 2);
+ }
+ break;
+ case Instruction.PUSH0:
+ {
+ method.CleanWord(stack, head);
+ method.StackPush(head);
+ }
+ break;
+ case Instruction.PUSH1:
+ case Instruction.PUSH2:
+ case Instruction.PUSH3:
+ case Instruction.PUSH4:
+ case Instruction.PUSH5:
+ case Instruction.PUSH6:
+ case Instruction.PUSH7:
+ case Instruction.PUSH8:
+ case Instruction.PUSH9:
+ case Instruction.PUSH10:
+ case Instruction.PUSH11:
+ case Instruction.PUSH12:
+ case Instruction.PUSH13:
+ case Instruction.PUSH14:
+ case Instruction.PUSH15:
+ case Instruction.PUSH16:
+ case Instruction.PUSH17:
+ case Instruction.PUSH18:
+ case Instruction.PUSH19:
+ case Instruction.PUSH20:
+ case Instruction.PUSH21:
+ case Instruction.PUSH22:
+ case Instruction.PUSH23:
+ case Instruction.PUSH24:
+ case Instruction.PUSH25:
+ case Instruction.PUSH26:
+ case Instruction.PUSH27:
+ case Instruction.PUSH28:
+ case Instruction.PUSH29:
+ case Instruction.PUSH30:
+ case Instruction.PUSH31:
+ case Instruction.PUSH32:
+ {// we load the stack
+ method.CleanAndLoadWord(stack, head);
+
+ // we load the span of bytes
+ method.LoadArgument(IMMEDIATES_DATA_INDEX);
+ method.LoadConstant(op.Arguments.Value);
+ method.LoadElement();
+ method.Call(Word.SetArray);
+ method.StackPush(head);
+ }
+ break;
+ case Instruction.ADD:
+ EmitBinaryUInt256Method(method, uint256R, (stack, head), typeof(UInt256).GetMethod(nameof(UInt256.Add), BindingFlags.Public | BindingFlags.Static)!, null, evmExceptionLabels, uint256A, uint256B);
+ break;
+ case Instruction.SUB:
+ EmitBinaryUInt256Method(method, uint256R, (stack, head), typeof(UInt256).GetMethod(nameof(UInt256.Subtract), BindingFlags.Public | BindingFlags.Static)!, null, evmExceptionLabels, uint256A, uint256B);
+ break;
+ case Instruction.MUL:
+ EmitBinaryUInt256Method(method, uint256R, (stack, head), typeof(UInt256).GetMethod(nameof(UInt256.Multiply), BindingFlags.Public | BindingFlags.Static)!, null, evmExceptionLabels, uint256A, uint256B);
+ break;
+ case Instruction.MOD:
+ EmitBinaryUInt256Method(method, uint256R, (stack, head), typeof(UInt256).GetMethod(nameof(UInt256.Mod), BindingFlags.Public | BindingFlags.Static)!,
+ (il, postInstructionLabel, locals) =>
+ {
+ Label label = il.DefineLabel();
+
+ il.LoadLocalAddress(locals[1]);
+ il.Call(GetPropertyInfo(typeof(UInt256), nameof(UInt256.IsZero), false, out _));
+ il.BranchIfFalse(label);
+
+ il.LoadConstant(0);
+ il.Call(ConvertionExplicit());
+ il.StoreLocal(uint256R);
+ il.Branch(postInstructionLabel);
+
+ il.MarkLabel(label);
+ }, evmExceptionLabels, uint256A, uint256B);
+ break;
+ case Instruction.SMOD:
+ EmitBinaryInt256Method(method, uint256R, (stack, head), typeof(Int256.Int256).GetMethod(nameof(Int256.Int256.Mod), BindingFlags.Public | BindingFlags.Static, [typeof(Int256.Int256).MakeByRefType(), typeof(Int256.Int256).MakeByRefType(), typeof(Int256.Int256).MakeByRefType()])!,
+ (il, postInstructionLabel, locals) =>
+ {
+ Label bIsNotZeroOrOneLabel = il.DefineLabel();
+
+ il.LoadLocalAddress(locals[1]);
+ il.Call(GetPropertyInfo(typeof(UInt256), nameof(UInt256.IsZeroOrOne), false, out _));
+ il.BranchIfFalse(bIsNotZeroOrOneLabel);
+
+ il.LoadField(GetFieldInfo(nameof(UInt256.Zero), BindingFlags.Static | BindingFlags.Public));
+ il.StoreLocal(uint256R);
+ il.Branch(postInstructionLabel);
+
+ il.MarkLabel(bIsNotZeroOrOneLabel);
+ }, evmExceptionLabels, uint256A, uint256B);
+ break;
+ case Instruction.DIV:
+ EmitBinaryUInt256Method(method, uint256R, (stack, head), typeof(UInt256).GetMethod(nameof(UInt256.Divide), BindingFlags.Public | BindingFlags.Static)!,
+ (il, postInstructionLabel, locals) =>
+ {
+ Label label = il.DefineLabel();
+
+ il.LoadLocalAddress(locals[1]);
+ il.Call(GetPropertyInfo(typeof(UInt256), nameof(UInt256.IsZero), false, out _));
+ il.BranchIfFalse(label);
+
+ il.LoadField(GetFieldInfo(nameof(UInt256.Zero), BindingFlags.Static | BindingFlags.Public));
+ il.StoreLocal(uint256R);
+ il.Branch(postInstructionLabel);
+
+ il.MarkLabel(label);
+ }, evmExceptionLabels, uint256A, uint256B);
+ break;
+ case Instruction.SDIV:
+ EmitBinaryInt256Method(method, uint256R, (stack, head), typeof(Int256.Int256).GetMethod(nameof(Int256.Int256.Divide), BindingFlags.Public | BindingFlags.Static, [typeof(Int256.Int256).MakeByRefType(), typeof(Int256.Int256).MakeByRefType(), typeof(Int256.Int256).MakeByRefType()])!,
+ (il, postInstructionLabel, locals) =>
+ {
+ Label bIsNotZero = il.DefineLabel();
+ Label bIsNotMinusOneLabel = il.DefineLabel();
+
+ il.LoadLocalAddress(locals[1]);
+ il.Call(GetPropertyInfo(typeof(UInt256), nameof(UInt256.IsZero), false, out _));
+ il.BranchIfFalse(bIsNotZero);
+
+ il.LoadField(typeof(UInt256).GetField(nameof(UInt256.Zero), BindingFlags.Static | BindingFlags.Public));
+ il.StoreLocal(uint256R);
+ il.Branch(postInstructionLabel);
+
+ il.MarkLabel(bIsNotZero);
+
+ il.LoadLocalAddress(locals[1]);
+ il.Call(GetAsMethodInfo());
+ il.LoadFieldAddress(typeof(Int256.Int256).GetField(nameof(Int256.Int256.MinusOne), BindingFlags.Static | BindingFlags.Public));
+ il.Call(typeof(Int256.Int256).GetMethod("op_Equality"));
+
+ il.LoadLocalAddress(locals[0]);
+ il.Call(typeof(VirtualMachine).GetProperty(nameof(VirtualMachine.P255), BindingFlags.Static | BindingFlags.NonPublic).GetMethod);
+ il.Call(typeof(UInt256).GetMethod("op_Equality", new[] { typeof(UInt256).MakeByRefType(), typeof(UInt256).MakeByRefType() }));
+ il.And();
+ il.BranchIfFalse(bIsNotMinusOneLabel);
+
+ il.Call(typeof(VirtualMachine).GetProperty(nameof(VirtualMachine.P255), BindingFlags.Static | BindingFlags.NonPublic).GetMethod);
+ il.LoadObject(typeof(UInt256));
+ il.StoreLocal(uint256R);
+ il.Branch(postInstructionLabel);
+
+ il.MarkLabel(bIsNotMinusOneLabel);
+ }, evmExceptionLabels, uint256A, uint256B);
+ break;
+ case Instruction.ADDMOD:
+ EmitTrinaryUInt256Method(method, uint256R, (stack, head), typeof(UInt256).GetMethod(nameof(UInt256.AddMod), BindingFlags.Public | BindingFlags.Static)!,
+ (il, postInstructionLabel, locals) =>
+ {
+ Label cIsNotZeroLabel = il.DefineLabel();
+
+ il.LoadLocalAddress(locals[2]);
+ il.Call(GetPropertyInfo(typeof(UInt256), nameof(UInt256.IsZeroOrOne), false, out _));
+ il.BranchIfFalse(cIsNotZeroLabel);
+
+ il.LoadField(GetFieldInfo(nameof(UInt256.Zero), BindingFlags.Static | BindingFlags.Public));
+ il.StoreLocal(uint256R);
+ il.Branch(postInstructionLabel);
+
+ il.MarkLabel(cIsNotZeroLabel);
+ }, evmExceptionLabels, uint256A, uint256B, uint256C);
+ break;
+ case Instruction.MULMOD:
+ EmitTrinaryUInt256Method(method, uint256R, (stack, head), typeof(UInt256).GetMethod(nameof(UInt256.MultiplyMod), BindingFlags.Public | BindingFlags.Static)!,
+ (il, postInstructionLabel, locals) =>
+ {
+ Label cIsNotZeroLabel = il.DefineLabel();
+
+ il.LoadLocalAddress(locals[2]);
+ il.Call(GetPropertyInfo(typeof(UInt256), nameof(UInt256.IsZeroOrOne), false, out _));
+ il.BranchIfFalse(cIsNotZeroLabel);
+
+ il.LoadField(GetFieldInfo(nameof(UInt256.Zero), BindingFlags.Static | BindingFlags.Public));
+ il.StoreLocal(uint256R);
+ il.Branch(postInstructionLabel);
+
+ il.MarkLabel(cIsNotZeroLabel);
+ }, evmExceptionLabels, uint256A, uint256B, uint256C);
+ break;
+ case Instruction.SHL:
+ EmitShiftUInt256Method(method, uint256R, (stack, head), isLeft: true, evmExceptionLabels, uint256A, uint256B);
+ break;
+ case Instruction.SHR:
+ EmitShiftUInt256Method(method, uint256R, (stack, head), isLeft: false, evmExceptionLabels, uint256A, uint256B);
+ break;
+ case Instruction.SAR:
+ EmitShiftInt256Method(method, uint256R, (stack, head), evmExceptionLabels, uint256A, uint256B);
+ break;
+ case Instruction.AND:
+ EmitBitwiseUInt256Method(method, uint256R, (stack, head), typeof(Vector256).GetMethod(nameof(Vector256.BitwiseAnd), BindingFlags.Public | BindingFlags.Static)!, evmExceptionLabels);
+ break;
+ case Instruction.OR:
+ EmitBitwiseUInt256Method(method, uint256R, (stack, head), typeof(Vector256).GetMethod(nameof(Vector256.BitwiseOr), BindingFlags.Public | BindingFlags.Static)!, evmExceptionLabels);
+ break;
+ case Instruction.XOR:
+ EmitBitwiseUInt256Method(method, uint256R, (stack, head), typeof(Vector256).GetMethod(nameof(Vector256.Xor), BindingFlags.Public | BindingFlags.Static)!, evmExceptionLabels);
+ break;
+ case Instruction.EXP:
+ {
+ Label powerIsZero = method.DefineLabel();
+ Label baseIsOneOrZero = method.DefineLabel();
+ Label endOfExpImpl = method.DefineLabel();
+
+ method.StackLoadPrevious(stack, head, 1);
+ method.Call(Word.GetUInt256);
+ method.StoreLocal(uint256A);
+ method.StackLoadPrevious(stack, head, 2);
+ method.Duplicate();
+ method.Call(Word.LeadingZeroProp);
+ method.StoreLocal(uint64A);
+ method.Call(Word.GetUInt256);
+ method.StoreLocal(uint256B);
+ method.StackPop(head, 2);
+
+ method.LoadLocalAddress(uint256B);
+ method.Call(typeof(UInt256).GetProperty(nameof(UInt256.IsZero)).GetMethod!);
+ method.BranchIfTrue(powerIsZero);
+
+ // load spec
+ method.LoadLocal(gasAvailable);
+ method.LoadArgument(SPEC_INDEX);
+ method.Call(typeof(ReleaseSpecExtensions).GetMethod(nameof(ReleaseSpecExtensions.GetExpByteCost)));
+ method.LoadConstant((long)32);
+ method.LoadLocal(uint64A);
+ method.Subtract();
+ method.Multiply();
+ method.Subtract();
+ method.Duplicate();
+ method.StoreLocal(gasAvailable);
+ method.LoadConstant((long)0);
+ method.BranchIfLess(evmExceptionLabels[EvmExceptionType.OutOfGas]);
+
+ method.LoadLocalAddress(uint256A);
+ method.Call(typeof(UInt256).GetProperty(nameof(UInt256.IsZeroOrOne)).GetMethod!);
+ method.BranchIfTrue(baseIsOneOrZero);
+
+ method.LoadLocalAddress(uint256A);
+ method.LoadLocalAddress(uint256B);
+ method.LoadLocalAddress(uint256R);
+ method.Call(typeof(UInt256).GetMethod(nameof(UInt256.Exp), BindingFlags.Public | BindingFlags.Static)!);
+
+ method.CleanAndLoadWord(stack, head);
+ method.LoadLocal(uint256R);
+ method.Call(Word.SetUInt256);
+
+ method.Branch(endOfExpImpl);
+
+ method.MarkLabel(powerIsZero);
+ method.CleanAndLoadWord(stack, head);
+ method.LoadConstant(1);
+ method.Call(Word.SetUInt0);
+ method.Branch(endOfExpImpl);
+
+ method.MarkLabel(baseIsOneOrZero);
+ method.CleanAndLoadWord(stack, head);
+ method.LoadLocal(uint256A);
+ method.Call(Word.SetUInt256);
+ method.Branch(endOfExpImpl);
+
+ method.MarkLabel(endOfExpImpl);
+ method.StackPush(head);
+ }
+ break;
+ case Instruction.LT:
+ EmitComparaisonUInt256Method(method, uint256R, (stack, head), typeof(UInt256).GetMethod("op_LessThan", new[] { typeof(UInt256).MakeByRefType(), typeof(UInt256).MakeByRefType() }), evmExceptionLabels, uint256A, uint256B);
+ break;
+ case Instruction.GT:
+ EmitComparaisonUInt256Method(method, uint256R, (stack, head), typeof(UInt256).GetMethod("op_GreaterThan", new[] { typeof(UInt256).MakeByRefType(), typeof(UInt256).MakeByRefType() }), evmExceptionLabels, uint256A, uint256B);
+ break;
+ case Instruction.SLT:
+ EmitComparaisonInt256Method(method, uint256R, (stack, head), typeof(Int256.Int256).GetMethod(nameof(Int256.Int256.CompareTo), new[] { typeof(Int256.Int256) }), false, evmExceptionLabels, uint256A, uint256B);
+ break;
+ case Instruction.SGT:
+ EmitComparaisonInt256Method(method, uint256R, (stack, head), typeof(Int256.Int256).GetMethod(nameof(Int256.Int256.CompareTo), new[] { typeof(Int256.Int256) }), true, evmExceptionLabels, uint256A, uint256B);
+ break;
+ case Instruction.EQ:
+ {
+ var refWordToRefByteMethod = GetAsMethodInfo();
+ var readVector256Method = GetReadUnalignedMethodInfo>();
+ var writeVector256Method = GetWriteUnalignedMethodInfo>();
+ var operationUnegenerified = typeof(Vector256).GetMethod(nameof(Vector256.EqualsAll), BindingFlags.Public | BindingFlags.Static)!.MakeGenericMethod(typeof(byte));
+
+ method.StackLoadPrevious(stack, head, 1);
+ method.Call(refWordToRefByteMethod);
+ method.Call(readVector256Method);
+ method.StackLoadPrevious(stack, head, 2);
+ method.Call(refWordToRefByteMethod);
+ method.Call(readVector256Method);
+ method.StackPop(head, 2);
+
+ method.Call(operationUnegenerified);
+ method.StoreLocal(lbool);
+
+ method.CleanAndLoadWord(stack, head);
+ method.LoadLocal(lbool);
+ method.Convert();
+ method.Call(Word.SetUInt0);
+ method.StackPush(head);
+ }
+ break;
+ case Instruction.ISZERO:
+ {// we load the stack
+ method.StackLoadPrevious(stack, head, 1);
+ method.Duplicate();
+ method.Duplicate();
+ method.Call(Word.GetIsZero);
+ method.StoreLocal(lbool);
+ method.Call(Word.SetToZero);
+ method.LoadLocal(lbool);
+ method.Call(Word.SetByte0);
+ }
+ break;
+ case Instruction.POP:
+ {
+ method.StackPop(head);
+ }
+ break;
+ case Instruction.DUP1:
+ case Instruction.DUP2:
+ case Instruction.DUP3:
+ case Instruction.DUP4:
+ case Instruction.DUP5:
+ case Instruction.DUP6:
+ case Instruction.DUP7:
+ case Instruction.DUP8:
+ case Instruction.DUP9:
+ case Instruction.DUP10:
+ case Instruction.DUP11:
+ case Instruction.DUP12:
+ case Instruction.DUP13:
+ case Instruction.DUP14:
+ case Instruction.DUP15:
+ case Instruction.DUP16:
+ {
+ int count = (int)op.Operation - (int)Instruction.DUP1 + 1;
+ method.Load(stack, head);
+ method.StackLoadPrevious(stack, head, count);
+ method.LoadObject(typeof(Word));
+ method.StoreObject(typeof(Word));
+ method.StackPush(head);
+ }
+ break;
+ case Instruction.SWAP1:
+ case Instruction.SWAP2:
+ case Instruction.SWAP3:
+ case Instruction.SWAP4:
+ case Instruction.SWAP5:
+ case Instruction.SWAP6:
+ case Instruction.SWAP7:
+ case Instruction.SWAP8:
+ case Instruction.SWAP9:
+ case Instruction.SWAP10:
+ case Instruction.SWAP11:
+ case Instruction.SWAP12:
+ case Instruction.SWAP13:
+ case Instruction.SWAP14:
+ case Instruction.SWAP15:
+ case Instruction.SWAP16:
+ {
+ var count = (int)op.Operation - (int)Instruction.SWAP1 + 1;
+
+ method.LoadLocalAddress(uint256R);
+ method.StackLoadPrevious(stack, head, 1);
+ method.LoadObject(typeof(Word));
+ method.StoreObject(typeof(Word));
+
+ method.StackLoadPrevious(stack, head, 1);
+ method.StackLoadPrevious(stack, head, count + 1);
+ method.LoadObject(typeof(Word));
+ method.StoreObject(typeof(Word));
+
+ method.StackLoadPrevious(stack, head, count + 1);
+ method.LoadLocalAddress(uint256R);
+ method.LoadObject(typeof(Word));
+ method.StoreObject(typeof(Word));
+ }
+ break;
+ case Instruction.CODESIZE:
+ {
+ var lastOpcode = code[^1];
+ method.CleanAndLoadWord(stack, head);
+ method.LoadConstant(lastOpcode.ProgramCounter + lastOpcode.Metadata.AdditionalBytes + 1);
+ method.Call(Word.SetInt0);
+ method.StackPush(head);
+ }
+ break;
+ case Instruction.PC:
+ {
+ method.CleanAndLoadWord(stack, head);
+ method.LoadConstant((uint)op.ProgramCounter);
+ method.Call(Word.SetUInt0);
+ method.StackPush(head);
+ }
+ break;
+ case Instruction.COINBASE:
+ {
+ method.CleanAndLoadWord(stack, head);
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.BlkCtx)));
+ method.Call(GetPropertyInfo(typeof(BlockExecutionContext), nameof(BlockExecutionContext.Header), false, out _));
+ method.Call(GetPropertyInfo(nameof(BlockHeader.GasBeneficiary), false, out _));
+ method.Call(Word.SetAddress);
+ method.StackPush(head);
+ }
+ break;
+ case Instruction.TIMESTAMP:
+ {
+ method.CleanAndLoadWord(stack, head);
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.BlkCtx)));
+ method.Call(GetPropertyInfo(typeof(BlockExecutionContext), nameof(BlockExecutionContext.Header), false, out _));
+ method.Call(GetPropertyInfo(nameof(BlockHeader.Timestamp), false, out _));
+ method.Call(Word.SetULong0);
+ method.StackPush(head);
+ }
+ break;
+ case Instruction.NUMBER:
+ {
+ method.CleanAndLoadWord(stack, head);
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.BlkCtx)));
+ method.Call(GetPropertyInfo(typeof(BlockExecutionContext), nameof(BlockExecutionContext.Header), false, out _));
+ method.Call(GetPropertyInfo(nameof(BlockHeader.Number), false, out _));
+ method.Call(Word.SetULong0);
+ method.StackPush(head);
+ }
+ break;
+ case Instruction.GASLIMIT:
+ {
+ method.CleanAndLoadWord(stack, head);
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.BlkCtx)));
+ method.Call(GetPropertyInfo(typeof(BlockExecutionContext), nameof(BlockExecutionContext.Header), false, out _));
+ method.Call(GetPropertyInfo(nameof(BlockHeader.GasLimit), false, out _));
+ method.Call(Word.SetULong0);
+ method.StackPush(head);
+ }
+ break;
+ case Instruction.CALLER:
+ {
+ method.CleanAndLoadWord(stack, head);
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.Env)));
+ method.LoadField(GetFieldInfo(typeof(ExecutionEnvironment), nameof(ExecutionEnvironment.Caller)));
+ method.Call(Word.SetAddress);
+ method.StackPush(head);
+ }
+ break;
+ case Instruction.ADDRESS:
+ {
+ method.CleanAndLoadWord(stack, head);
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.Env)));
+ method.LoadField(GetFieldInfo(typeof(ExecutionEnvironment), nameof(ExecutionEnvironment.ExecutingAccount)));
+ method.Call(Word.SetAddress);
+ method.StackPush(head);
+ }
+ break;
+ case Instruction.ORIGIN:
+ {
+ method.CleanAndLoadWord(stack, head);
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.TxCtx)));
+ method.Call(GetPropertyInfo(typeof(TxExecutionContext), nameof(TxExecutionContext.Origin), false, out _));
+ method.Call(Word.SetAddress);
+ method.StackPush(head);
+ }
+ break;
+ case Instruction.CALLVALUE:
+ {
+ method.CleanAndLoadWord(stack, head);
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.Env)));
+ method.LoadField(GetFieldInfo(typeof(ExecutionEnvironment), nameof(ExecutionEnvironment.Value)));
+ method.Call(Word.SetUInt256);
+ method.StackPush(head);
+ }
+ break;
+ case Instruction.GASPRICE:
+ {
+ method.CleanAndLoadWord(stack, head);
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.TxCtx)));
+ method.Call(GetPropertyInfo(typeof(TxExecutionContext), nameof(TxExecutionContext.GasPrice), false, out _));
+ method.Call(Word.SetUInt256);
+ method.StackPush(head);
+ }
+ break;
+ case Instruction.CALLDATACOPY:
+ {
+ Label endOfOpcode = method.DefineLabel();
+
+ method.StackLoadPrevious(stack, head, 1);
+ method.Call(Word.GetUInt256);
+ method.StoreLocal(uint256A);
+ method.StackLoadPrevious(stack, head, 2);
+ method.Call(Word.GetUInt256);
+ method.StoreLocal(uint256B);
+ method.StackLoadPrevious(stack, head, 3);
+ method.Call(Word.GetUInt256);
+ method.StoreLocal(uint256C);
+ method.StackPop(head, 3);
+
+ method.LoadLocal(gasAvailable);
+ method.LoadLocalAddress(uint256C);
+ method.LoadLocalAddress(lbool);
+ method.Call(typeof(EvmPooledMemory).GetMethod(nameof(EvmPooledMemory.Div32Ceiling), [typeof(UInt256).MakeByRefType(), typeof(bool).MakeByRefType()]));
+ method.LoadConstant(GasCostOf.Memory);
+ method.Multiply();
+ method.Subtract();
+ method.Duplicate();
+ method.StoreLocal(gasAvailable);
+ method.LoadConstant((long)0);
+ method.BranchIfLess(evmExceptionLabels[EvmExceptionType.OutOfGas]);
+
+ method.LoadLocalAddress(uint256C);
+ method.Call(typeof(UInt256).GetProperty(nameof(UInt256.IsZero)).GetMethod!);
+ method.BranchIfTrue(endOfOpcode);
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.EvmState)));
+ method.LoadLocalAddress(gasAvailable);
+ method.LoadLocalAddress(uint256A);
+ method.LoadLocalAddress(uint256C);
+ method.Call(typeof(VirtualMachine).GetMethod(nameof(VirtualMachine.UpdateMemoryCost)));
+ method.BranchIfFalse(evmExceptionLabels[EvmExceptionType.OutOfGas]);
+
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.InputBuffer)));
+ method.LoadObject(typeof(ReadOnlyMemory));
+ method.LoadLocalAddress(uint256B);
+ method.LoadLocal(uint256C);
+ method.LoadField(GetFieldInfo(typeof(UInt256), nameof(UInt256.u0)));
+ method.Convert();
+ method.LoadConstant((int)PadDirection.Right);
+ method.Call(typeof(ByteArrayExtensions).GetMethod(nameof(ByteArrayExtensions.SliceWithZeroPadding), [typeof(ReadOnlyMemory), typeof(UInt256).MakeByRefType(), typeof(int), typeof(PadDirection)]));
+ method.StoreLocal(localZeroPaddedSpan);
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.Memory)));
+ method.LoadLocalAddress(uint256A);
+ method.LoadLocalAddress(localZeroPaddedSpan);
+ method.CallVirtual(typeof(EvmPooledMemory).GetMethod(nameof(EvmPooledMemory.Save), [typeof(UInt256).MakeByRefType(), typeof(ZeroPaddedSpan).MakeByRefType()]));
+
+ method.MarkLabel(endOfOpcode);
+ }
+ break;
+ case Instruction.CALLDATALOAD:
+ {
+ method.StackLoadPrevious(stack, head, 1);
+ method.Call(Word.GetUInt256);
+ method.StoreLocal(uint256A);
+ method.StackPop(head, 1);
+
+ method.CleanAndLoadWord(stack, head);
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.InputBuffer)));
+ method.LoadObject(typeof(ReadOnlyMemory));
+
+ method.LoadLocalAddress(uint256A);
+ method.LoadConstant(Word.Size);
+ method.LoadConstant((int)PadDirection.Right);
+ method.Call(typeof(ByteArrayExtensions).GetMethod(nameof(ByteArrayExtensions.SliceWithZeroPadding), [typeof(ReadOnlyMemory), typeof(UInt256).MakeByRefType(), typeof(int), typeof(PadDirection)]));
+ method.LoadField(GetFieldInfo(typeof(ZeroPaddedSpan), nameof(ZeroPaddedSpan.Span)));
+ method.Call(Word.SetSpan);
+ method.StackPush(head);
+ }
+ break;
+ case Instruction.CALLDATASIZE:
+ {
+ method.CleanAndLoadWord(stack, head);
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.InputBuffer)));
+ method.Call(GetPropertyInfo>(nameof(ReadOnlyMemory.Length), false, out _));
+ method.Call(Word.SetInt0);
+ method.StackPush(head);
+ }
+ break;
+ case Instruction.MSIZE:
+ {
+ method.CleanAndLoadWord(stack, head);
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.Memory)));
+ method.Call(GetPropertyInfo(nameof(EvmPooledMemory.Size), false, out _));
+ method.Call(Word.SetULong0);
+ method.StackPush(head);
+ }
+ break;
+ case Instruction.MSTORE:
+ {
+ method.StackLoadPrevious(stack, head, 1);
+ method.Call(Word.GetUInt256);
+ method.StoreLocal(uint256A);
+ method.StackLoadPrevious(stack, head, 2);
+ method.Call(Word.GetUInt256);
+ method.StoreLocal(uint256B);
+ method.StackPop(head, 2);
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.EvmState)));
+ method.LoadLocalAddress(gasAvailable);
+ method.LoadLocalAddress(uint256A);
+ method.LoadConstant(Word.Size);
+ method.Call(ConvertionExplicit());
+ method.StoreLocal(uint256C);
+ method.LoadLocalAddress(uint256C);
+ method.Call(typeof(VirtualMachine).GetMethod(nameof(VirtualMachine.UpdateMemoryCost)));
+ method.BranchIfFalse(evmExceptionLabels[EvmExceptionType.OutOfGas]);
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.Memory)));
+ method.LoadLocalAddress(uint256A);
+ method.LoadLocalAddress(uint256B);
+ method.LoadConstant(Word.Size);
+ method.Call(typeof(UInt256).GetMethod(nameof(UInt256.PaddedBytes)));
+ method.Call(ConvertionImplicit(typeof(Span), typeof(byte[])));
+ method.Call(typeof(EvmPooledMemory).GetMethod(nameof(EvmPooledMemory.SaveWord)));
+ }
+ break;
+ case Instruction.MSTORE8:
+ {
+ method.StackLoadPrevious(stack, head, 1);
+ method.Call(Word.GetUInt256);
+ method.StoreLocal(uint256A);
+ method.StackLoadPrevious(stack, head, 2);
+ method.Call(Word.GetByte0);
+ method.StoreLocal(byte8A);
+ method.StackPop(head, 2);
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.EvmState)));
+ method.LoadLocalAddress(gasAvailable);
+ method.LoadLocalAddress(uint256A);
+ method.LoadConstant(1);
+ method.Call(ConvertionExplicit());
+ method.StoreLocal(uint256C);
+ method.LoadLocalAddress(uint256C);
+ method.Call(typeof(VirtualMachine).GetMethod(nameof(VirtualMachine.UpdateMemoryCost)));
+ method.BranchIfFalse(evmExceptionLabels[EvmExceptionType.OutOfGas]);
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.Memory)));
+ method.LoadLocalAddress(uint256A);
+ method.LoadLocal(byte8A);
+
+ method.Call(typeof(EvmPooledMemory).GetMethod(nameof(EvmPooledMemory.SaveByte)));
+ }
+ break;
+ case Instruction.MLOAD:
+ {
+ method.StackLoadPrevious(stack, head, 1);
+ method.Call(Word.GetUInt256);
+ method.StoreLocal(uint256A);
+ method.StackPop(head, 1);
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.EvmState)));
+ method.LoadLocalAddress(gasAvailable);
+ method.LoadLocalAddress(uint256A);
+ method.LoadFieldAddress(GetFieldInfo(typeof(VirtualMachine), nameof(VirtualMachine.BigInt32)));
+ method.Call(typeof(VirtualMachine).GetMethod(nameof(VirtualMachine.UpdateMemoryCost)));
+ method.BranchIfFalse(evmExceptionLabels[EvmExceptionType.OutOfGas]);
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.Memory)));
+ method.LoadLocalAddress(uint256A);
+ method.Call(typeof(EvmPooledMemory).GetMethod(nameof(EvmPooledMemory.LoadSpan), [typeof(UInt256).MakeByRefType()]));
+ method.Call(ConvertionImplicit(typeof(Span), typeof(Span)));
+ method.StoreLocal(localReadonOnlySpan);
+
+ method.CleanAndLoadWord(stack, head);
+ method.LoadLocalAddress(localReadonOnlySpan);
+ method.LoadConstant(BitConverter.IsLittleEndian);
+ method.NewObject(typeof(UInt256), typeof(ReadOnlySpan).MakeByRefType(), typeof(bool));
+ method.Call(Word.SetUInt256);
+ method.StackPush(head);
+ }
+ break;
+ case Instruction.MCOPY:
+ {
+ method.StackLoadPrevious(stack, head, 1);
+ method.Call(Word.GetUInt256);
+ method.StoreLocal(uint256A);
+
+ method.StackLoadPrevious(stack, head, 2);
+ method.Call(Word.GetUInt256);
+ method.StoreLocal(uint256B);
+
+ method.StackLoadPrevious(stack, head, 3);
+ method.Call(Word.GetUInt256);
+ method.StoreLocal(uint256C);
+
+ method.StackPop(head, 3);
+
+ method.LoadLocal(gasAvailable);
+ method.LoadLocalAddress(uint256C);
+ method.LoadLocalAddress(lbool);
+ method.Call(typeof(EvmPooledMemory).GetMethod(nameof(EvmPooledMemory.Div32Ceiling), [typeof(UInt256).MakeByRefType(), typeof(bool).MakeByRefType()]));
+ method.LoadConstant(GasCostOf.VeryLow);
+ method.Multiply();
+ method.Subtract();
+ method.Duplicate();
+ method.StoreLocal(gasAvailable);
+ method.LoadConstant((long)0);
+ method.BranchIfLess(evmExceptionLabels[EvmExceptionType.OutOfGas]);
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.EvmState)));
+ method.LoadLocalAddress(gasAvailable);
+ method.LoadLocalAddress(uint256A);
+ method.LoadLocalAddress(uint256B);
+ method.Call(typeof(UInt256).GetMethod(nameof(UInt256.Max)));
+ method.StoreLocal(uint256R);
+ method.LoadLocalAddress(uint256R);
+ method.LoadLocalAddress(uint256C);
+ method.Call(typeof(VirtualMachine).GetMethod(nameof(VirtualMachine.UpdateMemoryCost)));
+ method.BranchIfFalse(evmExceptionLabels[EvmExceptionType.OutOfGas]);
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.Memory)));
+ method.LoadLocalAddress(uint256A);
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.Memory)));
+ method.LoadLocalAddress(uint256B);
+ method.LoadLocalAddress(uint256C);
+ method.Call(typeof(EvmPooledMemory).GetMethod(nameof(EvmPooledMemory.LoadSpan), [typeof(UInt256).MakeByRefType(), typeof(UInt256).MakeByRefType()]));
+ method.Call(typeof(EvmPooledMemory).GetMethod(nameof(EvmPooledMemory.Save), [typeof(UInt256).MakeByRefType(), typeof(Span)]));
+ }
+ break;
+ case Instruction.KECCAK256:
+ {
+ var refWordToRefValueHashMethod = GetAsMethodInfo();
+
+ method.StackLoadPrevious(stack, head, 1);
+ method.Call(Word.GetUInt256);
+ method.StoreLocal(uint256A);
+ method.StackLoadPrevious(stack, head, 2);
+ method.Call(Word.GetUInt256);
+ method.StoreLocal(uint256B);
+
+ method.LoadLocal(gasAvailable);
+ method.LoadLocalAddress(uint256B);
+ method.LoadLocalAddress(lbool);
+ method.Call(typeof(EvmPooledMemory).GetMethod(nameof(EvmPooledMemory.Div32Ceiling), [typeof(UInt256).MakeByRefType(), typeof(bool).MakeByRefType()]));
+ method.LoadConstant(GasCostOf.Sha3Word);
+ method.Multiply();
+ method.Subtract();
+ method.Duplicate();
+ method.StoreLocal(gasAvailable);
+ method.LoadConstant((long)0);
+ method.BranchIfLess(evmExceptionLabels[EvmExceptionType.OutOfGas]);
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.EvmState)));
+ method.LoadLocalAddress(gasAvailable);
+ method.LoadLocalAddress(uint256A);
+ method.LoadLocalAddress(uint256B);
+ method.Call(typeof(VirtualMachine).GetMethod(nameof(VirtualMachine.UpdateMemoryCost)));
+ method.BranchIfFalse(evmExceptionLabels[EvmExceptionType.OutOfGas]);
+
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.Memory)));
+ method.LoadLocalAddress(uint256A);
+ method.LoadLocalAddress(uint256B);
+ method.Call(typeof(EvmPooledMemory).GetMethod(nameof(EvmPooledMemory.LoadSpan), [typeof(UInt256).MakeByRefType(), typeof(UInt256).MakeByRefType()]));
+ method.Call(ConvertionImplicit(typeof(Span), typeof(Span)));
+ method.StackLoadPrevious(stack, head, 2);
+ method.Call(refWordToRefValueHashMethod);
+ method.Call(typeof(KeccakCache).GetMethod(nameof(KeccakCache.ComputeTo), [typeof(ReadOnlySpan), typeof(ValueHash256).MakeByRefType()]));
+ method.StackPop(head);
+ }
+ break;
+ case Instruction.BYTE:
+ {// load a
+ method.StackLoadPrevious(stack, head, 1);
+ method.Duplicate();
+ method.Call(Word.GetUInt0);
+ method.StoreLocal(uint32A);
+ method.Call(Word.GetUInt256);
+ method.StoreLocal(uint256A);
+ method.StackLoadPrevious(stack, head, 2);
+ method.Call(Word.GetSpan);
+ method.StoreLocal(localReadonOnlySpan);
+ method.StackPop(head, 2);
+
+
+ Label pushZeroLabel = method.DefineLabel();
+ Label endOfInstructionImpl = method.DefineLabel();
+ method.LoadLocalAddress(uint256A);
+ method.LoadConstant(Word.Size - 1);
+ method.Call(typeof(UInt256).GetMethod("op_GreaterThan", new[] { typeof(UInt256).MakeByRefType(), typeof(int) }));
+ method.LoadLocalAddress(uint256A);
+ method.LoadConstant(0);
+ method.Call(typeof(UInt256).GetMethod("op_LessThan", new[] { typeof(UInt256).MakeByRefType(), typeof(int) }));
+ method.Or();
+ method.BranchIfTrue(pushZeroLabel);
+
+ method.LoadLocalAddress(localReadonOnlySpan);
+ method.LoadLocal(uint32A);
+ method.Call(typeof(ReadOnlySpan).GetMethod("get_Item"));
+ method.LoadIndirect();
+ method.Convert();
+ method.StoreLocal(uint32A);
+
+ method.CleanAndLoadWord(stack, head);
+ method.LoadLocal(uint32A);
+ method.Call(Word.SetUInt0);
+ method.StackPush(head);
+ method.Branch(endOfInstructionImpl);
+
+ method.MarkLabel(pushZeroLabel);
+ method.CleanWord(stack, head);
+ method.StackPush(head);
+
+ method.MarkLabel(endOfInstructionImpl);
+ }
+ break;
+ case Instruction.CODECOPY:
+ {
+ var endOfOpcode = method.DefineLabel();
+
+ method.StackLoadPrevious(stack, head, 1);
+ method.Call(Word.GetUInt256);
+ method.StoreLocal(uint256A);
+ method.StackLoadPrevious(stack, head, 2);
+ method.Call(Word.GetUInt256);
+ method.StoreLocal(uint256B);
+ method.StackLoadPrevious(stack, head, 3);
+ method.Call(Word.GetUInt256);
+ method.StoreLocal(uint256C);
+ method.StackPop(head, 3);
+
+ method.LoadLocal(gasAvailable);
+ method.LoadLocalAddress(uint256C);
+ method.LoadLocalAddress(lbool);
+ method.Call(typeof(EvmPooledMemory).GetMethod(nameof(EvmPooledMemory.Div32Ceiling), [typeof(UInt256).MakeByRefType(), typeof(bool).MakeByRefType()]));
+ method.LoadConstant(GasCostOf.Memory);
+ method.Multiply();
+ method.Subtract();
+ method.Duplicate();
+ method.StoreLocal(gasAvailable);
+ method.LoadConstant((long)0);
+ method.BranchIfLess(evmExceptionLabels[EvmExceptionType.OutOfGas]);
+
+ method.LoadLocalAddress(uint256C);
+ method.Call(typeof(UInt256).GetProperty(nameof(UInt256.IsZero)).GetMethod!);
+ method.BranchIfTrue(endOfOpcode);
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.EvmState)));
+ method.LoadLocalAddress(gasAvailable);
+ method.LoadLocalAddress(uint256A);
+ method.LoadLocalAddress(uint256C);
+ method.Call(typeof(VirtualMachine).GetMethod(nameof(VirtualMachine.UpdateMemoryCost)));
+ method.BranchIfFalse(evmExceptionLabels[EvmExceptionType.OutOfGas]);
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.MachineCode)));
+ method.StoreLocal(localReadOnlyMemory);
+
+ method.LoadLocal(localReadOnlyMemory);
+ method.LoadLocalAddress(uint256B);
+ method.LoadLocalAddress(uint256C);
+ method.Call(MethodInfo("op_Explicit", typeof(Int32), new[] { typeof(UInt256).MakeByRefType() }));
+ method.LoadConstant((int)PadDirection.Right);
+ method.Call(typeof(ByteArrayExtensions).GetMethod(nameof(ByteArrayExtensions.SliceWithZeroPadding), [typeof(ReadOnlyMemory), typeof(UInt256).MakeByRefType(), typeof(int), typeof(PadDirection)]));
+ method.StoreLocal(localZeroPaddedSpan);
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.Memory)));
+ method.LoadLocalAddress(uint256A);
+ method.LoadLocalAddress(localZeroPaddedSpan);
+ method.Call(typeof(EvmPooledMemory).GetMethod(nameof(EvmPooledMemory.Save), [typeof(UInt256).MakeByRefType(), typeof(ZeroPaddedSpan).MakeByRefType()]));
+
+ method.MarkLabel(endOfOpcode);
+ }
+ break;
+ case Instruction.GAS:
+ {
+ method.CleanAndLoadWord(stack, head);
+ method.LoadLocal(gasAvailable);
+ method.Call(Word.SetULong0);
+
+ method.StackPush(head);
+ }
+ break;
+ case Instruction.RETURNDATASIZE:
+ {
+ method.CleanAndLoadWord(stack, head);
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.ReturnBuffer)));
+ method.Call(GetPropertyInfo>(nameof(ReadOnlyMemory.Length), false, out _));
+ method.Call(Word.SetInt0);
+ method.StackPush(head);
+ }
+ break;
+ case Instruction.RETURNDATACOPY:
+ {
+ var endOfOpcode = method.DefineLabel();
+ using Local tempResult = method.DeclareLocal(typeof(UInt256));
+
+
+ method.StackLoadPrevious(stack, head, 1);
+ method.Call(Word.GetUInt256);
+ method.StoreLocal(uint256A);
+ method.StackLoadPrevious(stack, head, 2);
+ method.Call(Word.GetUInt256);
+ method.StoreLocal(uint256B);
+ method.StackLoadPrevious(stack, head, 3);
+ method.Call(Word.GetUInt256);
+ method.StoreLocal(uint256C);
+ method.StackPop(head, 3);
+
+ method.LoadLocalAddress(uint256B);
+ method.LoadLocalAddress(uint256C);
+ method.LoadLocalAddress(tempResult);
+ method.Call(typeof(UInt256).GetMethod(nameof(UInt256.AddOverflow)));
+ method.LoadLocalAddress(tempResult);
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.ReturnBuffer)));
+ method.Call(typeof(ReadOnlyMemory).GetProperty(nameof(ReadOnlyMemory.Length)).GetMethod!);
+ method.Call(typeof(UInt256).GetMethod("op_GreaterThan", new[] { typeof(UInt256).MakeByRefType(), typeof(int) }));
+ method.Or();
+ method.BranchIfTrue(evmExceptionLabels[EvmExceptionType.AccessViolation]);
+
+
+ method.LoadLocal(gasAvailable);
+ method.LoadLocalAddress(uint256C);
+ method.LoadLocalAddress(lbool);
+ method.Call(typeof(EvmPooledMemory).GetMethod(nameof(EvmPooledMemory.Div32Ceiling), [typeof(UInt256).MakeByRefType(), typeof(bool).MakeByRefType()]));
+ method.LoadConstant(GasCostOf.Memory);
+ method.Multiply();
+ method.Subtract();
+ method.Duplicate();
+ method.StoreLocal(gasAvailable);
+ method.LoadConstant((long)0);
+ method.BranchIfLess(evmExceptionLabels[EvmExceptionType.OutOfGas]);
+
+ // Note : check if c + b > returnData.Size
+
+ method.LoadLocalAddress(uint256C);
+ method.Call(typeof(UInt256).GetProperty(nameof(UInt256.IsZero)).GetMethod!);
+ method.BranchIfTrue(endOfOpcode);
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.EvmState)));
+ method.LoadLocalAddress(gasAvailable);
+ method.LoadLocalAddress(uint256A);
+ method.LoadLocalAddress(uint256C);
+ method.Call(typeof(VirtualMachine).GetMethod(nameof(VirtualMachine.UpdateMemoryCost)));
+ method.BranchIfFalse(evmExceptionLabels[EvmExceptionType.OutOfGas]);
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.ReturnBuffer)));
+ method.LoadObject(typeof(ReadOnlyMemory));
+ method.LoadLocalAddress(uint256B);
+ method.LoadLocalAddress(uint256C);
+ method.Call(MethodInfo("op_Explicit", typeof(Int32), new[] { typeof(UInt256).MakeByRefType() }));
+ method.LoadConstant((int)PadDirection.Right);
+ method.Call(typeof(ByteArrayExtensions).GetMethod(nameof(ByteArrayExtensions.SliceWithZeroPadding), [typeof(ReadOnlyMemory), typeof(UInt256).MakeByRefType(), typeof(int), typeof(PadDirection)]));
+ method.StoreLocal(localZeroPaddedSpan);
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.Memory)));
+ method.LoadLocalAddress(uint256A);
+ method.LoadLocalAddress(localZeroPaddedSpan);
+ method.Call(typeof(EvmPooledMemory).GetMethod(nameof(EvmPooledMemory.Save), [typeof(UInt256).MakeByRefType(), typeof(ZeroPaddedSpan).MakeByRefType()]));
+
+ method.MarkLabel(endOfOpcode);
+ }
+ break;
+ case Instruction.RETURN or Instruction.REVERT:
+ {
+ method.StackLoadPrevious(stack, head, 1);
+ method.Call(Word.GetUInt256);
+ method.StoreLocal(uint256A);
+ method.StackLoadPrevious(stack, head, 2);
+ method.Call(Word.GetUInt256);
+ method.StoreLocal(uint256B);
+ method.StackPop(head, 2);
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.EvmState)));
+ method.LoadLocalAddress(gasAvailable);
+ method.LoadLocalAddress(uint256A);
+ method.LoadLocalAddress(uint256B);
+ method.Call(typeof(VirtualMachine).GetMethod(nameof(VirtualMachine.UpdateMemoryCost)));
+ method.BranchIfFalse(evmExceptionLabels[EvmExceptionType.OutOfGas]);
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.ReturnBuffer)));
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.Memory)));
+ method.LoadLocalAddress(uint256A);
+ method.LoadLocalAddress(uint256B);
+ method.Call(typeof(EvmPooledMemory).GetMethod(nameof(EvmPooledMemory.Load), [typeof(UInt256).MakeByRefType(), typeof(UInt256).MakeByRefType()]));
+ method.StoreObject>();
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadConstant(true);
+ switch (op.Operation)
+ {
+ case Instruction.REVERT:
+ method.StoreField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.ShouldRevert)));
+ break;
+ case Instruction.RETURN:
+ method.StoreField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.ShouldReturn)));
+ break;
+ }
+ method.FakeBranch(ret);
+ }
+ break;
+ case Instruction.BASEFEE:
+ {
+ method.CleanAndLoadWord(stack, head);
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.BlkCtx)));
+ method.Call(GetPropertyInfo(typeof(BlockExecutionContext), nameof(BlockExecutionContext.Header), false, out _));
+ method.Call(GetPropertyInfo(typeof(BlockHeader), nameof(BlockHeader.BaseFeePerGas), false, out _));
+ method.Call(Word.SetUInt256);
+ method.StackPush(head);
+ }
+ break;
+ case Instruction.BLOBBASEFEE:
+ {
+ using Local uint256Nullable = method.DeclareLocal(typeof(UInt256?));
+ method.CleanAndLoadWord(stack, head);
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.BlkCtx)));
+ method.Call(GetPropertyInfo(typeof(BlockExecutionContext), nameof(BlockExecutionContext.BlobBaseFee), false, out _));
+ method.StoreLocal(uint256Nullable);
+ method.LoadLocalAddress(uint256Nullable);
+ method.Call(GetPropertyInfo(typeof(UInt256?), nameof(Nullable.Value), false, out _));
+ method.Call(Word.SetUInt256);
+ method.StackPush(head);
+ }
+ break;
+ case Instruction.PREVRANDAO:
+ {
+ Label isPostMergeBranch = method.DefineLabel();
+ Label endOfOpcode = method.DefineLabel();
+ method.CleanAndLoadWord(stack, head);
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.BlkCtx)));
+ method.Call(GetPropertyInfo(typeof(BlockExecutionContext), nameof(BlockExecutionContext.Header), false, out _));
+ method.Duplicate();
+ method.Call(GetPropertyInfo(typeof(BlockHeader), nameof(BlockHeader.IsPostMerge), false, out _));
+ method.BranchIfFalse(isPostMergeBranch);
+ method.Call(GetPropertyInfo(typeof(BlockHeader), nameof(BlockHeader.Random), false, out _));
+ method.LoadField(typeof(Hash256).GetField("_hash256", BindingFlags.Instance | BindingFlags.NonPublic));
+ method.Call(Word.SetKeccak);
+ method.Branch(endOfOpcode);
+
+ method.MarkLabel(isPostMergeBranch);
+ method.Call(GetPropertyInfo(typeof(BlockHeader), nameof(BlockHeader.Difficulty), false, out _));
+ method.Call(Word.SetUInt256);
+
+ method.MarkLabel(endOfOpcode);
+ method.StackPush(head);
+ }
+ break;
+ case Instruction.BLOBHASH:
+ {
+ Label blobVersionedHashNotFound = method.DefineLabel();
+ Label endOfOpcode = method.DefineLabel();
+
+ method.StackLoadPrevious(stack, head, 1);
+ method.Call(Word.GetInt0);
+ method.StoreLocal(uint32A);
+ method.StackPop(head, 1);
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.TxCtx)));
+ method.Call(GetPropertyInfo(typeof(TxExecutionContext), nameof(TxExecutionContext.BlobVersionedHashes), false, out _));
+ method.LoadNull();
+ method.BranchIfEqual(blobVersionedHashNotFound);
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.TxCtx)));
+ method.Call(GetPropertyInfo(typeof(TxExecutionContext), nameof(TxExecutionContext.BlobVersionedHashes), false, out _));
+ method.Call(GetPropertyInfo(typeof(byte[][]), nameof(Array.Length), false, out _));
+ method.LoadLocal(uint32A);
+ method.BranchIfLessOrEqual(blobVersionedHashNotFound);
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.TxCtx)));
+ method.Call(GetPropertyInfo(typeof(TxExecutionContext), nameof(TxExecutionContext.BlobVersionedHashes), false, out _));
+ method.LoadLocal(uint32A);
+ method.LoadElement();
+ method.StoreLocal(localArray);
+
+ method.CleanAndLoadWord(stack, head);
+ method.LoadLocal(localArray);
+ method.Call(Word.SetArray);
+ method.Branch(endOfOpcode);
+
+ method.MarkLabel(blobVersionedHashNotFound);
+ method.CleanWord(stack, head);
+
+ method.MarkLabel(endOfOpcode);
+ method.StackPush(head);
+ }
+ break;
+ case Instruction.BLOCKHASH:
+ {
+ Label blockHashReturnedNull = method.DefineLabel();
+ Label pushToStackRegion = method.DefineLabel();
+
+ method.StackLoadPrevious(stack, head, 1);
+ method.Call(Word.GetUInt0);
+ method.Convert();
+ method.LoadConstant(long.MaxValue);
+ method.Call(typeof(Math).GetMethod(nameof(Math.Min), [typeof(long), typeof(long)]));
+ method.StoreLocal(int64A);
+ method.StackPop(head, 1);
+
+ method.LoadArgument(BLOCKHASH_PROVIDER_INDEX);
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.BlkCtx)));
+ method.Call(GetPropertyInfo(typeof(BlockExecutionContext), nameof(BlockExecutionContext.Header), false, out _));
+ method.LoadLocalAddress(int64A);
+ method.CallVirtual(typeof(IBlockhashProvider).GetMethod(nameof(IBlockhashProvider.GetBlockhash), [typeof(BlockHeader), typeof(long).MakeByRefType()]));
+ method.Duplicate();
+ method.StoreLocal(hash256);
+ method.LoadNull();
+ method.BranchIfEqual(blockHashReturnedNull);
+
+ // not equal
+ method.LoadLocal(hash256);
+ method.Call(GetPropertyInfo(typeof(Hash256), nameof(Hash256.Bytes), false, out _));
+ method.Call(ConvertionImplicit(typeof(Span), typeof(Span)));
+ method.StoreLocal(localReadonOnlySpan);
+ method.Branch(pushToStackRegion);
+ // equal to null
+
+ method.MarkLabel(blockHashReturnedNull);
+
+ method.LoadField(GetFieldInfo(typeof(VirtualMachine), nameof(VirtualMachine.BytesZero32)));
+ method.Call(ConvertionImplicit(typeof(ReadOnlySpan), typeof(byte[])));
+ method.StoreLocal(localReadonOnlySpan);
+
+ method.MarkLabel(pushToStackRegion);
+ method.CleanAndLoadWord(stack, head);
+ method.LoadLocalAddress(localReadonOnlySpan);
+ method.LoadConstant(BitConverter.IsLittleEndian);
+ method.NewObject(typeof(UInt256), typeof(ReadOnlySpan).MakeByRefType(), typeof(bool));
+ method.Call(Word.SetUInt256);
+ method.StackPush(head);
+ }
+ break;
+ case Instruction.SIGNEXTEND:
+ {
+ Label signIsNegative = method.DefineLabel();
+ Label endOfOpcodeHandling = method.DefineLabel();
+ Label argumentGt32 = method.DefineLabel();
+
+ method.StackLoadPrevious(stack, head, 1);
+ method.Call(Word.GetUInt0);
+ method.StoreLocal(uint32A);
+
+ method.LoadLocal(uint32A);
+ method.LoadConstant(32);
+ method.BranchIfGreaterOrEqual(argumentGt32);
+
+ method.StackLoadPrevious(stack, head, 2);
+ method.Call(Word.GetArray);
+ method.StoreLocal(localArray);
+
+ method.LoadConstant((uint)31);
+ method.LoadLocal(uint32A);
+ method.Subtract();
+ method.StoreLocal(uint32A);
+
+ method.LoadLocal(localArray);
+ method.LoadLocal(uint32A);
+ method.LoadElement();
+ method.Convert();
+ method.LoadConstant((sbyte)0);
+ method.BranchIfLess(signIsNegative);
+
+ method.LoadField(GetFieldInfo(typeof(VirtualMachine), nameof(VirtualMachine.BytesZero32)));
+ method.Branch(endOfOpcodeHandling);
+
+ method.MarkLabel(signIsNegative);
+ method.LoadField(GetFieldInfo(typeof(VirtualMachine), nameof(VirtualMachine.BytesMax32)));
+
+ method.MarkLabel(endOfOpcodeHandling);
+ method.LoadConstant(0);
+ method.LoadLocal(uint32A);
+ method.EmitAsSpan();
+ method.StoreLocal(localSpan);
+
+ using Local tempLocalSpan = method.DeclareLocal(typeof(Span));
+ method.LoadLocal(localArray);
+ method.Duplicate();
+ method.Call(GetPropertyInfo(typeof(byte[]), nameof(Array.Length), false, out _));
+ method.StoreLocal(uint32B);
+ method.LoadConstant(0);
+ method.LoadLocal(uint32B);
+ method.EmitAsSpan();
+ method.StoreLocal(tempLocalSpan);
+
+ method.LoadLocalAddress(localSpan);
+ method.LoadLocal(tempLocalSpan);
+ method.Call(typeof(Span).GetMethod(nameof(Span.CopyTo), [typeof(Span)]));
+ method.MarkLabel(argumentGt32);
+ method.StackPop(head, 1);
+ }
+ break;
+ case Instruction.LOG0:
+ case Instruction.LOG1:
+ case Instruction.LOG2:
+ case Instruction.LOG3:
+ case Instruction.LOG4:
+ {
+ sbyte topicsCount = (sbyte)(op.Operation - Instruction.LOG0);
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.EvmState)));
+ method.Call(GetPropertyInfo(typeof(EvmState), nameof(EvmState.IsStatic), false, out _));
+ method.BranchIfTrue(evmExceptionLabels[EvmExceptionType.StaticCallViolation]);
+
+ EmitLogMethod(method, (stack, head), topicsCount, evmExceptionLabels, uint256A, uint256B, int64A, gasAvailable, hash256, localReadOnlyMemory);
+ }
+ break;
+ case Instruction.TSTORE:
+ {
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.EvmState)));
+ method.Call(GetPropertyInfo(typeof(EvmState), nameof(EvmState.IsStatic), false, out _));
+ method.BranchIfTrue(evmExceptionLabels[EvmExceptionType.StaticCallViolation]);
+
+ method.StackLoadPrevious(stack, head, 1);
+ method.Call(Word.GetUInt256);
+ method.StoreLocal(uint256A);
+
+ method.StackLoadPrevious(stack, head, 2);
+ method.Call(Word.GetArray);
+ method.StoreLocal(localArray);
+
+ method.StackPop(head, 2);
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.Env)));
+ method.LoadField(GetFieldInfo(typeof(ExecutionEnvironment), nameof(ExecutionEnvironment.ExecutingAccount)));
+ method.LoadLocalAddress(uint256A);
+ method.NewObject(typeof(StorageCell), [typeof(Address), typeof(UInt256).MakeByRefType()]);
+ method.StoreLocal(storageCell);
+
+ method.LoadArgument(WORLD_STATE_INDEX);
+ method.LoadLocalAddress(storageCell);
+ method.LoadLocal(localArray);
+ method.CallVirtual(typeof(IWorldState).GetMethod(nameof(IWorldState.SetTransientState), [typeof(StorageCell).MakeByRefType(), typeof(byte[])]));
+ }
+ break;
+ case Instruction.TLOAD:
+ {
+ method.StackLoadPrevious(stack, head, 1);
+ method.Call(Word.GetUInt256);
+ method.StoreLocal(uint256A);
+ method.StackPop(head, 1);
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.Env)));
+ method.LoadField(GetFieldInfo(typeof(ExecutionEnvironment), nameof(ExecutionEnvironment.ExecutingAccount)));
+ method.LoadLocalAddress(uint256A);
+ method.NewObject(typeof(StorageCell), [typeof(Address), typeof(UInt256).MakeByRefType()]);
+ method.StoreLocal(storageCell);
+
+ method.LoadArgument(WORLD_STATE_INDEX);
+ method.LoadLocalAddress(storageCell);
+ method.CallVirtual(typeof(IWorldState).GetMethod(nameof(IWorldState.GetTransientState), [typeof(StorageCell).MakeByRefType()]));
+ method.StoreLocal(localReadonOnlySpan);
+
+ method.CleanAndLoadWord(stack, head);
+ method.LoadLocal(localReadonOnlySpan);
+ method.Call(Word.SetSpan);
+ method.StackPush(head);
+ }
+ break;
+ case Instruction.SSTORE:
+ {
+ method.StackLoadPrevious(stack, head, 1);
+ method.Call(Word.GetUInt256);
+ method.StoreLocal(uint256A);
+ method.StackLoadPrevious(stack, head, 2);
+ method.Call(Word.GetSpan);
+ method.StoreLocal(localReadonOnlySpan);
+ method.StackPop(head, 2);
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.EvmState)));
+ method.LoadArgument(WORLD_STATE_INDEX);
+ method.LoadLocalAddress(gasAvailable);
+ method.LoadLocalAddress(uint256A);
+ method.LoadLocalAddress(localReadonOnlySpan);
+ method.LoadArgument(SPEC_INDEX);
+ method.Call(GetPropertyInfo(nameof(NullTxTracer.Instance), false, out _));
+
+ MethodInfo sstoreMethod =
+ typeof(VirtualMachine)
+ .GetMethod(nameof(VirtualMachine.InstructionSStore), BindingFlags.Static | BindingFlags.NonPublic)
+ .MakeGenericMethod(typeof(VirtualMachine.NotTracing), typeof(VirtualMachine.NotTracing), typeof(VirtualMachine.NotTracing));
+ method.Call(sstoreMethod);
+
+ Label endOfOpcode = method.DefineLabel();
+ method.Duplicate();
+ method.StoreLocal(uint32A);
+ method.LoadConstant((int)EvmExceptionType.None);
+ method.BranchIfEqual(endOfOpcode);
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadLocal(uint32A);
+ method.StoreField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.EvmException)));
+ method.Branch(exit);
+
+ method.MarkLabel(endOfOpcode);
+ }
+ break;
+ case Instruction.SLOAD:
+ {
+ method.LoadLocal(gasAvailable);
+ method.LoadArgument(SPEC_INDEX);
+ method.Call(typeof(ReleaseSpecExtensions).GetMethod(nameof(ReleaseSpecExtensions.GetSLoadCost)));
+ method.Subtract();
+ method.Duplicate();
+ method.StoreLocal(gasAvailable);
+ method.LoadConstant((long)0);
+ method.BranchIfLess(evmExceptionLabels[EvmExceptionType.OutOfGas]);
+
+ method.StackLoadPrevious(stack, head, 1);
+ method.Call(Word.GetUInt256);
+ method.StoreLocal(uint256A);
+ method.StackPop(head, 1);
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.Env)));
+ method.LoadField(GetFieldInfo(typeof(ExecutionEnvironment), nameof(ExecutionEnvironment.ExecutingAccount)));
+ method.LoadLocalAddress(uint256A);
+ method.NewObject(typeof(StorageCell), [typeof(Address), typeof(UInt256).MakeByRefType()]);
+ method.StoreLocal(storageCell);
+
+ method.LoadLocalAddress(gasAvailable);
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.EvmState)));
+ method.LoadLocalAddress(storageCell);
+ method.LoadConstant((int)VirtualMachine.StorageAccessType.SLOAD);
+ method.LoadArgument(SPEC_INDEX);
+ method.Call(GetPropertyInfo(nameof(NullTxTracer.Instance), false, out _));
+ method.Call(typeof(VirtualMachine).GetMethod(nameof(VirtualMachine.ChargeStorageAccessGas), BindingFlags.Static | BindingFlags.NonPublic));
+ method.BranchIfFalse(evmExceptionLabels[EvmExceptionType.OutOfGas]);
+
+ method.LoadArgument(WORLD_STATE_INDEX);
+ method.LoadLocalAddress(storageCell);
+ method.CallVirtual(typeof(IWorldState).GetMethod(nameof(IWorldState.Get), [typeof(StorageCell).MakeByRefType()]));
+ method.StoreLocal(localReadonOnlySpan);
+
+ method.CleanAndLoadWord(stack, head);
+ method.LoadLocal(localReadonOnlySpan);
+ method.Call(Word.SetSpan);
+ method.StackPush(head);
+ }
+ break;
+ case Instruction.EXTCODESIZE:
+ {
+ method.LoadLocal(gasAvailable);
+ method.LoadArgument(SPEC_INDEX);
+ method.Call(typeof(ReleaseSpecExtensions).GetMethod(nameof(ReleaseSpecExtensions.GetExtCodeCost)));
+ method.Subtract();
+ method.Duplicate();
+ method.StoreLocal(gasAvailable);
+ method.LoadConstant((long)0);
+ method.BranchIfLess(evmExceptionLabels[EvmExceptionType.OutOfGas]);
+
+ method.StackLoadPrevious(stack, head, 1);
+ method.Call(Word.GetAddress);
+ method.StoreLocal(address);
+ method.StackPop(head, 1);
+
+ method.LoadLocalAddress(gasAvailable);
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.EvmState)));
+ method.LoadLocal(address);
+ method.LoadConstant(true);
+ method.LoadArgument(WORLD_STATE_INDEX);
+ method.LoadArgument(SPEC_INDEX);
+ method.Call(GetPropertyInfo(nameof(NullTxTracer.Instance), false, out _));
+ method.LoadConstant(true);
+ method.Call(typeof(VirtualMachine).GetMethod(nameof(VirtualMachine.ChargeAccountAccessGas)));
+ method.BranchIfFalse(evmExceptionLabels[EvmExceptionType.OutOfGas]);
+
+ method.CleanAndLoadWord(stack, head);
+
+ method.LoadArgument(CODE_INFO_REPOSITORY_INDEX);
+ method.LoadArgument(WORLD_STATE_INDEX);
+ method.LoadLocal(address);
+ method.LoadArgument(SPEC_INDEX);
+ method.Call(typeof(CodeInfoRepositoryExtensions).GetMethod(nameof(CodeInfoRepositoryExtensions.GetCachedCodeInfo), [typeof(ICodeInfoRepository), typeof(IWorldState), typeof(Address), typeof(IReleaseSpec)]));
+ method.Call(GetPropertyInfo(nameof(CodeInfo.MachineCode), false, out _));
+ method.StoreLocal(localReadOnlyMemory);
+ method.LoadLocalAddress(localReadOnlyMemory);
+ method.Call(GetPropertyInfo>(nameof(ReadOnlyMemory.Length), false, out _));
+
+ method.Call(Word.SetInt0);
+ method.StackPush(head);
+ }
+ break;
+ case Instruction.EXTCODECOPY:
+ {
+ Label endOfOpcode = method.DefineLabel();
+
+ method.StackLoadPrevious(stack, head, 4);
+ method.Call(Word.GetUInt256);
+ method.StoreLocal(uint256C);
+
+ method.LoadLocal(gasAvailable);
+ method.LoadArgument(SPEC_INDEX);
+ method.Call(typeof(ReleaseSpecExtensions).GetMethod(nameof(ReleaseSpecExtensions.GetExtCodeCost)));
+ method.LoadLocalAddress(uint256C);
+ method.LoadLocalAddress(lbool);
+ method.Call(typeof(EvmPooledMemory).GetMethod(nameof(EvmPooledMemory.Div32Ceiling), [typeof(UInt256).MakeByRefType(), typeof(bool).MakeByRefType()]));
+ method.LoadConstant(GasCostOf.Memory);
+ method.Multiply();
+ method.Add();
+ method.Subtract();
+ method.Duplicate();
+ method.StoreLocal(gasAvailable);
+ method.LoadConstant((long)0);
+ method.BranchIfLess(evmExceptionLabels[EvmExceptionType.OutOfGas]);
+
+ method.StackLoadPrevious(stack, head, 1);
+ method.Call(Word.GetAddress);
+ method.StoreLocal(address);
+ method.StackLoadPrevious(stack, head, 2);
+ method.Call(Word.GetUInt256);
+ method.StoreLocal(uint256A);
+ method.StackLoadPrevious(stack, head, 3);
+ method.Call(Word.GetUInt256);
+ method.StoreLocal(uint256B);
+ method.StackPop(head, 4);
+
+ method.LoadLocalAddress(gasAvailable);
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.EvmState)));
+ method.LoadLocal(address);
+ method.LoadConstant(true);
+ method.LoadArgument(WORLD_STATE_INDEX);
+ method.LoadArgument(SPEC_INDEX);
+ method.Call(GetPropertyInfo(nameof(NullTxTracer.Instance), false, out _));
+ method.LoadConstant(true);
+ method.Call(typeof(VirtualMachine).GetMethod(nameof(VirtualMachine.ChargeAccountAccessGas)));
+ method.BranchIfFalse(evmExceptionLabels[EvmExceptionType.OutOfGas]);
+
+ method.LoadLocalAddress(uint256C);
+ method.Call(typeof(UInt256).GetProperty(nameof(UInt256.IsZero)).GetMethod!);
+ method.BranchIfTrue(endOfOpcode);
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.EvmState)));
+ method.LoadLocalAddress(gasAvailable);
+ method.LoadLocalAddress(uint256A);
+ method.LoadLocalAddress(uint256C);
+ method.Call(typeof(VirtualMachine).GetMethod(nameof(VirtualMachine.UpdateMemoryCost)));
+ method.BranchIfFalse(evmExceptionLabels[EvmExceptionType.OutOfGas]);
+
+ method.LoadArgument(CODE_INFO_REPOSITORY_INDEX);
+ method.LoadArgument(WORLD_STATE_INDEX);
+ method.LoadLocal(address);
+ method.LoadArgument(SPEC_INDEX);
+ method.Call(typeof(CodeInfoRepositoryExtensions).GetMethod(nameof(CodeInfoRepositoryExtensions.GetCachedCodeInfo), [typeof(ICodeInfoRepository), typeof(IWorldState), typeof(Address), typeof(IReleaseSpec)]));
+ method.Call(GetPropertyInfo(nameof(CodeInfo.MachineCode), false, out _));
+
+ method.LoadLocalAddress(uint256B);
+ method.LoadLocal(uint256C);
+ method.LoadField(GetFieldInfo(typeof(UInt256), nameof(UInt256.u0)));
+ method.Convert();
+ method.LoadConstant((int)PadDirection.Right);
+ method.Call(typeof(ByteArrayExtensions).GetMethod(nameof(ByteArrayExtensions.SliceWithZeroPadding), [typeof(ReadOnlyMemory), typeof(UInt256).MakeByRefType(), typeof(int), typeof(PadDirection)]));
+ method.StoreLocal(localZeroPaddedSpan);
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.Memory)));
+ method.LoadLocalAddress(uint256A);
+ method.LoadLocalAddress(localZeroPaddedSpan);
+ method.Call(typeof(EvmPooledMemory).GetMethod(nameof(EvmPooledMemory.Save), [typeof(UInt256).MakeByRefType(), typeof(ZeroPaddedSpan).MakeByRefType()]));
+
+ method.MarkLabel(endOfOpcode);
+ }
+ break;
+ case Instruction.EXTCODEHASH:
+ {
+ Label endOfOpcode = method.DefineLabel();
+
+ method.LoadLocal(gasAvailable);
+ method.LoadArgument(SPEC_INDEX);
+ method.Call(typeof(ReleaseSpecExtensions).GetMethod(nameof(ReleaseSpecExtensions.GetExtCodeHashCost)));
+ method.Subtract();
+ method.Duplicate();
+ method.StoreLocal(gasAvailable);
+ method.LoadConstant((long)0);
+ method.BranchIfLess(evmExceptionLabels[EvmExceptionType.OutOfGas]);
+
+ method.StackLoadPrevious(stack, head, 1);
+ method.Call(Word.GetAddress);
+ method.StoreLocal(address);
+ method.StackPop(head, 1);
+
+ method.LoadLocalAddress(gasAvailable);
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.EvmState)));
+ method.LoadLocal(address);
+ method.LoadConstant(true);
+ method.LoadArgument(WORLD_STATE_INDEX);
+ method.LoadArgument(SPEC_INDEX);
+ method.Call(GetPropertyInfo(nameof(NullTxTracer.Instance), false, out _));
+ method.LoadConstant(true);
+ method.Call(typeof(VirtualMachine).GetMethod(nameof(VirtualMachine.ChargeAccountAccessGas)));
+ method.BranchIfFalse(evmExceptionLabels[EvmExceptionType.OutOfGas]);
+
+ method.LoadArgument(WORLD_STATE_INDEX);
+ method.LoadLocal(address);
+ method.CallVirtual(typeof(IReadOnlyStateProvider).GetMethod(nameof(IWorldState.AccountExists)));
+ method.LoadConstant(false);
+ method.CompareEqual();
+ method.LoadArgument(WORLD_STATE_INDEX);
+ method.LoadLocal(address);
+ method.CallVirtual(typeof(IReadOnlyStateProvider).GetMethod(nameof(IWorldState.IsDeadAccount)));
+ method.Or();
+ method.BranchIfTrue(endOfOpcode);
+
+ method.CleanAndLoadWord(stack, head);
+ method.LoadArgument(WORLD_STATE_INDEX);
+ method.LoadLocal(address);
+ method.CallVirtual(typeof(IAccountStateProvider).GetMethod(nameof(IWorldState.GetCodeHash)));
+ method.Call(Word.SetKeccak);
+ method.MarkLabel(endOfOpcode);
+ method.StackPush(head);
+ }
+ break;
+ case Instruction.SELFBALANCE:
+ {
+ method.CleanAndLoadWord(stack, head);
+ method.LoadArgument(WORLD_STATE_INDEX);
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.Env)));
+ method.LoadField(GetFieldInfo(typeof(ExecutionEnvironment), nameof(ExecutionEnvironment.ExecutingAccount)));
+ method.CallVirtual(typeof(IAccountStateProvider).GetMethod(nameof(IWorldState.GetBalance)));
+ method.Call(Word.SetUInt256);
+ method.StackPush(head);
+ }
+ break;
+ case Instruction.BALANCE:
+ {
+ method.LoadLocal(gasAvailable);
+ method.LoadArgument(SPEC_INDEX);
+ method.Call(typeof(ReleaseSpecExtensions).GetMethod(nameof(ReleaseSpecExtensions.GetBalanceCost)));
+ method.Subtract();
+ method.Duplicate();
+ method.StoreLocal(gasAvailable);
+ method.LoadConstant((long)0);
+ method.BranchIfLess(evmExceptionLabels[EvmExceptionType.OutOfGas]);
+
+ method.StackLoadPrevious(stack, head, 1);
+ method.Call(Word.GetAddress);
+ method.StoreLocal(address);
+ method.StackPop(head, 1);
+
+ method.LoadLocalAddress(gasAvailable);
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.EvmState)));
+ method.LoadLocal(address);
+ method.LoadConstant(false);
+ method.LoadArgument(WORLD_STATE_INDEX);
+ method.LoadArgument(SPEC_INDEX);
+ method.Call(GetPropertyInfo(nameof(NullTxTracer.Instance), false, out _));
+ method.LoadConstant(true);
+ method.Call(typeof(VirtualMachine).GetMethod(nameof(VirtualMachine.ChargeAccountAccessGas)));
+ method.BranchIfFalse(evmExceptionLabels[EvmExceptionType.OutOfGas]);
+
+ method.CleanAndLoadWord(stack, head);
+ method.LoadArgument(WORLD_STATE_INDEX);
+ method.LoadLocal(address);
+ method.CallVirtual(typeof(IAccountStateProvider).GetMethod(nameof(IWorldState.GetBalance)));
+ method.Call(Word.SetUInt256);
+ method.StackPush(head);
+ }
+ break;
+ default:
+ {
+ method.FakeBranch(evmExceptionLabels[EvmExceptionType.BadInstruction]);
+ }
+ break;
+ }
+
+ if (bakeInTracerCalls)
+ {
+ EmitCallToEndInstructionTrace(method, gasAvailable);
+ }
+ }
+
+ Label skipProgramCounterSetting = method.DefineLabel();
+ Local isEphemeralJump = method.DeclareLocal();
+ // prepare ILEvmState
+ // check if returnState is null
+ method.MarkLabel(ret);
+ // we get stack size
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadLocal(head);
+ method.StoreField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.StackHead)));
+
+ // set stack
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadLocal(stack);
+ method.Call(GetCastMethodInfo());
+ method.StoreField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.Stack)));
+
+ // set gas available
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadLocal(gasAvailable);
+ method.StoreField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.GasAvailable)));
+
+ // set program counter
+ method.LoadLocal(isEphemeralJump);
+ method.BranchIfTrue(skipProgramCounterSetting);
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadLocal(programCounter);
+ method.LoadConstant(1);
+ method.Add();
+ method.StoreField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.ProgramCounter)));
+
+ method.MarkLabel(skipProgramCounterSetting);
+
+
+ // set exception
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadConstant((int)EvmExceptionType.None);
+ method.StoreField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.EvmException)));
+
+ // go to return
+ method.Branch(exit);
+
+ Label jumpIsLocal = method.DefineLabel();
+ Label jumpIsNotLocal = method.DefineLabel();
+
+ // isContinuation
+ method.MarkLabel(isContinuation);
+ method.LoadLocal(programCounter);
+ method.StoreLocal(jmpDestination);
+ method.Branch(jumpIsLocal);
+
+ // jump table
+ method.MarkLabel(jumpTable);
+ method.StackLoadPrevious(stack, head, 1);
+ method.Call(Word.GetInt0);
+ method.StoreLocal(jmpDestination);
+ method.StackPop(head);
+
+ method.StackPop(head, consumeJumpCondition);
+ method.LoadConstant(0);
+ method.StoreLocal(consumeJumpCondition);
+
+ //check if jump crosses segment boundaies
+ int maxJump = code[^1].ProgramCounter + code[^1].Metadata.AdditionalBytes;
+ int minJump = code[0].ProgramCounter;
+
+ // if (jumpDest <= maxJump)
+ method.LoadLocal(jmpDestination);
+ method.LoadConstant(maxJump);
+ method.BranchIfGreater(jumpIsNotLocal);
+
+ // if (jumpDest >= minJump)
+ method.LoadLocal(jmpDestination);
+ method.LoadConstant(minJump);
+ method.BranchIfLess(jumpIsNotLocal);
+
+ method.Branch(jumpIsLocal);
+
+ method.MarkLabel(jumpIsNotLocal);
+ method.LoadArgument(VMSTATE_INDEX);
+ method.Duplicate();
+ method.LoadConstant(true);
+ method.StoreLocal(isEphemeralJump);
+ method.LoadConstant(true);
+ method.StoreField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.ShouldJump)));
+ method.LoadLocal(jmpDestination);
+ method.Convert();
+ method.StoreField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.ProgramCounter)));
+ method.Branch(ret);
+
+ method.MarkLabel(jumpIsLocal);
+
+
+ // if (jumpDest > uint.MaxValue)
+ method.LoadConstant(uint.MaxValue);
+ method.LoadLocal(jmpDestination);
+ // goto invalid address
+ method.BranchIfGreater(evmExceptionLabels[EvmExceptionType.InvalidJumpDestination]);
+ // else
+
+ const int length = 1 << 8;
+ const int bitMask = length - 1; // 128
+ Label[] jumps = new Label[length];
+ for (int i = 0; i < length; i++)
+ {
+ jumps[i] = method.DefineLabel();
+ }
+
+ // we get first Word.Size bits of the jump destination since it is less than int.MaxValue
+
+ method.LoadLocal(jmpDestination);
+ method.LoadConstant(bitMask);
+ method.And();
+
+
+ // switch on the first 7 bits
+ method.Switch(jumps);
+
+ for (int i = 0; i < length; i++)
+ {
+ method.MarkLabel(jumps[i]);
+ // for each destination matching the bit mask emit check for the equality
+ foreach (ushort dest in jumpDestinations.Keys.Where(dest => (dest & bitMask) == i))
+ {
+ method.LoadLocal(jmpDestination);
+ method.LoadConstant(dest);
+ method.Duplicate();
+ method.StoreLocal(uint32A);
+ method.BranchIfEqual(jumpDestinations[dest]);
+ }
+ // each bucket ends with a jump to invalid access to do not fall through to another one
+ method.Branch(evmExceptionLabels[EvmExceptionType.InvalidJumpDestination]);
+ }
+
+ foreach (var kvp in evmExceptionLabels)
+ {
+ method.MarkLabel(kvp.Value);
+ if(bakeInTracerCalls)
+ {
+ EmitCallToErrorTrace(method, gasAvailable, kvp);
+ }
+
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadConstant((int)kvp.Key);
+ method.StoreField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.EvmException)));
+ method.Branch(exit);
+ }
+
+ // return
+ method.MarkLabel(exit);
+ method.Return();
+
+ return jumpDestinations.Keys.ToArray();
+ }
+
+ private static void EmitCallToErrorTrace(Emit method, Local gasAvailable, KeyValuePair kvp)
+ {
+ Label skipTracing = method.DefineLabel();
+ method.LoadArgument(TXTRACER_INDEX);
+ method.CallVirtual(typeof(ITxTracer).GetProperty(nameof(ITxTracer.IsTracingInstructions)).GetGetMethod());
+ method.BranchIfFalse(skipTracing);
+
+ method.LoadArgument(TXTRACER_INDEX);
+ method.LoadLocal(gasAvailable);
+ method.LoadConstant((int)kvp.Key);
+ method.Call(typeof(VirtualMachine).GetMethod(nameof(VirtualMachine.EndInstructionTraceError), BindingFlags.Static | BindingFlags.NonPublic));
+
+ method.MarkLabel(skipTracing);
+ }
+
+ private static void EmitCallToEndInstructionTrace(Emit method, Local gasAvailable)
+ {
+ Label skipTracing = method.DefineLabel();
+ method.LoadArgument(TXTRACER_INDEX);
+ method.CallVirtual(typeof(ITxTracer).GetProperty(nameof(ITxTracer.IsTracingInstructions)).GetGetMethod());
+ method.BranchIfFalse(skipTracing);
+
+ method.LoadArgument(TXTRACER_INDEX);
+ method.LoadLocal(gasAvailable);
+ method.LoadArgument(VMSTATE_INDEX);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.Memory)));
+ method.Call(GetPropertyInfo(nameof(EvmPooledMemory.Size), false, out _));
+ method.Call(typeof(VirtualMachine).GetMethod(nameof(VirtualMachine.EndInstructionTrace), BindingFlags.Static | BindingFlags.NonPublic));
+
+ method.MarkLabel(skipTracing);
+ }
+
+
+ private static void EmitCallToStartInstructionTrace(Emit method, Local gasAvailable, Local head, OpcodeInfo op)
+ {
+ Label skipTracing = method.DefineLabel();
+ method.LoadArgument(TXTRACER_INDEX);
+ method.CallVirtual(typeof(ITxTracer).GetProperty(nameof(ITxTracer.IsTracingInstructions)).GetGetMethod());
+ method.BranchIfFalse(skipTracing);
+
+ method.LoadArgument(TXTRACER_INDEX);
+ method.LoadConstant((int)op.Operation);
+ method.LoadArgument(0);
+ method.LoadField(GetFieldInfo(typeof(ILEvmState), nameof(ILEvmState.EvmState)));
+ method.LoadLocal(gasAvailable);
+ method.LoadConstant(op.ProgramCounter);
+ method.LoadLocal(head);
+ method.Call(typeof(VirtualMachine).GetMethod(nameof(VirtualMachine.StartInstructionTrace), BindingFlags.Static | BindingFlags.NonPublic));
+
+ method.MarkLabel(skipTracing);
+ }
+
+ private static void EmitShiftUInt256Method(Emit il, Local uint256R, (Local span, Local idx) stack, bool isLeft, Dictionary exceptions, params Local[] locals)
+ {
+ MethodInfo shiftOp = typeof(UInt256).GetMethod(isLeft ? nameof(UInt256.LeftShift) : nameof(UInt256.RightShift));
+ Label skipPop = il.DefineLabel();
+ Label endOfOpcode = il.DefineLabel();
+
+ // Note: Use Vector256 directoly if UInt256 does not use it internally
+ // we the two uint256 from the stack
+ Local shiftBit = il.DeclareLocal();
+
+ il.StackLoadPrevious(stack.span, stack.idx, 1);
+ il.Call(Word.GetUInt256);
+ il.Duplicate();
+ il.LoadField(GetFieldInfo(typeof(UInt256), nameof(UInt256.u0)));
+ il.Convert();
+ il.StoreLocal(shiftBit);
+ il.StoreLocal(locals[0]);
+
+ il.LoadLocalAddress(locals[0]);
+ il.LoadConstant(Word.FullSize);
+ il.Call(typeof(UInt256).GetMethod("op_LessThan", new[] { typeof(UInt256).MakeByRefType(), typeof(int) }));
+ il.BranchIfFalse(skipPop);
+
+ il.StackLoadPrevious(stack.span, stack.idx, 2);
+ il.Call(Word.GetUInt256);
+ il.StoreLocal(locals[1]);
+ il.LoadLocalAddress(locals[1]);
+
+ il.LoadLocal(shiftBit);
+
+ il.LoadLocalAddress(uint256R);
+
+ il.Call(shiftOp);
+
+ il.StackPop(stack.idx, 2);
+ il.CleanAndLoadWord(stack.span, stack.idx);
+ il.LoadLocal(uint256R);
+ il.Call(Word.SetUInt256);
+ il.StackPush(stack.idx, 1);
+ il.Branch(endOfOpcode);
+
+ il.MarkLabel(skipPop);
+
+ il.StackPop(stack.idx, 2);
+ il.CleanWord(stack.span, stack.idx);
+ il.StackPush(stack.idx, 1);
+
+ il.MarkLabel(endOfOpcode);
+ }
+
+ private static void EmitShiftInt256Method(Emit il, Local uint256R, (Local span, Local idx) stack, Dictionary exceptions, params Local[] locals)
+ {
+ Label aBiggerOrEqThan256 = il.DefineLabel();
+ Label signIsNeg = il.DefineLabel();
+ Label endOfOpcode = il.DefineLabel();
+
+ // Note: Use Vector256 directoly if UInt256 does not use it internally
+ // we the two uint256 from the stack
+ il.StackLoadPrevious(stack.span, stack.idx, 1);
+ il.Call(Word.GetUInt256);
+ il.StoreLocal(locals[0]);
+
+ il.StackLoadPrevious(stack.span, stack.idx, 2);
+ il.Call(Word.GetUInt256);
+ il.StoreLocal(locals[1]);
+ il.StackPop(stack.idx, 2);
+
+ il.LoadLocalAddress(locals[0]);
+ il.LoadConstant(Word.FullSize);
+ il.Call(typeof(UInt256).GetMethod("op_LessThan", new[] { typeof(UInt256).MakeByRefType(), typeof(int) }));
+ il.BranchIfFalse(aBiggerOrEqThan256);
+
+ using Local shiftBits = il.DeclareLocal();
+
+
+ il.LoadLocalAddress(locals[1]);
+ il.Call(GetAsMethodInfo());
+ il.LoadLocalAddress(locals[0]);
+ il.LoadField(GetFieldInfo(nameof(UInt256.u0)));
+ il.Convert();
+ il.LoadLocalAddress(uint256R);
+ il.Call(GetAsMethodInfo());
+ il.Call(typeof(Int256.Int256).GetMethod(nameof(Int256.Int256.RightShift), [typeof(int), typeof(Int256.Int256).MakeByRefType()]));
+ il.CleanAndLoadWord(stack.span, stack.idx);
+ il.LoadLocal(uint256R);
+ il.Call(Word.SetUInt256);
+ il.Branch(endOfOpcode);
+
+ il.MarkLabel(aBiggerOrEqThan256);
+
+ il.LoadLocalAddress(locals[1]);
+ il.Call(GetAsMethodInfo());
+ il.Call(GetPropertyInfo(typeof(Int256.Int256), nameof(Int256.Int256.Sign), false, out _));
+ il.LoadConstant(0);
+ il.BranchIfLess(signIsNeg);
+
+ il.CleanWord(stack.span, stack.idx);
+ il.Branch(endOfOpcode);
+
+ // sign
+ il.MarkLabel(signIsNeg);
+ il.CleanAndLoadWord(stack.span, stack.idx);
+ il.LoadFieldAddress(GetFieldInfo(typeof(Int256.Int256), nameof(Int256.Int256.MinusOne)));
+ il.Call(GetAsMethodInfo());
+ il.LoadObject();
+ il.Call(Word.SetUInt256);
+ il.Branch(endOfOpcode);
+
+ il.MarkLabel(endOfOpcode);
+ il.StackPush(stack.idx);
+ }
+
+ private static void EmitBitwiseUInt256Method(Emit il, Local uint256R, (Local span, Local idx) stack, MethodInfo operation, Dictionary exceptions, params Local[] locals)
+ {
+ // Note: Use Vector256 directoly if UInt256 does not use it internally
+ // we the two uint256 from the stack
+ var refWordToRefByteMethod = GetAsMethodInfo();
+ var readVector256Method = GetReadUnalignedMethodInfo>();
+ var writeVector256Method = GetWriteUnalignedMethodInfo>();
+ var operationUnegenerified = operation.MakeGenericMethod(typeof(byte));
+
+ using Local vectorResult = il.DeclareLocal>();
+
+ il.StackLoadPrevious(stack.span, stack.idx, 1);
+ il.Call(refWordToRefByteMethod);
+ il.Call(readVector256Method);
+ il.StackLoadPrevious(stack.span, stack.idx, 2);
+ il.Call(refWordToRefByteMethod);
+ il.Call(readVector256Method);
+
+ il.Call(operationUnegenerified);
+ il.StoreLocal(vectorResult);
+
+ il.StackLoadPrevious(stack.span, stack.idx, 2);
+ il.Call(refWordToRefByteMethod);
+ il.LoadLocal(vectorResult);
+ il.Call(writeVector256Method);
+ il.StackPop(stack.idx);
+ }
+
+ private static void EmitComparaisonUInt256Method(Emit il, Local uint256R, (Local span, Local idx) stack, MethodInfo operation, Dictionary exceptions, params Local[] locals)
+ {
+ // we the two uint256 from the stack
+ il.StackLoadPrevious(stack.span, stack.idx, 1);
+ il.Call(Word.GetUInt256);
+ il.StoreLocal(locals[0]);
+ il.StackLoadPrevious(stack.span, stack.idx, 2);
+ il.Call(Word.GetUInt256);
+ il.StoreLocal(locals[1]);
+ il.StackPop(stack.idx, 2);
+
+ // invoke op on the uint256
+ il.LoadLocalAddress(locals[0]);
+ il.LoadLocalAddress(locals[1]);
+ il.Call(operation);
+
+ // convert to conv_i
+ il.Convert();
+ il.Call(ConvertionExplicit());
+ il.StoreLocal(uint256R);
+
+ // push the result to the stack
+ il.CleanAndLoadWord(stack.span, stack.idx);
+ il.LoadLocal(uint256R); // stack: word*, uint256
+ il.Call(Word.SetUInt256);
+ il.StackPush(stack.idx);
+ }
+
+ private static void EmitComparaisonInt256Method(Emit il, Local uint256R, (Local span, Local idx) stack, MethodInfo operation, bool isGreaterThan, Dictionary exceptions, params Local[] locals)
+ {
+ Label endOpcodeHandling = il.DefineLabel();
+ Label pushOnehandling = il.DefineLabel();
+ // we the two uint256 from the stack
+ il.StackLoadPrevious(stack.span, stack.idx, 1);
+ il.Call(Word.GetUInt256);
+ il.StoreLocal(locals[0]);
+ il.StackLoadPrevious(stack.span, stack.idx, 2);
+ il.Call(Word.GetUInt256);
+ il.StoreLocal(locals[1]);
+ il.StackPop(stack.idx, 2);
+
+ // invoke op on the uint256
+ il.LoadLocalAddress(locals[0]);
+ il.Call(GetAsMethodInfo());
+ il.LoadLocalAddress(locals[1]);
+ il.Call(GetAsMethodInfo());
+ il.LoadObject();
+ il.Call(operation);
+ il.LoadConstant(0);
+ if (isGreaterThan)
+ {
+ il.BranchIfGreater(pushOnehandling);
+ }
+ else
+ {
+ il.BranchIfLess(pushOnehandling);
+ }
+
+ il.CleanAndLoadWord(stack.span, stack.idx);
+ il.LoadField(GetFieldInfo(typeof(UInt256), nameof(UInt256.Zero)));
+ il.Branch(endOpcodeHandling);
+
+ il.MarkLabel(pushOnehandling);
+ il.CleanAndLoadWord(stack.span, stack.idx);
+ il.LoadField(GetFieldInfo(typeof(UInt256), nameof(UInt256.One)));
+ il.Branch(endOpcodeHandling);
+
+ // push the result to the stack
+ il.MarkLabel(endOpcodeHandling);
+ il.Call(Word.SetUInt256);
+ il.StackPush(stack.idx);
+ }
+
+ private static void EmitBinaryUInt256Method(Emit il, Local uint256R, (Local span, Local idx) stack, MethodInfo operation, Action, Label, Local[]> customHandling, Dictionary exceptions, params Local[] locals)
+ {
+ Label label = il.DefineLabel();
+
+ // we the two uint256 from the stack
+ il.StackLoadPrevious(stack.span, stack.idx, 1);
+ il.Call(Word.GetUInt256);
+ il.StoreLocal(locals[0]);
+ il.StackLoadPrevious(stack.span, stack.idx, 2);
+ il.Call(Word.GetUInt256);
+ il.StoreLocal(locals[1]);
+ il.StackPop(stack.idx, 2);
+
+ // incase of custom handling, we branch to the label
+ customHandling?.Invoke(il, label, locals);
+
+ // invoke op on the uint256
+ il.LoadLocalAddress(locals[0]);
+ il.LoadLocalAddress(locals[1]);
+ il.LoadLocalAddress(uint256R);
+ il.Call(operation);
+
+ // skip the main handling
+ il.MarkLabel(label);
+
+ // push the result to the stack
+ il.CleanAndLoadWord(stack.span, stack.idx);
+ il.LoadLocal(uint256R); // stack: word*, uint256
+ il.Call(Word.SetUInt256);
+ il.StackPush(stack.idx);
+ }
+
+ private static void EmitBinaryInt256Method(Emit il, Local uint256R, (Local span, Local idx) stack, MethodInfo operation, Action, Label, Local[]> customHandling, Dictionary exceptions, params Local[] locals)
+ {
+ Label label = il.DefineLabel();
+
+ // we the two uint256 from the stack
+ il.StackLoadPrevious(stack.span, stack.idx, 1);
+ il.Call(Word.GetUInt256);
+ il.StoreLocal(locals[0]);
+ il.StackLoadPrevious(stack.span, stack.idx, 2);
+ il.Call(Word.GetUInt256);
+ il.StoreLocal(locals[1]);
+ il.StackPop(stack.idx, 2);
+
+ // incase of custom handling, we branch to the label
+ customHandling?.Invoke(il, label, locals);
+
+ // invoke op on the uint256
+ il.LoadLocalAddress(locals[0]);
+ il.Call(GetAsMethodInfo());
+ il.LoadLocalAddress(locals[1]);
+ il.Call(GetAsMethodInfo());
+ il.LoadLocalAddress(uint256R);
+ il.Call(GetAsMethodInfo());
+ il.Call(operation);
+
+ // skip the main handling
+ il.MarkLabel(label);
+
+ // push the result to the stack
+ il.CleanAndLoadWord(stack.span, stack.idx);
+ il.LoadLocal(uint256R); // stack: word*, uint256
+ il.Call(Word.SetUInt256);
+ il.StackPush(stack.idx);
+ }
+
+ private static void EmitTrinaryUInt256Method(Emit il, Local uint256R, (Local span, Local idx) stack, MethodInfo operation, Action, Label, Local[]> customHandling, Dictionary exceptions, params Local[] locals)
+ {
+ Label label = il.DefineLabel();
+
+ // we the two uint256 from the stack
+ il.StackLoadPrevious(stack.span, stack.idx, 1);
+ il.Call(Word.GetUInt256);
+ il.StoreLocal(locals[0]);
+ il.StackLoadPrevious(stack.span, stack.idx, 2);
+ il.Call(Word.GetUInt256);
+ il.StoreLocal(locals[1]);
+ il.StackLoadPrevious(stack.span, stack.idx, 3);
+ il.Call(Word.GetUInt256);
+ il.StoreLocal(locals[2]);
+ il.StackPop(stack.idx, 3);
+
+ // incase of custom handling, we branch to the label
+ customHandling?.Invoke(il, label, locals);
+
+ // invoke op on the uint256
+ il.LoadLocalAddress(locals[0]);
+ il.LoadLocalAddress(locals[1]);
+ il.LoadLocalAddress(locals[2]);
+ il.LoadLocalAddress(uint256R);
+ il.Call(operation);
+
+ // skip the main handling
+ il.MarkLabel(label);
+
+ // push the result to the stack
+ il.CleanAndLoadWord(stack.span, stack.idx);
+ il.LoadLocal(uint256R); // stack: word*, uint256
+ il.Call(Word.SetUInt256);
+ il.StackPush(stack.idx);
+ }
+
+
+ private static void EmitLogMethod(
+ Emit