diff --git a/src/Neo.VM/Collections/OrderedDictionary.cs b/src/Neo.VM/Collections/OrderedDictionary.cs index e2757dcb..a3877e7d 100644 --- a/src/Neo.VM/Collections/OrderedDictionary.cs +++ b/src/Neo.VM/Collections/OrderedDictionary.cs @@ -1,10 +1,10 @@ // Copyright (C) 2016-2022 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, +// +// The neo-vm is free software distributed under the MIT software license, // see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// project or http://www.opensource.org/licenses/mit-license.php // for more details. -// +// // Redistribution and use in source and binary forms with or without // modifications are permitted. @@ -39,7 +39,7 @@ protected override TKey GetKeyForItem(TItem item) } } - private readonly InternalCollection collection = new(); + private readonly InternalCollection collection = new InternalCollection(); public int Count => collection.Count; public bool IsReadOnly => false; @@ -76,7 +76,10 @@ public bool Remove(TKey key) return collection.Remove(key); } + // supress warning of value parameter nullability mismatch +#pragma warning disable CS8767 public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) +#pragma warning restore CS8767 { if (collection.TryGetValue(key, out var entry)) { diff --git a/src/Neo.VM/Cryptography/BitOperations.cs b/src/Neo.VM/Cryptography/BitOperations.cs new file mode 100644 index 00000000..7661e56e --- /dev/null +++ b/src/Neo.VM/Cryptography/BitOperations.cs @@ -0,0 +1,28 @@ +// Copyright (C) 2015-2022 The Neo Project. +// +// The neo is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace Neo.VM.Cryptography +{ +#if !NET5_0_OR_GREATER + static class BitOperations + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint RotateLeft(uint value, int offset) + => (value << offset) | (value >> (32 - offset)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ulong RotateLeft(ulong value, int offset) + => (value << offset) | (value >> (64 - offset)); + } +#endif +} diff --git a/src/Neo.VM/Debugger.cs b/src/Neo.VM/Debugger.cs index 73000c04..776a6a79 100644 --- a/src/Neo.VM/Debugger.cs +++ b/src/Neo.VM/Debugger.cs @@ -1,10 +1,10 @@ // Copyright (C) 2016-2022 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, +// +// The neo-vm is free software distributed under the MIT software license, // see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// project or http://www.opensource.org/licenses/mit-license.php // for more details. -// +// // Redistribution and use in source and binary forms with or without // modifications are permitted. @@ -18,7 +18,7 @@ namespace Neo.VM public class Debugger { private readonly ExecutionEngine engine; - private readonly Dictionary> break_points = new(); + private readonly Dictionary> break_points = new Dictionary>(); /// /// Create a debugger on the specified . diff --git a/src/Neo.VM/EvaluationStack.cs b/src/Neo.VM/EvaluationStack.cs index 5e73bc30..831694a9 100644 --- a/src/Neo.VM/EvaluationStack.cs +++ b/src/Neo.VM/EvaluationStack.cs @@ -1,10 +1,10 @@ // Copyright (C) 2016-2022 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, +// +// The neo-vm is free software distributed under the MIT software license, // see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// project or http://www.opensource.org/licenses/mit-license.php // for more details. -// +// // Redistribution and use in source and binary forms with or without // modifications are permitted. @@ -22,7 +22,7 @@ namespace Neo.VM /// public sealed class EvaluationStack : IReadOnlyList { - private readonly List innerList = new(); + private readonly List innerList = new List(); private readonly ReferenceCounter referenceCounter; internal EvaluationStack(ReferenceCounter referenceCounter) @@ -152,7 +152,7 @@ internal T Remove(int index) where T : StackItem throw new ArgumentOutOfRangeException(nameof(index)); } index = innerList.Count - index - 1; - if (innerList[index] is not T item) + if (!(innerList[index] is T item)) throw new InvalidCastException($"The item can't be casted to type {typeof(T)}"); innerList.RemoveAt(index); referenceCounter.RemoveStackReference(item); diff --git a/src/Neo.VM/ExecutionEngine.cs b/src/Neo.VM/ExecutionEngine.cs index befb8bcf..84f984fa 100644 --- a/src/Neo.VM/ExecutionEngine.cs +++ b/src/Neo.VM/ExecutionEngine.cs @@ -1,10 +1,10 @@ // Copyright (C) 2016-2022 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, +// +// The neo-vm is free software distributed under the MIT software license, // see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// project or http://www.opensource.org/licenses/mit-license.php // for more details. -// +// // Redistribution and use in source and binary forms with or without // modifications are permitted. @@ -703,7 +703,7 @@ private void ExecuteInstruction(Instruction instruction) var x1 = Pop().GetSpan(); int length = x1.Length + x2.Length; Limits.AssertMaxItemSize(length); - Buffer result = new(length, false); + Buffer result = new Buffer(length, false); x1.CopyTo(result.InnerBuffer.Span); x2.CopyTo(result.InnerBuffer.Span[x1.Length..]); Push(result); @@ -720,7 +720,7 @@ private void ExecuteInstruction(Instruction instruction) var x = Pop().GetSpan(); if (index + count > x.Length) throw new InvalidOperationException($"The value {count} is out of range."); - Buffer result = new(count, false); + Buffer result = new Buffer(count, false); x.Slice(index, count).CopyTo(result.InnerBuffer.Span); Push(result); break; @@ -733,7 +733,7 @@ private void ExecuteInstruction(Instruction instruction) var x = Pop().GetSpan(); if (count > x.Length) throw new InvalidOperationException($"The value {count} is out of range."); - Buffer result = new(count, false); + Buffer result = new Buffer(count, false); x[..count].CopyTo(result.InnerBuffer.Span); Push(result); break; @@ -746,7 +746,7 @@ private void ExecuteInstruction(Instruction instruction) var x = Pop().GetSpan(); if (count > x.Length) throw new InvalidOperationException($"The value {count} is out of range."); - Buffer result = new(count, false); + Buffer result = new Buffer(count, false); x[^count..^0].CopyTo(result.InnerBuffer.Span); Push(result); break; @@ -1020,7 +1020,7 @@ private void ExecuteInstruction(Instruction instruction) int size = (int)Pop().GetInteger(); if (size < 0 || size * 2 > CurrentContext!.EvaluationStack.Count) throw new InvalidOperationException($"The value {size} is out of range."); - Map map = new(ReferenceCounter); + Map map = new Map(ReferenceCounter); for (int i = 0; i < size; i++) { PrimitiveType key = Pop(); @@ -1035,7 +1035,7 @@ private void ExecuteInstruction(Instruction instruction) int size = (int)Pop().GetInteger(); if (size < 0 || size > CurrentContext!.EvaluationStack.Count) throw new InvalidOperationException($"The value {size} is out of range."); - Struct @struct = new(ReferenceCounter); + Struct @struct = new Struct(ReferenceCounter); for (int i = 0; i < size; i++) { StackItem item = Pop(); @@ -1049,7 +1049,7 @@ private void ExecuteInstruction(Instruction instruction) int size = (int)Pop().GetInteger(); if (size < 0 || size > CurrentContext!.EvaluationStack.Count) throw new InvalidOperationException($"The value {size} is out of range."); - VMArray array = new(ReferenceCounter); + VMArray array = new VMArray(ReferenceCounter); for (int i = 0; i < size; i++) { StackItem item = Pop(); @@ -1124,7 +1124,7 @@ private void ExecuteInstruction(Instruction instruction) int n = (int)Pop().GetInteger(); if (n < 0 || n > Limits.MaxStackSize) throw new InvalidOperationException($"MaxStackSize exceed: {n}"); - Struct result = new(ReferenceCounter); + Struct result = new Struct(ReferenceCounter); for (var i = 0; i < n; i++) result.Add(StackItem.Null); Push(result); @@ -1209,7 +1209,7 @@ private void ExecuteInstruction(Instruction instruction) Map map => map.Values, _ => throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {x.Type}"), }; - VMArray newArray = new(ReferenceCounter); + VMArray newArray = new VMArray(ReferenceCounter); foreach (StackItem item in values) if (item is Struct s) newArray.Add(s.Clone(Limits)); @@ -1295,7 +1295,7 @@ private void ExecuteInstruction(Instruction instruction) int index = (int)key.GetInteger(); if (index < 0 || index >= buffer.Size) throw new CatchableException($"The value {index} is out of range."); - if (value is not PrimitiveType p) + if (!(value is PrimitiveType p)) throw new InvalidOperationException($"Value must be a primitive type in {instruction.OpCode}"); int b = (int)p.GetInteger(); if (b < sbyte.MinValue || b > byte.MaxValue) diff --git a/src/Neo.VM/ExecutionEngineLimits.cs b/src/Neo.VM/ExecutionEngineLimits.cs index 6e92965f..3598dc92 100644 --- a/src/Neo.VM/ExecutionEngineLimits.cs +++ b/src/Neo.VM/ExecutionEngineLimits.cs @@ -1,10 +1,10 @@ // Copyright (C) 2016-2022 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, +// +// The neo-vm is free software distributed under the MIT software license, // see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// project or http://www.opensource.org/licenses/mit-license.php // for more details. -// +// // Redistribution and use in source and binary forms with or without // modifications are permitted. @@ -16,47 +16,103 @@ namespace Neo.VM /// /// Represents the restrictions on the VM. /// - public sealed record ExecutionEngineLimits + public sealed class ExecutionEngineLimits : IEquatable { /// /// The default strategy. /// - public static readonly ExecutionEngineLimits Default = new(); + public static readonly ExecutionEngineLimits Default = new ExecutionEngineLimits(); /// /// The maximum number of bits that and can shift. /// - public int MaxShift { get; init; } = 256; + public int MaxShift + { + get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } = 256; /// /// The maximum number of items that can be contained in the VM's evaluation stacks and slots. /// - public uint MaxStackSize { get; init; } = 2 * 1024; + public uint MaxStackSize + { + get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } = 2 * 1024; /// /// The maximum size of an item in the VM. /// - public uint MaxItemSize { get; init; } = 1024 * 1024; + public uint MaxItemSize + { + get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } = 1024 * 1024; /// /// The largest comparable size. If a or exceeds this size, comparison operations on it cannot be performed in the VM. /// - public uint MaxComparableSize { get; init; } = 65536; + public uint MaxComparableSize + { + get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } = 65536; /// /// The maximum number of frames in the invocation stack of the VM. /// - public uint MaxInvocationStackSize { get; init; } = 1024; + public uint MaxInvocationStackSize + { + get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } = 1024; /// /// The maximum nesting depth of -- blocks. /// - public uint MaxTryNestingDepth { get; init; } = 16; + public uint MaxTryNestingDepth + { + get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } = 16; /// /// Allow to catch the ExecutionEngine Exceptions /// - public bool CatchEngineExceptions { get; init; } = true; + public bool CatchEngineExceptions + { + get; +#if NET5_0_OR_GREATER + init; +#else + set; +#endif + } = true; /// /// Assert that the size of the item meets the limit. @@ -83,5 +139,19 @@ public void AssertShift(int shift) throw new InvalidOperationException($"Invalid shift value: {shift}"); } } + + public bool Equals(ExecutionEngineLimits? other) + { + if (ReferenceEquals(this, other)) return true; + if (other is null) return false; + return MaxShift == other.MaxShift + && MaxStackSize == other.MaxStackSize + && MaxItemSize == other.MaxItemSize + && MaxComparableSize == other.MaxComparableSize + && MaxInvocationStackSize == other.MaxInvocationStackSize + && MaxInvocationStackSize == other.MaxInvocationStackSize + && MaxTryNestingDepth == other.MaxTryNestingDepth + && CatchEngineExceptions == other.CatchEngineExceptions; + } } } diff --git a/src/Neo.VM/Instruction.cs b/src/Neo.VM/Instruction.cs index 17bf86f3..d4fbbc19 100644 --- a/src/Neo.VM/Instruction.cs +++ b/src/Neo.VM/Instruction.cs @@ -1,10 +1,10 @@ // Copyright (C) 2016-2022 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, +// +// The neo-vm is free software distributed under the MIT software license, // see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// project or http://www.opensource.org/licenses/mit-license.php // for more details. -// +// // Redistribution and use in source and binary forms with or without // modifications are permitted. @@ -191,7 +191,7 @@ static Instruction() private Instruction(OpCode opcode) { this.OpCode = opcode; - if (!Enum.IsDefined(opcode)) throw new BadScriptException(); + if (!Enum.IsDefined(typeof(OpCode), opcode)) throw new BadScriptException(); } internal Instruction(ReadOnlyMemory script, int ip) : this((OpCode)script.Span[ip++]) diff --git a/src/Neo.VM/Neo.VM.csproj b/src/Neo.VM/Neo.VM.csproj index 1852c835..f12820d1 100644 --- a/src/Neo.VM/Neo.VM.csproj +++ b/src/Neo.VM/Neo.VM.csproj @@ -5,7 +5,7 @@ Neo virtual machine 3.4.0 The Neo Project - net6.0 + netstandard2.1;net5.0;net6.0 NEO;AntShares;Blockchain;Smart Contract;VM https://github.com/neo-project/neo-vm MIT diff --git a/src/Neo.VM/ReferenceCounter.cs b/src/Neo.VM/ReferenceCounter.cs index 1a4b664d..dc348cc2 100644 --- a/src/Neo.VM/ReferenceCounter.cs +++ b/src/Neo.VM/ReferenceCounter.cs @@ -1,10 +1,10 @@ // Copyright (C) 2016-2022 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, +// +// The neo-vm is free software distributed under the MIT software license, // see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// project or http://www.opensource.org/licenses/mit-license.php // for more details. -// +// // Redistribution and use in source and binary forms with or without // modifications are permitted. @@ -23,8 +23,8 @@ public sealed class ReferenceCounter { private const bool TrackAllItems = false; - private readonly HashSet tracked_items = new(ReferenceEqualityComparer.Instance); - private readonly HashSet zero_referred = new(ReferenceEqualityComparer.Instance); + private readonly HashSet tracked_items = new HashSet(ReferenceEqualityComparer.Instance); + private readonly HashSet zero_referred = new HashSet(ReferenceEqualityComparer.Instance); private LinkedList>? cached_components; private int references_count = 0; @@ -39,7 +39,8 @@ private static bool NeedTrack(StackItem item) #pragma warning disable CS0162 if (TrackAllItems) return true; #pragma warning restore CS0162 - if (item is CompoundType or Buffer) return true; + if (item is CompoundType) return true; + if (item is Buffer) return true; return false; } @@ -49,10 +50,10 @@ internal void AddReference(StackItem item, CompoundType parent) if (!NeedTrack(item)) return; cached_components = null; tracked_items.Add(item); - item.ObjectReferences ??= new(ReferenceEqualityComparer.Instance); + item.ObjectReferences ??= new Dictionary(ReferenceEqualityComparer.Instance); if (!item.ObjectReferences.TryGetValue(parent, out var pEntry)) { - pEntry = new(parent); + pEntry = new StackItem.ObjectReferenceEntry(parent); item.ObjectReferences.Add(parent, pEntry); } pEntry.References++; @@ -84,7 +85,7 @@ internal int CheckZeroReferred() if (cached_components is null) { //Tarjan tarjan = new(tracked_items.Where(p => p.StackReferences == 0)); - Tarjan tarjan = new(tracked_items); + Tarjan tarjan = new Tarjan(tracked_items); cached_components = tarjan.Invoke(); } foreach (StackItem item in tracked_items) diff --git a/src/Neo.VM/ReferenceEqualityComparer.cs b/src/Neo.VM/ReferenceEqualityComparer.cs new file mode 100644 index 00000000..c824f9e7 --- /dev/null +++ b/src/Neo.VM/ReferenceEqualityComparer.cs @@ -0,0 +1,29 @@ +// Copyright (C) 2016-2022 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +namespace Neo.VM +{ +#if !NET5_0_OR_GREATER + // https://github.dev/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ReferenceEqualityComparer.cs + public sealed class ReferenceEqualityComparer : IEqualityComparer, System.Collections.IEqualityComparer + { + private ReferenceEqualityComparer() { } + + public static ReferenceEqualityComparer Instance { get; } = new ReferenceEqualityComparer(); + + public new bool Equals(object? x, object? y) => ReferenceEquals(x, y); + + public int GetHashCode(object? obj) => RuntimeHelpers.GetHashCode(obj!); + } +#endif +} diff --git a/src/Neo.VM/Script.cs b/src/Neo.VM/Script.cs index 2a5213d1..9ad2be93 100644 --- a/src/Neo.VM/Script.cs +++ b/src/Neo.VM/Script.cs @@ -24,7 +24,7 @@ public class Script { private readonly ReadOnlyMemory _value; private readonly bool strictMode; - private readonly Dictionary _instructions = new(); + private readonly Dictionary _instructions = new Dictionary(); /// /// The length of the script. @@ -154,7 +154,7 @@ public Instruction GetInstruction(int ip) } public static implicit operator ReadOnlyMemory(Script script) => script._value; - public static implicit operator Script(ReadOnlyMemory script) => new(script); - public static implicit operator Script(byte[] script) => new(script); + public static implicit operator Script(ReadOnlyMemory script) => new Script(script); + public static implicit operator Script(byte[] script) => new Script(script); } } diff --git a/src/Neo.VM/ScriptBuilder.cs b/src/Neo.VM/ScriptBuilder.cs index 63761553..fc793663 100644 --- a/src/Neo.VM/ScriptBuilder.cs +++ b/src/Neo.VM/ScriptBuilder.cs @@ -19,7 +19,7 @@ namespace Neo.VM /// public class ScriptBuilder : IDisposable { - private readonly MemoryStream ms = new(); + private readonly MemoryStream ms = new MemoryStream(); private readonly BinaryWriter writer; /// @@ -96,15 +96,19 @@ public ScriptBuilder EmitPush(BigInteger value) Span buffer = stackalloc byte[32]; if (!value.TryWriteBytes(buffer, out int bytesWritten, isUnsigned: false, isBigEndian: false)) throw new ArgumentOutOfRangeException(nameof(value)); - return bytesWritten switch - { - 1 => Emit(OpCode.PUSHINT8, PadRight(buffer, bytesWritten, 1, value.Sign < 0)), - 2 => Emit(OpCode.PUSHINT16, PadRight(buffer, bytesWritten, 2, value.Sign < 0)), - <= 4 => Emit(OpCode.PUSHINT32, PadRight(buffer, bytesWritten, 4, value.Sign < 0)), - <= 8 => Emit(OpCode.PUSHINT64, PadRight(buffer, bytesWritten, 8, value.Sign < 0)), - <= 16 => Emit(OpCode.PUSHINT128, PadRight(buffer, bytesWritten, 16, value.Sign < 0)), - _ => Emit(OpCode.PUSHINT256, PadRight(buffer, bytesWritten, 32, value.Sign < 0)), - }; + + return bytesWritten <= 8 + ? bytesWritten > 4 + ? Emit(OpCode.PUSHINT64, PadRight(buffer, bytesWritten, 8, value.Sign < 0)) + : bytesWritten switch + { + 1 => Emit(OpCode.PUSHINT8, PadRight(buffer, bytesWritten, 1, value.Sign < 0)), + 2 => Emit(OpCode.PUSHINT16, PadRight(buffer, bytesWritten, 2, value.Sign < 0)), + _ => Emit(OpCode.PUSHINT32, PadRight(buffer, bytesWritten, 4, value.Sign < 0)), + } + : bytesWritten > 16 + ? Emit(OpCode.PUSHINT256, PadRight(buffer, bytesWritten, 32, value.Sign < 0)) + : Emit(OpCode.PUSHINT128, PadRight(buffer, bytesWritten, 16, value.Sign < 0)); } /// diff --git a/src/Neo.VM/StronglyConnectedComponents/Tarjan.cs b/src/Neo.VM/StronglyConnectedComponents/Tarjan.cs index 6bbea540..b9425514 100644 --- a/src/Neo.VM/StronglyConnectedComponents/Tarjan.cs +++ b/src/Neo.VM/StronglyConnectedComponents/Tarjan.cs @@ -1,10 +1,10 @@ // Copyright (C) 2016-2022 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, +// +// The neo-vm is free software distributed under the MIT software license, // see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// project or http://www.opensource.org/licenses/mit-license.php // for more details. -// +// // Redistribution and use in source and binary forms with or without // modifications are permitted. @@ -17,8 +17,8 @@ namespace Neo.VM.StronglyConnectedComponents class Tarjan { private readonly IEnumerable vertexs; - private readonly LinkedList> components = new(); - private readonly Stack stack = new(); + private readonly LinkedList> components = new LinkedList>(); + private readonly Stack stack = new Stack(); private int index = 0; public Tarjan(IEnumerable vertexs) @@ -59,7 +59,7 @@ private void StrongConnect(T v) if (v.LowLink == v.DFN) { - HashSet scc = new(ReferenceEqualityComparer.Instance); + HashSet scc = new HashSet(ReferenceEqualityComparer.Instance); T w; do { @@ -73,11 +73,12 @@ private void StrongConnect(T v) private void StrongConnectNonRecursive(T v) { - Stack<(T, T?, IEnumerator?, int)> sstack = new(); + Stack<(T, T?, IEnumerator?, int)> sstack = new Stack<(T, T?, IEnumerator?, int)>(); sstack.Push((v, null, null, 0)); while (sstack.TryPop(out var state)) { - (v, T? w, IEnumerator? s, int n) = state; + v = state.Item1; + var (_, w, s, n) = state; switch (n) { case 0: @@ -106,7 +107,7 @@ private void StrongConnectNonRecursive(T v) } if (v.LowLink == v.DFN) { - HashSet scc = new(ReferenceEqualityComparer.Instance); + HashSet scc = new HashSet(ReferenceEqualityComparer.Instance); do { w = stack.Pop(); diff --git a/src/Neo.VM/Types/Buffer.cs b/src/Neo.VM/Types/Buffer.cs index aa73ca04..f35975d0 100644 --- a/src/Neo.VM/Types/Buffer.cs +++ b/src/Neo.VM/Types/Buffer.cs @@ -1,10 +1,10 @@ // Copyright (C) 2016-2022 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, +// +// The neo-vm is free software distributed under the MIT software license, // see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// project or http://www.opensource.org/licenses/mit-license.php // for more details. -// +// // Redistribution and use in source and binary forms with or without // modifications are permitted. @@ -77,7 +77,11 @@ public override StackItem ConvertTo(StackItemType type) throw new InvalidCastException(); return new BigInteger(InnerBuffer.Span); case StackItemType.ByteString: +#if NET5_0_OR_GREATER byte[] clone = GC.AllocateUninitializedArray(InnerBuffer.Length); +#else + byte[] clone = new byte[InnerBuffer.Length]; +#endif InnerBuffer.CopyTo(clone); return clone; default: @@ -88,7 +92,9 @@ public override StackItem ConvertTo(StackItemType type) internal override StackItem DeepCopy(Dictionary refMap, bool asImmutable) { if (refMap.TryGetValue(this, out StackItem? mappedItem)) return mappedItem; - StackItem result = asImmutable ? new ByteString(InnerBuffer.ToArray()) : new Buffer(InnerBuffer.Span); + StackItem result = asImmutable + ? (StackItem)new ByteString(InnerBuffer.ToArray()) + : new Buffer(InnerBuffer.Span); refMap.Add(this, result); return result; } diff --git a/src/Neo.VM/Types/ByteString.cs b/src/Neo.VM/Types/ByteString.cs index 1f72621a..02e1519e 100644 --- a/src/Neo.VM/Types/ByteString.cs +++ b/src/Neo.VM/Types/ByteString.cs @@ -1,10 +1,10 @@ // Copyright (C) 2016-2022 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, +// +// The neo-vm is free software distributed under the MIT software license, // see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// project or http://www.opensource.org/licenses/mit-license.php // for more details. -// +// // Redistribution and use in source and binary forms with or without // modifications are permitted. @@ -51,7 +51,7 @@ private bool Equals(ByteString other) public override bool Equals(StackItem? other) { if (ReferenceEquals(this, other)) return true; - if (other is not ByteString b) return false; + if (!(other is ByteString b)) return false; return Equals(b); } @@ -68,7 +68,7 @@ internal bool Equals(StackItem? other, ref uint limits) uint comparedSize = 1; try { - if (other is not ByteString b) return false; + if (!(other is ByteString b)) return false; comparedSize = Math.Max((uint)Math.Max(Size, b.Size), comparedSize); if (ReferenceEquals(this, b)) return true; if (b.Size > limits) @@ -91,7 +91,7 @@ public override int GetHashCode() { if (_hashCode == 0) { - using Murmur32 murmur = new(s_seed); + using Murmur32 murmur = new Murmur32(s_seed); _hashCode = BinaryPrimitives.ReadInt32LittleEndian(murmur.ComputeHash(GetSpan().ToArray())); } return _hashCode; diff --git a/src/Neo.VM/Types/Map.cs b/src/Neo.VM/Types/Map.cs index 5670f41d..363e7809 100644 --- a/src/Neo.VM/Types/Map.cs +++ b/src/Neo.VM/Types/Map.cs @@ -1,10 +1,10 @@ // Copyright (C) 2016-2022 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, +// +// The neo-vm is free software distributed under the MIT software license, // see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// project or http://www.opensource.org/licenses/mit-license.php // for more details. -// +// // Redistribution and use in source and binary forms with or without // modifications are permitted. @@ -27,7 +27,7 @@ public class Map : CompoundType, IReadOnlyDictionary /// public const int MaxKeySize = 64; - private readonly OrderedDictionary dictionary = new(); + private readonly OrderedDictionary dictionary = new OrderedDictionary(); /// /// Gets or sets the element that has the specified key in the map. @@ -116,7 +116,7 @@ public bool ContainsKey(PrimitiveType key) internal override StackItem DeepCopy(Dictionary refMap, bool asImmutable) { if (refMap.TryGetValue(this, out StackItem? mappedItem)) return mappedItem; - Map result = new(ReferenceCounter); + Map result = new Map(ReferenceCounter); refMap.Add(this, result); foreach (var (k, v) in dictionary) result[k] = v.DeepCopy(refMap, asImmutable); @@ -167,7 +167,10 @@ public bool Remove(PrimitiveType key) /// if the map contains an element that has the specified key; /// otherwise, . /// +// supress warning of value parameter nullability mismatch +#pragma warning disable CS8767 public bool TryGetValue(PrimitiveType key, [MaybeNullWhen(false)] out StackItem value) +#pragma warning restore CS8767 { if (key.Size > MaxKeySize) throw new ArgumentException($"MaxKeySize exceed: {key.Size}"); diff --git a/src/Neo.VM/Types/StackItem.cs b/src/Neo.VM/Types/StackItem.cs index b19aeae1..33d3c6eb 100644 --- a/src/Neo.VM/Types/StackItem.cs +++ b/src/Neo.VM/Types/StackItem.cs @@ -33,7 +33,7 @@ public static Boolean True { get { - tls_true ??= new(true); + tls_true ??= new Boolean(true); return tls_true; } } @@ -48,7 +48,7 @@ public static Boolean False { get { - tls_false ??= new(false); + tls_false ??= new Boolean(false); return tls_false; } } @@ -63,7 +63,7 @@ public static StackItem Null { get { - tls_null ??= new(); + tls_null ??= new Null(); return tls_null; } } @@ -100,7 +100,7 @@ internal virtual void Cleanup() /// The copied object. public StackItem DeepCopy(bool asImmutable = false) { - return DeepCopy(new(ReferenceEqualityComparer.Instance), asImmutable); + return DeepCopy(new Dictionary(ReferenceEqualityComparer.Instance), asImmutable); } internal virtual StackItem DeepCopy(Dictionary refMap, bool asImmutable) diff --git a/src/Neo.VM/Types/Struct.cs b/src/Neo.VM/Types/Struct.cs index 3279d2b0..2a8ff875 100644 --- a/src/Neo.VM/Types/Struct.cs +++ b/src/Neo.VM/Types/Struct.cs @@ -1,10 +1,10 @@ // Copyright (C) 2016-2022 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, +// +// The neo-vm is free software distributed under the MIT software license, // see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// project or http://www.opensource.org/licenses/mit-license.php // for more details. -// +// // Redistribution and use in source and binary forms with or without // modifications are permitted. @@ -47,8 +47,8 @@ public Struct(ReferenceCounter? referenceCounter, IEnumerable? fields public Struct Clone(ExecutionEngineLimits limits) { int count = (int)(limits.MaxStackSize - 1); - Struct result = new(ReferenceCounter); - Queue queue = new(); + Struct result = new Struct(ReferenceCounter); + Queue queue = new Queue(); queue.Enqueue(result); queue.Enqueue(this); while (queue.Count > 0) @@ -61,7 +61,7 @@ public Struct Clone(ExecutionEngineLimits limits) if (count < 0) throw new InvalidOperationException("Beyond clone limits!"); if (item is Struct sb) { - Struct sa = new(ReferenceCounter); + Struct sa = new Struct(ReferenceCounter); a.Add(sa); queue.Enqueue(sa); queue.Enqueue(sb); @@ -89,9 +89,9 @@ public override bool Equals(StackItem? other) internal override bool Equals(StackItem? other, ExecutionEngineLimits limits) { - if (other is not Struct s) return false; - Stack stack1 = new(); - Stack stack2 = new(); + if (!(other is Struct s)) return false; + Stack stack1 = new Stack(); + Stack stack2 = new Stack(); stack1.Push(this); stack2.Push(s); uint count = limits.MaxStackSize; @@ -114,7 +114,7 @@ internal override bool Equals(StackItem? other, ExecutionEngineLimits limits) if (a is Struct sa) { if (ReferenceEquals(a, b)) continue; - if (b is not Struct sb) return false; + if (!(b is Struct sb)) return false; if (sa.Count != sb.Count) return false; foreach (StackItem item in sa) stack1.Push(item); diff --git a/src/Neo.VM/Utility.cs b/src/Neo.VM/Utility.cs index f72bc65b..ada3c4ad 100644 --- a/src/Neo.VM/Utility.cs +++ b/src/Neo.VM/Utility.cs @@ -1,15 +1,16 @@ // Copyright (C) 2016-2022 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, +// +// The neo-vm is free software distributed under the MIT software license, // see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// project or http://www.opensource.org/licenses/mit-license.php // for more details. -// +// // Redistribution and use in source and binary forms with or without // modifications are permitted. using System; using System.Numerics; +using System.Runtime.CompilerServices; using System.Text; namespace Neo.VM @@ -58,5 +59,31 @@ public static BigInteger Sqrt(this BigInteger value) return z; } + +#if !NET5_0_OR_GREATER + static int GetBitLength(this BigInteger i) + { + byte[] b = i.ToByteArray(); + return (b.Length - 1) * 8 + BitLen(i.Sign > 0 ? b[b.Length - 1] : 255 - b[b.Length - 1]); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static int BitLen(int w) + { + return (w < 1 << 15 ? (w < 1 << 7 + ? (w < 1 << 3 ? (w < 1 << 1 + ? (w < 1 << 0 ? (w < 0 ? 32 : 0) : 1) + : (w < 1 << 2 ? 2 : 3)) : (w < 1 << 5 + ? (w < 1 << 4 ? 4 : 5) + : (w < 1 << 6 ? 6 : 7))) + : (w < 1 << 11 + ? (w < 1 << 9 ? (w < 1 << 8 ? 8 : 9) : (w < 1 << 10 ? 10 : 11)) + : (w < 1 << 13 ? (w < 1 << 12 ? 12 : 13) : (w < 1 << 14 ? 14 : 15)))) : (w < 1 << 23 ? (w < 1 << 19 + ? (w < 1 << 17 ? (w < 1 << 16 ? 16 : 17) : (w < 1 << 18 ? 18 : 19)) + : (w < 1 << 21 ? (w < 1 << 20 ? 20 : 21) : (w < 1 << 22 ? 22 : 23))) : (w < 1 << 27 + ? (w < 1 << 25 ? (w < 1 << 24 ? 24 : 25) : (w < 1 << 26 ? 26 : 27)) + : (w < 1 << 29 ? (w < 1 << 28 ? 28 : 29) : (w < 1 << 30 ? 30 : 31))))); + } +#endif } } diff --git a/src/Neo.VM/VMUnhandledException.cs b/src/Neo.VM/VMUnhandledException.cs index 797d33dc..47a30fb0 100644 --- a/src/Neo.VM/VMUnhandledException.cs +++ b/src/Neo.VM/VMUnhandledException.cs @@ -37,7 +37,7 @@ public VMUnhandledException(StackItem ex) : base(GetExceptionMessage(ex)) private static string GetExceptionMessage(StackItem e) { - StringBuilder sb = new("An unhandled exception was thrown."); + StringBuilder sb = new StringBuilder("An unhandled exception was thrown."); ByteString? s = e as ByteString; if (s is null && e is Array array && array.Count > 0) s = array[0] as ByteString;