Skip to content

Commit

Permalink
Use ReadOnlySpan and ReadOnlyMemory for reducing memory copy (neo-pro…
Browse files Browse the repository at this point in the history
  • Loading branch information
erikzhang authored Apr 1, 2019
1 parent 58152f8 commit 8db80d4
Show file tree
Hide file tree
Showing 18 changed files with 243 additions and 225 deletions.
147 changes: 75 additions & 72 deletions src/neo-vm/ExecutionEngine.cs

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/neo-vm/HashComparer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ internal class HashComparer : IEqualityComparer<byte[]>
{
public bool Equals(byte[] x, byte[] y)
{
return Unsafe.Equals(x, y);
return Unsafe.SpanEquals(x, y);
}

public int GetHashCode(byte[] obj)
Expand Down
14 changes: 14 additions & 0 deletions src/neo-vm/Helper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#if !NETCOREAPP
using System.Numerics;

namespace Neo.VM
{
internal static class Helper
{
public static int GetByteCount(this BigInteger source)
{
return source.ToByteArray().Length;
}
}
}
#endif
10 changes: 6 additions & 4 deletions src/neo-vm/ICrypto.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
namespace Neo.VM
using System;

namespace Neo.VM
{
public interface ICrypto
{
byte[] Hash160(byte[] message);
byte[] Hash160(ReadOnlySpan<byte> message);

byte[] Hash256(byte[] message);
byte[] Hash256(ReadOnlySpan<byte> message);

bool VerifySignature(byte[] message, byte[] signature, byte[] pubkey);
bool VerifySignature(ReadOnlySpan<byte> message, ReadOnlySpan<byte> signature, ReadOnlySpan<byte> pubkey);
}
}
85 changes: 33 additions & 52 deletions src/neo-vm/Instruction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public class Instruction
public static Instruction RET { get; } = new Instruction(OpCode.RET);

public readonly OpCode OpCode;
public readonly byte[] Operand;
public readonly ReadOnlyMemory<byte> Operand;

private static readonly int[] OperandSizePrefixTable = new int[256];
private static readonly int[] OperandSizeTable = new int[256];
Expand All @@ -29,15 +29,39 @@ public short TokenI16
{
get
{
return BitConverter.ToInt16(Operand, 0);
#if NETCOREAPP
return BitConverter.ToInt16(Operand.Span);
#else
if (Operand.Length < sizeof(short))
throw new InvalidOperationException();
unsafe
{
fixed (byte* pbyte = Operand.Span)
{
return *(short*)pbyte;
}
}
#endif
}
}

public short TokenI16_1
{
get
{
return BitConverter.ToInt16(Operand, sizeof(short));
#if NETCOREAPP
return BitConverter.ToInt16(Operand.Span.Slice(2, 2));
#else
if (Operand.Length < sizeof(short) * 2)
throw new InvalidOperationException();
unsafe
{
fixed (byte* pbyte = &Operand.Span[sizeof(short)])
{
return *(short*)pbyte;
}
}
#endif
}
}

Expand Down Expand Up @@ -70,68 +94,25 @@ private Instruction(OpCode opcode)
internal Instruction(byte[] script, int ip)
{
this.OpCode = (OpCode)script[ip++];
int operandSizePrefix = OperandSizePrefixTable[(int)OpCode];
int operandSize = 0;
switch (OperandSizePrefixTable[(int)OpCode])
switch (operandSizePrefix)
{
case 0:
operandSize = OperandSizeTable[(int)OpCode];
break;
case 1:
operandSize = ReadByte(script, ref ip);
operandSize = script[ip];
break;
case 2:
operandSize = ReadUInt16(script, ref ip);
operandSize = BitConverter.ToUInt16(script, ip);
break;
case 4:
operandSize = ReadInt32(script, ref ip);
operandSize = BitConverter.ToInt32(script, ip);
break;
}
if (operandSize > 0)
this.Operand = ReadBytes(script, ref ip, operandSize);
}

private static byte ReadByte(byte[] script, ref int ip)
{
if (ip + sizeof(byte) > script.Length)
throw new InvalidOperationException();
return script[ip++];
}

private static byte[] ReadBytes(byte[] script, ref int ip, int count)
{
if (ip + count > script.Length)
throw new InvalidOperationException();
byte[] buffer = new byte[count];
Unsafe.MemoryCopy(script, ip, buffer, 0, count);
ip += count;
return buffer;
}

public byte[] ReadBytes(int offset, int count)
{
if (offset + count > Operand.Length)
throw new InvalidOperationException();
byte[] buffer = new byte[count];
Unsafe.MemoryCopy(Operand, offset, buffer, 0, count);
return buffer;
}

private static int ReadInt32(byte[] script, ref int ip)
{
if (ip + sizeof(int) > script.Length)
throw new InvalidOperationException();
int value = Unsafe.ToInt32(script, ip);
ip += sizeof(int);
return value;
}

private static ushort ReadUInt16(byte[] script, ref int ip)
{
if (ip + sizeof(ushort) > script.Length)
throw new InvalidOperationException();
ushort value = Unsafe.ToUInt16(script, ip);
ip += sizeof(ushort);
return value;
this.Operand = new ReadOnlyMemory<byte>(script, ip + operandSizePrefix, operandSize);
}
}
}
28 changes: 24 additions & 4 deletions src/neo-vm/StackItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,16 @@ public static StackItem FromInterface<T>(T value)

