Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Further Improve JumpDestAnalysis (x20 improvement) #6554

Merged
merged 13 commits into from
Jan 18, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@
using Nethermind.JsonRpc.Data;
using Nethermind.JsonRpc.Test.Modules;
using Nethermind.Logging;

using Newtonsoft.Json.Linq;
using Nethermind.State;
using NUnit.Framework;

namespace Nethermind.AccountAbstraction.Test;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using Nethermind.Evm.Test;
using Nethermind.Logging;
using Nethermind.Specs;
using Nethermind.State;
using NUnit.Framework;

namespace Nethermind.AccountAbstraction.Test
Expand Down
77 changes: 77 additions & 0 deletions src/Nethermind/Nethermind.Evm.Test/CodeAnalysis/CodeInfoTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

using System.Linq;
using System.Reflection;
using System.Runtime.Intrinsics;

using FluentAssertions;
using Nethermind.Evm.CodeAnalysis;
using NUnit.Framework;
Expand Down Expand Up @@ -165,5 +167,80 @@ public void Push1Jumpdest_Over10k()
codeInfo.ValidateJump(10, false).Should().BeFalse();
codeInfo.ValidateJump(11, false).Should().BeFalse(); // 0x5b but not JUMPDEST but data
}

[TestCase(1)]
[TestCase(2)]
[TestCase(3)]
[TestCase(4)]
[TestCase(5)]
[TestCase(6)]
[TestCase(7)]
[TestCase(8)]
[TestCase(9)]
[TestCase(10)]
[TestCase(11)]
[TestCase(12)]
[TestCase(13)]
[TestCase(14)]
[TestCase(15)]
[TestCase(16)]
[TestCase(17)]
[TestCase(18)]
[TestCase(19)]
[TestCase(20)]
[TestCase(21)]
[TestCase(22)]
[TestCase(23)]
[TestCase(24)]
[TestCase(25)]
[TestCase(26)]
[TestCase(27)]
[TestCase(28)]
[TestCase(29)]
[TestCase(30)]
[TestCase(31)]
[TestCase(32)]
public void PushNJumpdest_Over10k(int n)
{
byte[] code = new byte[10_001];

// One vector (aligned), half vector to unalign
int i;
for (i = 0; i < Vector256<byte>.Count * 2 + Vector128<byte>.Count; i++)
{
code[i] = (byte)0x5b;
}
for (; i < Vector256<byte>.Count * 3; i++)
{
//
}
var triggerPushes = false;
for (; i < code.Length; i++)
{
if (i % (n + 1) == 0)
{
triggerPushes = true;
}
if (triggerPushes)
{
code[i] = i % (n + 1) == 0 ? (byte)(0x60 + n - 1) : (byte)0x5b;
}
}

CodeInfo codeInfo = new(code);

for (i = 0; i < Vector256<byte>.Count * 2 + Vector128<byte>.Count; i++)
{
codeInfo.ValidateJump(i, false).Should().BeTrue();
}
for (; i < Vector256<byte>.Count * 3; i++)
{
codeInfo.ValidateJump(i, false).Should().BeFalse();
}
for (; i < code.Length; i++)
{
codeInfo.ValidateJump(i, false).Should().BeFalse(); // Are 0x5b but not JUMPDEST but data
}
}
}
}
1 change: 1 addition & 0 deletions src/Nethermind/Nethermind.Evm.Test/Eip1014Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Nethermind.Core.Crypto;
using Nethermind.Core.Extensions;
using Nethermind.Specs;
using Nethermind.State;
using Nethermind.Core.Test.Builders;
using Nethermind.Evm.Tracing.GethStyle;
using Nethermind.Trie;
Expand Down
1 change: 1 addition & 0 deletions src/Nethermind/Nethermind.Evm.Test/Eip1052Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using Nethermind.Evm.Precompiles;
using Nethermind.Specs.Forks;
using Nethermind.Specs.Test;
using Nethermind.State;
using NUnit.Framework;

namespace Nethermind.Evm.Test
Expand Down
1 change: 1 addition & 0 deletions src/Nethermind/Nethermind.Evm.Test/Eip1153Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using Nethermind.Core.Extensions;
using Nethermind.Specs;
using Nethermind.State;
using Nethermind.Core.Test.Builders;
using NUnit.Framework;
using System.Diagnostics;
Expand Down
1 change: 1 addition & 0 deletions src/Nethermind/Nethermind.Evm.Test/Eip1884Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Nethermind.Core.Extensions;
using Nethermind.Core.Specs;
using Nethermind.Specs;
using Nethermind.State;
using Nethermind.Core.Test.Builders;
using Nethermind.Int256;
using NUnit.Framework;
Expand Down
1 change: 1 addition & 0 deletions src/Nethermind/Nethermind.Evm.Test/Eip3860Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using Nethermind.Core.Extensions;
using Nethermind.Specs;
using Nethermind.State;
using Nethermind.Core.Test.Builders;
using NUnit.Framework;
using Nethermind.Core;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using Nethermind.Logging;
using Nethermind.Specs;
using Nethermind.Specs.Forks;
using Nethermind.State;
using NUnit.Framework;

namespace Nethermind.Evm.Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
using Nethermind.Core.Test.Builders;
using Nethermind.Evm.Tracing.GethStyle.JavaScript;
using Nethermind.Int256;
using Nethermind.JsonRpc.Modules.DebugModule;
using Nethermind.Serialization.Json;
using Nethermind.Specs.Forks;
using Nethermind.State;

namespace Nethermind.Evm.Test.Tracing;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using Nethermind.Core.Extensions;
using Nethermind.Core.Test.Builders;
using Nethermind.Evm.Tracing.GethStyle;
using Nethermind.State;
using NUnit.Framework;