public virtual BigInteger GetBigInteger()
{
return new BigInteger(GetByteArray());
#if NETCOREAPP
return new BigInteger(GetByteArray().Span);
#else
return new BigInteger(GetByteArray().ToArray());
#endif
}

public abstract bool GetBoolean();

public abstract byte[] GetByteArray();
public abstract ReadOnlyMemory<byte> GetByteArray();

public virtual int GetByteLength()
{
Expand All @@ -46,15 +50,26 @@ public override int GetHashCode()
unchecked
{
int hash = 17;
foreach (byte element in GetByteArray())
foreach (byte element in GetByteArray().Span)
hash = hash * 31 + element;
return hash;
}
}

public virtual string GetString()
{
return Encoding.UTF8.GetString(GetByteArray());
#if NETCOREAPP
return Encoding.UTF8.GetString(GetByteArray().Span);
#else
ReadOnlySpan<byte> span = GetByteArray().Span;
unsafe
{
fixed (byte* bp = span)
{
return Encoding.UTF8.GetString(bp, span.Length);
}
}
#endif
}

public static implicit operator StackItem(int value)
Expand Down Expand Up @@ -92,6 +107,11 @@ public static implicit operator StackItem(byte[] value)
return new ByteArray(value);
}

public static implicit operator StackItem(ReadOnlyMemory<byte> value)
{
return new ByteArray(value);
}

public static implicit operator StackItem(string value)
{
return new ByteArray(Encoding.UTF8.GetBytes(value));
Expand Down
2 changes: 1 addition & 1 deletion src/neo-vm/Types/Array.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public override bool GetBoolean()
return true;
}