namespace Nethermind.Evm.Test.Tracing;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using Nethermind.Int256;
using Nethermind.Evm.Precompiles;
using Nethermind.Evm.Tracing.ParityStyle;
using Nethermind.State;
using NUnit.Framework;

namespace Nethermind.Evm.Test.Tracing
Expand Down
1 change: 1 addition & 0 deletions src/Nethermind/Nethermind.Evm.Test/VmCodeDepositTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Nethermind.Core;
using Nethermind.Core.Extensions;
using Nethermind.Specs;
using Nethermind.State;
using Nethermind.Core.Test.Builders;
using NUnit.Framework;

Expand Down
31 changes: 12 additions & 19 deletions src/Nethermind/Nethermind.Evm/ByteArrayExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,25 +34,18 @@ private static ZeroPaddedSpan SliceWithZeroPadding(this ReadOnlySpan<byte> span,
return new ZeroPaddedSpan(span.Slice(startIndex, copiedLength), length - copiedLength, padDirection);
}

public static ZeroPaddedSpan SliceWithZeroPadding(this Span<byte> span, scoped in UInt256 startIndex, int length, PadDirection padDirection = PadDirection.Right)
{
if (startIndex >= span.Length || startIndex > int.MaxValue)
{
return new ZeroPaddedSpan(default, length, PadDirection.Right);
}

return SliceWithZeroPadding(span, (int)startIndex, length, padDirection);
}

public static ZeroPaddedSpan SliceWithZeroPadding(this ReadOnlyMemory<byte> bytes, scoped in UInt256 startIndex, int length, PadDirection padDirection = PadDirection.Right)
{
if (startIndex >= bytes.Length || startIndex > int.MaxValue)
{
return new ZeroPaddedSpan(default, length, PadDirection.Right);
}

return SliceWithZeroPadding(bytes.Span, (int)startIndex, length, padDirection);
}
public static ZeroPaddedSpan SliceWithZeroPadding(this Span<byte> span, scoped in UInt256 startIndex, int length, PadDirection padDirection = PadDirection.Right) => startIndex >= span.Length || startIndex > int.MaxValue
? new ZeroPaddedSpan(default, length, PadDirection.Right)
: SliceWithZeroPadding(span, (int)startIndex, length, padDirection);

public static ZeroPaddedSpan SliceWithZeroPadding(this ReadOnlySpan<byte> span, scoped in UInt256 startIndex, int length, PadDirection padDirection = PadDirection.Right) => startIndex >= span.Length || startIndex > int.MaxValue
benaadams marked this conversation as resolved.
Show resolved Hide resolved
? new ZeroPaddedSpan(default, length, PadDirection.Right)
: SliceWithZeroPadding(span, (int)startIndex, length, padDirection);

public static ZeroPaddedSpan SliceWithZeroPadding(this ReadOnlyMemory<byte> bytes, scoped in UInt256 startIndex, int length, PadDirection padDirection = PadDirection.Right) =>
startIndex >= bytes.Length || startIndex > int.MaxValue
? new ZeroPaddedSpan(default, length, PadDirection.Right)
: SliceWithZeroPadding(bytes.Span, (int)startIndex, length, padDirection);

public static ZeroPaddedSpan SliceWithZeroPadding(this byte[] bytes, scoped in UInt256 startIndex, int length, PadDirection padDirection = PadDirection.Right) =>
bytes.AsSpan().SliceWithZeroPadding(startIndex, length, padDirection);
Expand Down
32 changes: 17 additions & 15 deletions src/Nethermind/Nethermind.Evm/CodeAnalysis/CodeInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,30 @@
// SPDX-License-Identifier: LGPL-3.0-only

using System;
using System.Runtime.CompilerServices;
using System.Threading;

using Nethermind.Evm.Precompiles;

namespace Nethermind.Evm.CodeAnalysis
{
public class CodeInfo
public class CodeInfo : IThreadPoolWorkItem
{
public byte[] MachineCode { get; set; }
public ReadOnlyMemory<byte> MachineCode { get; }
public IPrecompile? Precompile { get; set; }
private JumpDestinationAnalyzer? _analyzer;
private readonly JumpDestinationAnalyzer _analyzer;
private static readonly JumpDestinationAnalyzer _emptyAnalyzer = new(Array.Empty<byte>());
public static CodeInfo Empty { get; } = new CodeInfo(Array.Empty<byte>());

public CodeInfo(byte[] code)
{
MachineCode = code;
_analyzer = code.Length == 0 ? _emptyAnalyzer : new JumpDestinationAnalyzer(code);
}

public CodeInfo(ReadOnlyMemory<byte> code)
{
MachineCode = code;
_analyzer = code.Length == 0 ? _emptyAnalyzer : new JumpDestinationAnalyzer(code);
}

public bool IsPrecompile => Precompile is not null;
Expand All @@ -25,24 +34,17 @@ public CodeInfo(IPrecompile precompile)
{
Precompile = precompile;
MachineCode = Array.Empty<byte>();
_analyzer = _emptyAnalyzer;
}

public bool ValidateJump(int destination, bool isSubroutine)
{
JumpDestinationAnalyzer analyzer = _analyzer;
analyzer ??= CreateAnalyzer();

return analyzer.ValidateJump(destination, isSubroutine);
return _analyzer.ValidateJump(destination, isSubroutine);
}

/// <summary>
/// Do sampling to choose an algo when the code is big enough.
/// When the code size is small we can use the default analyzer.
/// </summary>
[MethodImpl(MethodImplOptions.NoInlining)]
private JumpDestinationAnalyzer CreateAnalyzer()
void IThreadPoolWorkItem.Execute()
{
return _analyzer = new JumpDestinationAnalyzer(MachineCode);
_analyzer.Execute();
}
}
}
Loading