public override byte[] GetByteArray()
public override ReadOnlyMemory<byte> GetByteArray()
{
throw new NotSupportedException();
}
Expand Down
10 changes: 5 additions & 5 deletions src/neo-vm/Types/Boolean.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ namespace Neo.VM.Types
{
public class Boolean : StackItem
{
private static readonly byte[] TRUE = { 1 };
private static readonly byte[] FALSE = new byte[0];
private static readonly ReadOnlyMemory<byte> TRUE = new byte[] { 1 };
private static readonly ReadOnlyMemory<byte> FALSE = ReadOnlyMemory<byte>.Empty;

private bool value;

Expand All @@ -20,7 +20,7 @@ public override bool Equals(StackItem other)
if (ReferenceEquals(this, other)) return true;
if (ReferenceEquals(null, other)) return false;
if (other is Boolean b) return value == b.value;
byte[] bytes_other;
ReadOnlyMemory<byte> bytes_other;
try
{
bytes_other = other.GetByteArray();
Expand All @@ -29,7 +29,7 @@ public override bool Equals(StackItem other)
{
return false;
}
return Unsafe.Equals(GetByteArray(), bytes_other);
return Unsafe.SpanEquals(GetByteArray().Span, bytes_other.Span);
}

public override BigInteger GetBigInteger()
Expand All @@ -42,7 +42,7 @@ public override bool GetBoolean()
return value;
}

public override byte[] GetByteArray()
public override ReadOnlyMemory<byte> GetByteArray()
{
return value ? TRUE : FALSE;
}
Expand Down
12 changes: 6 additions & 6 deletions src/neo-vm/Types/ByteArray.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ namespace Neo.VM.Types
{
public class ByteArray : StackItem
{
private byte[] value;
private ReadOnlyMemory<byte> value;

public ByteArray(byte[] value)
public ByteArray(ReadOnlyMemory<byte> value)
{
this.value = value;
}
Expand All @@ -15,7 +15,7 @@ public override bool Equals(StackItem other)
{
if (ReferenceEquals(this, other)) return true;
if (ReferenceEquals(null, other)) return false;
byte[] bytes_other;
ReadOnlyMemory<byte> bytes_other;
try
{
bytes_other = other.GetByteArray();
Expand All @@ -24,17 +24,17 @@ public override bool Equals(StackItem other)
{
return false;
}
return Unsafe.Equals(value, bytes_other);
return Unsafe.SpanEquals(value.Span, bytes_other.Span);
}

public override bool GetBoolean()
{
if (value.Length > ExecutionEngine.MaxSizeForBigInteger)
return true;
return Unsafe.NotZero(value);
return Unsafe.NotZero(value.Span);
}

public override byte[] GetByteArray()
public override ReadOnlyMemory<byte> GetByteArray()
{
return value;
}
Expand Down
15 changes: 11 additions & 4 deletions src/neo-vm/Types/Integer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public override bool Equals(StackItem other)
if (ReferenceEquals(this, other)) return true;
if (ReferenceEquals(null, other)) return false;
if (other is Integer i) return value == i.value;
byte[] bytes_other;
ReadOnlyMemory<byte> bytes_other;
try
{
bytes_other = other.GetByteArray();
Expand All @@ -26,7 +26,7 @@ public override bool Equals(StackItem other)
{
return false;
}
return Unsafe.Equals(GetByteArray(), bytes_other);
return Unsafe.SpanEquals(GetByteArray().Span, bytes_other.Span);
}

public override BigInteger GetBigInteger()
Expand All @@ -39,17 +39,24 @@ public override bool GetBoolean()
return !value.IsZero;
}

public override byte[] GetByteArray()
public override ReadOnlyMemory<byte> GetByteArray()
{
return value.ToByteArray();
}

#if NETCOREAPP
public override int GetByteLength()
{
return value.GetByteCount();
}
#else
private int _length = -1;
public override int GetByteLength()
{
if (_length == -1)
_length = value.ToByteArray().Length;
_length = value.GetByteCount();
return _length;
}
#endif
}
}
2 changes: 1 addition & 1 deletion src/neo-vm/Types/InteropInterface.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace Neo.VM.Types
{
public abstract class InteropInterface : StackItem
{
public override byte[] GetByteArray()
public override ReadOnlyMemory<byte> GetByteArray()
{
throw new NotSupportedException();
}
Expand Down
2 changes: 1 addition & 1 deletion src/neo-vm/Types/Map.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public override bool GetBoolean()
return true;
}

public override byte[] GetByteArray()
public override ReadOnlyMemory<byte> GetByteArray()
{
throw new NotSupportedException();
}
Expand Down
Loading

0 comments on commit 8db80d4

Please sign in to comment.