From 116b032d5805a6f4a82ea172f8c22ad181bde1fa Mon Sep 17 00:00:00 2001 From: Shargon Date: Thu, 4 Mar 2021 10:01:42 +0100 Subject: [PATCH 01/11] Added some converts --- src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs | 1 + src/Neo.SmartContract.Framework/Helper.cs | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs b/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs index 0ca0209ea..0fad32426 100644 --- a/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs +++ b/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs @@ -672,6 +672,7 @@ private int ConvertCall(OpCode src, NeoMethod to, List methodTokens { ConvertPushNumber(1, src, to); Convert1by1(VM.OpCode.SUBSTR, null, to); + Insert1(VM.OpCode.CONVERT, "", to, new byte[] { (byte)VM.Types.StackItemType.ByteString }); return 0; } else if (src.tokenMethod == "System.String System.String::Substring(System.Int32)") diff --git a/src/Neo.SmartContract.Framework/Helper.cs b/src/Neo.SmartContract.Framework/Helper.cs index e2a814ce2..b9f83b9d9 100644 --- a/src/Neo.SmartContract.Framework/Helper.cs +++ b/src/Neo.SmartContract.Framework/Helper.cs @@ -162,24 +162,40 @@ public static byte ToByte(this int source) [OpCode(OpCode.CAT)] public extern static byte[] Concat(this byte[] first, ByteString second); + [OpCode(OpCode.CAT)] + [OpCode(OpCode.CONVERT, StackItemType.ByteString)] + public extern static ByteString Concat(this ByteString first, ByteString second); + [NonemitWithConvert(ConvertMethod.HexToBytes)] public extern static byte[] HexToBytes(this string hex, bool reverse = false); [OpCode(OpCode.SUBSTR)] public extern static byte[] Range(this byte[] source, int index, int count); + [OpCode(OpCode.SUBSTR)] + [OpCode(OpCode.CONVERT, StackItemType.ByteString)] + public extern static ByteString Range(this ByteString source, int index, int count); + /// /// Returns byte[] with first 'count' elements from 'source'. Faults if count < 0 /// [OpCode(OpCode.LEFT)] public extern static byte[] Take(this byte[] source, int count); + [OpCode(OpCode.LEFT)] + [OpCode(OpCode.CONVERT, StackItemType.ByteString)] + public extern static ByteString Take(this ByteString source, int count); + /// /// Returns byte[] with last 'count' elements from 'source'. Faults if count < 0 /// [OpCode(OpCode.RIGHT)] public extern static byte[] Last(this byte[] source, int count); + [OpCode(OpCode.RIGHT)] + [OpCode(OpCode.CONVERT, StackItemType.ByteString)] + public extern static ByteString Last(this ByteString source, int count); + /// /// Returns a reversed copy of parameter 'source'. /// Example: [0a,0b,0c,0d,0e] -> [0e,0d,0c,0b,0a] From fda9af455bfdc84d666ec690ca795eaa714fffd2 Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 5 Mar 2021 12:00:29 +0100 Subject: [PATCH 02/11] Erik's review --- src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs | 2 +- src/Neo.SmartContract.Framework/Helper.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs b/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs index 0fad32426..f99e4755b 100644 --- a/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs +++ b/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs @@ -672,7 +672,7 @@ private int ConvertCall(OpCode src, NeoMethod to, List methodTokens { ConvertPushNumber(1, src, to); Convert1by1(VM.OpCode.SUBSTR, null, to); - Insert1(VM.OpCode.CONVERT, "", to, new byte[] { (byte)VM.Types.StackItemType.ByteString }); + Insert1(VM.OpCode.CONVERT, "", to, new byte[] { (byte)VM.Types.StackItemType.Integer }); return 0; } else if (src.tokenMethod == "System.String System.String::Substring(System.Int32)") diff --git a/src/Neo.SmartContract.Framework/Helper.cs b/src/Neo.SmartContract.Framework/Helper.cs index b9f83b9d9..38368196b 100644 --- a/src/Neo.SmartContract.Framework/Helper.cs +++ b/src/Neo.SmartContract.Framework/Helper.cs @@ -164,7 +164,7 @@ public static byte ToByte(this int source) [OpCode(OpCode.CAT)] [OpCode(OpCode.CONVERT, StackItemType.ByteString)] - public extern static ByteString Concat(this ByteString first, ByteString second); + public extern static string Concat(this string first, string second); [NonemitWithConvert(ConvertMethod.HexToBytes)] public extern static byte[] HexToBytes(this string hex, bool reverse = false); From e12d1fdbe8fd779e118ab6ebef33fe1e5118a7b6 Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 5 Mar 2021 12:02:17 +0100 Subject: [PATCH 03/11] Change to String --- src/Neo.SmartContract.Framework/Helper.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Neo.SmartContract.Framework/Helper.cs b/src/Neo.SmartContract.Framework/Helper.cs index 38368196b..aa9fd70f4 100644 --- a/src/Neo.SmartContract.Framework/Helper.cs +++ b/src/Neo.SmartContract.Framework/Helper.cs @@ -174,7 +174,7 @@ public static byte ToByte(this int source) [OpCode(OpCode.SUBSTR)] [OpCode(OpCode.CONVERT, StackItemType.ByteString)] - public extern static ByteString Range(this ByteString source, int index, int count); + public extern static string Range(this string source, int index, int count); /// /// Returns byte[] with first 'count' elements from 'source'. Faults if count < 0 @@ -184,7 +184,7 @@ public static byte ToByte(this int source) [OpCode(OpCode.LEFT)] [OpCode(OpCode.CONVERT, StackItemType.ByteString)] - public extern static ByteString Take(this ByteString source, int count); + public extern static string Take(this string source, int count); /// /// Returns byte[] with last 'count' elements from 'source'. Faults if count < 0 @@ -194,7 +194,7 @@ public static byte ToByte(this int source) [OpCode(OpCode.RIGHT)] [OpCode(OpCode.CONVERT, StackItemType.ByteString)] - public extern static ByteString Last(this ByteString source, int count); + public extern static string Last(this string source, int count); /// /// Returns a reversed copy of parameter 'source'. From 61729002fb6316af309ed8fc97d4a18dd07769a5 Mon Sep 17 00:00:00 2001 From: Shargon Date: Mon, 8 Mar 2021 09:19:41 +0100 Subject: [PATCH 04/11] Remove concat --- src/Neo.SmartContract.Framework/Helper.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Neo.SmartContract.Framework/Helper.cs b/src/Neo.SmartContract.Framework/Helper.cs index aa9fd70f4..cb7b6fb96 100644 --- a/src/Neo.SmartContract.Framework/Helper.cs +++ b/src/Neo.SmartContract.Framework/Helper.cs @@ -162,10 +162,6 @@ public static byte ToByte(this int source) [OpCode(OpCode.CAT)] public extern static byte[] Concat(this byte[] first, ByteString second); - [OpCode(OpCode.CAT)] - [OpCode(OpCode.CONVERT, StackItemType.ByteString)] - public extern static string Concat(this string first, string second); - [NonemitWithConvert(ConvertMethod.HexToBytes)] public extern static byte[] HexToBytes(this string hex, bool reverse = false); From fe7b16b633c399c1a8b9f520c03c9a5b0e18f514 Mon Sep 17 00:00:00 2001 From: Shargon Date: Mon, 8 Mar 2021 09:56:36 +0100 Subject: [PATCH 05/11] Erik's feedback & UT --- src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs | 4 +-- src/Neo.SmartContract.Framework/Helper.cs | 4 +++ .../TestClasses/Contract_Types_String.cs | 16 +++++++++ .../UnitTest_Types.cs | 34 +++++++++++++++++++ 4 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_Types_String.cs diff --git a/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs b/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs index f99e4755b..ca4afa5b5 100644 --- a/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs +++ b/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs @@ -670,9 +670,7 @@ private int ConvertCall(OpCode src, NeoMethod to, List methodTokens } else if (src.tokenMethod == "System.Char System.String::get_Chars(System.Int32)") { - ConvertPushNumber(1, src, to); - Convert1by1(VM.OpCode.SUBSTR, null, to); - Insert1(VM.OpCode.CONVERT, "", to, new byte[] { (byte)VM.Types.StackItemType.Integer }); + Convert1by1(VM.OpCode.PICKITEM, src, to); return 0; } else if (src.tokenMethod == "System.String System.String::Substring(System.Int32)") diff --git a/src/Neo.SmartContract.Framework/Helper.cs b/src/Neo.SmartContract.Framework/Helper.cs index cb7b6fb96..d88426b41 100644 --- a/src/Neo.SmartContract.Framework/Helper.cs +++ b/src/Neo.SmartContract.Framework/Helper.cs @@ -168,6 +168,8 @@ public static byte ToByte(this int source) [OpCode(OpCode.SUBSTR)] public extern static byte[] Range(this byte[] source, int index, int count); + [OpCode(OpCode.SWAP)] + [OpCode(OpCode.ROT)] [OpCode(OpCode.SUBSTR)] [OpCode(OpCode.CONVERT, StackItemType.ByteString)] public extern static string Range(this string source, int index, int count); @@ -178,6 +180,7 @@ public static byte ToByte(this int source) [OpCode(OpCode.LEFT)] public extern static byte[] Take(this byte[] source, int count); + [OpCode(OpCode.SWAP)] [OpCode(OpCode.LEFT)] [OpCode(OpCode.CONVERT, StackItemType.ByteString)] public extern static string Take(this string source, int count); @@ -188,6 +191,7 @@ public static byte ToByte(this int source) [OpCode(OpCode.RIGHT)] public extern static byte[] Last(this byte[] source, int count); + [OpCode(OpCode.SWAP)] [OpCode(OpCode.RIGHT)] [OpCode(OpCode.CONVERT, StackItemType.ByteString)] public extern static string Last(this string source, int count); diff --git a/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_Types_String.cs b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_Types_String.cs new file mode 100644 index 000000000..25fe8220b --- /dev/null +++ b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_Types_String.cs @@ -0,0 +1,16 @@ +using System; +using System.Text; +using System.Numerics; +using System.Runtime.CompilerServices; +using Neo.SmartContract.Framework; + +namespace Neo.Compiler.MSIL.UnitTests.TestClasses +{ + class Contract_Types_String : SmartContract.Framework.SmartContract + { + public static char checkIndex(string cad, int pos) { return cad[pos]; } + public static string checkRange(string cad, int pos, int count) { return cad.Range(pos, count); } + public static string checkTake(string cad, int count) { return cad.Take(count); } + public static string checkLast(string cad, int count) { return cad.Last(count); } + } +} diff --git a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Types.cs b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Types.cs index 46acf1e02..f438cc797 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Types.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Types.cs @@ -521,5 +521,39 @@ public void UInt160_byte_array_construct() var received = new UInt160(((ByteString)item).GetSpan()); Assert.AreEqual(received, notZero); } + + [TestMethod] + public void String_Methods() + { + using var testengine = new TestEngine(); + testengine.AddEntryScript("./TestClasses/Contract_Types_String.cs"); + + var result = testengine.ExecuteTestCaseStandard("checkIndex", "hello", 4); + Assert.AreEqual(1, result.Count); + var item = result.Pop(); + Assert.IsTrue(item is Integer); + Assert.AreEqual((byte)'o', item.GetInteger()); + + testengine.Reset(); + result = testengine.ExecuteTestCaseStandard("checkTake", "hello", 4); + Assert.AreEqual(1, result.Count); + item = result.Pop(); + Assert.IsTrue(item is ByteString); + Assert.AreEqual("hell", item.GetString()); + + testengine.Reset(); + result = testengine.ExecuteTestCaseStandard("checkLast", "hello", 2); + Assert.AreEqual(1, result.Count); + item = result.Pop(); + Assert.IsTrue(item is ByteString); + Assert.AreEqual("lo", item.GetString()); + + testengine.Reset(); + result = testengine.ExecuteTestCaseStandard("checkRange", "hello", 1, 2); + Assert.AreEqual(1, result.Count); + item = result.Pop(); + Assert.IsTrue(item is ByteString); + Assert.AreEqual("el", item.GetString()); + } } } From 0130d6500bf317377c63a037a3cb660b6d66cd2f Mon Sep 17 00:00:00 2001 From: Shargon Date: Mon, 8 Mar 2021 09:58:10 +0100 Subject: [PATCH 06/11] Use Substring for range --- src/Neo.SmartContract.Framework/Helper.cs | 6 ------ .../TestClasses/Contract_Types_String.cs | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/Neo.SmartContract.Framework/Helper.cs b/src/Neo.SmartContract.Framework/Helper.cs index d88426b41..2de351970 100644 --- a/src/Neo.SmartContract.Framework/Helper.cs +++ b/src/Neo.SmartContract.Framework/Helper.cs @@ -168,12 +168,6 @@ public static byte ToByte(this int source) [OpCode(OpCode.SUBSTR)] public extern static byte[] Range(this byte[] source, int index, int count); - [OpCode(OpCode.SWAP)] - [OpCode(OpCode.ROT)] - [OpCode(OpCode.SUBSTR)] - [OpCode(OpCode.CONVERT, StackItemType.ByteString)] - public extern static string Range(this string source, int index, int count); - /// /// Returns byte[] with first 'count' elements from 'source'. Faults if count < 0 /// diff --git a/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_Types_String.cs b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_Types_String.cs index 25fe8220b..be9a5d24a 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_Types_String.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/TestClasses/Contract_Types_String.cs @@ -9,7 +9,7 @@ namespace Neo.Compiler.MSIL.UnitTests.TestClasses class Contract_Types_String : SmartContract.Framework.SmartContract { public static char checkIndex(string cad, int pos) { return cad[pos]; } - public static string checkRange(string cad, int pos, int count) { return cad.Range(pos, count); } + public static string checkRange(string cad, int pos, int count) { return cad.Substring(pos, count); } public static string checkTake(string cad, int count) { return cad.Take(count); } public static string checkLast(string cad, int count) { return cad.Last(count); } } From 7d3d09ea24e06312de785169a433bebfe390d866 Mon Sep 17 00:00:00 2001 From: Shargon Date: Mon, 8 Mar 2021 18:37:13 +0100 Subject: [PATCH 07/11] Remove SWAP --- src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs | 24 +++++++++++++------ src/Neo.Compiler.MSIL/MSIL/Converter.cs | 2 +- .../CallingConversionAttribute.cs | 16 +++++++++++++ src/Neo.SmartContract.Framework/Helper.cs | 5 ++-- 4 files changed, 37 insertions(+), 10 deletions(-) create mode 100644 src/Neo.SmartContract.Framework/CallingConversionAttribute.cs diff --git a/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs b/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs index ca4afa5b5..3ee29a199 100644 --- a/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs +++ b/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Linq; +using System.Runtime.InteropServices; using System.Text.RegularExpressions; namespace Neo.Compiler.MSIL @@ -240,7 +241,7 @@ public bool IsNonCall(Mono.Cecil.MethodDefinition defs) return false; } - public bool IsMixAttribute(Mono.Cecil.MethodDefinition defs, out VM.OpCode[] opcodes, out string[] opdata) + public bool IsMixAttribute(MethodDefinition defs, out VM.OpCode[] opcodes, out string[] opdata, out CallingConvention callingConvention) { // ============================================ // Integrates attributes: OpCode/Syscall/Script @@ -248,6 +249,7 @@ public bool IsMixAttribute(Mono.Cecil.MethodDefinition defs, out VM.OpCode[] opc opcodes = null; opdata = null; + callingConvention = CallingConvention.ThisCall; if (defs == null) return false; @@ -263,6 +265,7 @@ public bool IsMixAttribute(Mono.Cecil.MethodDefinition defs, out VM.OpCode[] opc if (count_attrs == 0) return false; // no OpCode/Syscall/Script Attribute + bool callingConventionSet = false; opcodes = new VM.OpCode[count_attrs]; opdata = new string[count_attrs]; @@ -298,6 +301,12 @@ public bool IsMixAttribute(Mono.Cecil.MethodDefinition defs, out VM.OpCode[] opc i++; } + else if (attr.AttributeType.FullName == "Neo.SmartContract.Framework.CallingConversionAttribute") + { + callingConvention = Enum.Parse(attr.ConstructorArguments[0].Value.ToString()); + callingConventionSet = true; + ext++; + } if (attr.AttributeType.FullName == "System.Runtime.CompilerServices.ExtensionAttribute") ext++; @@ -306,6 +315,11 @@ public bool IsMixAttribute(Mono.Cecil.MethodDefinition defs, out VM.OpCode[] opc if ((count_attrs + ext) == defs.CustomAttributes.Count) { // all attributes are OpCode or Syscall or Script (plus ExtensionAttribute which is automatic) + + if (!callingConventionSet && count_attrs == 1 && opcodes[0] != VM.OpCode.SYSCALL) + { + callingConvention = CallingConvention.Cdecl; + } return true; } else @@ -417,16 +431,12 @@ private int ConvertCall(OpCode src, NeoMethod to, List methodTokens //{ // calltype = 3; //} - else if (IsMixAttribute(defs, out callcodes, out calldata)) + else if (IsMixAttribute(defs, out callcodes, out calldata, out var callingConvention)) { //only syscall, need to reverse arguments //only opcall, no matter what arguments - calltype = 7; - if (callcodes.Length == 1 && callcodes[0] != VM.OpCode.SYSCALL) - { - calltype = 2; - } + calltype = callingConvention == CallingConvention.ThisCall ? 7 : 2; } else if (IsContractCall(defs, out callhash)) { diff --git a/src/Neo.Compiler.MSIL/MSIL/Converter.cs b/src/Neo.Compiler.MSIL/MSIL/Converter.cs index 81f90b496..2adf82e74 100644 --- a/src/Neo.Compiler.MSIL/MSIL/Converter.cs +++ b/src/Neo.Compiler.MSIL/MSIL/Converter.cs @@ -116,7 +116,7 @@ public NeoModule Convert(ILModule _in, ConvOption option = null) continue; if (IsNonCall(m.Value.method)) continue; - if (IsMixAttribute(m.Value.method, out _, out _)) + if (IsMixAttribute(m.Value.method, out _, out _, out _)) continue; if (m.Key.Contains("::Main(")) diff --git a/src/Neo.SmartContract.Framework/CallingConversionAttribute.cs b/src/Neo.SmartContract.Framework/CallingConversionAttribute.cs new file mode 100644 index 000000000..d7358cd1a --- /dev/null +++ b/src/Neo.SmartContract.Framework/CallingConversionAttribute.cs @@ -0,0 +1,16 @@ +using System; +using System.Runtime.InteropServices; + +namespace Neo.SmartContract.Framework +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] + public class CallingConversionAttribute : Attribute + { + public CallingConvention CallingConversion { get; private set; } + + public CallingConversionAttribute(CallingConvention callingConvention) + { + CallingConversion = callingConvention; + } + } +} diff --git a/src/Neo.SmartContract.Framework/Helper.cs b/src/Neo.SmartContract.Framework/Helper.cs index 2de351970..d545683c4 100644 --- a/src/Neo.SmartContract.Framework/Helper.cs +++ b/src/Neo.SmartContract.Framework/Helper.cs @@ -1,5 +1,6 @@ using System; using System.Numerics; +using System.Runtime.InteropServices; namespace Neo.SmartContract.Framework { @@ -174,7 +175,7 @@ public static byte ToByte(this int source) [OpCode(OpCode.LEFT)] public extern static byte[] Take(this byte[] source, int count); - [OpCode(OpCode.SWAP)] + [CallingConversion(CallingConvention.Cdecl)] [OpCode(OpCode.LEFT)] [OpCode(OpCode.CONVERT, StackItemType.ByteString)] public extern static string Take(this string source, int count); @@ -185,7 +186,7 @@ public static byte ToByte(this int source) [OpCode(OpCode.RIGHT)] public extern static byte[] Last(this byte[] source, int count); - [OpCode(OpCode.SWAP)] + [CallingConversion(CallingConvention.Cdecl)] [OpCode(OpCode.RIGHT)] [OpCode(OpCode.CONVERT, StackItemType.ByteString)] public extern static string Last(this string source, int count); From a6f8f8f8440ed09e0a3a061cf2bcf94490c1ecf0 Mon Sep 17 00:00:00 2001 From: Shargon Date: Mon, 8 Mar 2021 18:43:48 +0100 Subject: [PATCH 08/11] Change UT --- tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Types.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Types.cs b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Types.cs index f438cc797..bb74969fc 100644 --- a/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Types.cs +++ b/tests/Neo.Compiler.MSIL.UnitTests/UnitTest_Types.cs @@ -531,28 +531,28 @@ public void String_Methods() var result = testengine.ExecuteTestCaseStandard("checkIndex", "hello", 4); Assert.AreEqual(1, result.Count); var item = result.Pop(); - Assert.IsTrue(item is Integer); + Assert.IsInstanceOfType(item, typeof(Integer)); Assert.AreEqual((byte)'o', item.GetInteger()); testengine.Reset(); result = testengine.ExecuteTestCaseStandard("checkTake", "hello", 4); Assert.AreEqual(1, result.Count); item = result.Pop(); - Assert.IsTrue(item is ByteString); + Assert.IsInstanceOfType(item, typeof(ByteString)); Assert.AreEqual("hell", item.GetString()); testengine.Reset(); result = testengine.ExecuteTestCaseStandard("checkLast", "hello", 2); Assert.AreEqual(1, result.Count); item = result.Pop(); - Assert.IsTrue(item is ByteString); + Assert.IsInstanceOfType(item, typeof(ByteString)); Assert.AreEqual("lo", item.GetString()); testengine.Reset(); result = testengine.ExecuteTestCaseStandard("checkRange", "hello", 1, 2); Assert.AreEqual(1, result.Count); item = result.Pop(); - Assert.IsTrue(item is ByteString); + Assert.IsInstanceOfType(item, typeof(ByteString)); Assert.AreEqual("el", item.GetString()); } } From 02562005216e1b24792c55c534327fd26181214c Mon Sep 17 00:00:00 2001 From: Shargon Date: Mon, 8 Mar 2021 18:56:23 +0100 Subject: [PATCH 09/11] Always use 7 --- src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs | 95 ++++++++++-------------- 1 file changed, 38 insertions(+), 57 deletions(-) diff --git a/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs b/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs index 3ee29a199..d5650e624 100644 --- a/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs +++ b/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs @@ -382,6 +382,7 @@ private int ConvertCall(OpCode src, NeoMethod to, List methodTokens UInt160 callhash = null; VM.OpCode[] callcodes = null; string[] calldata = null; + CallingConvention callingConvention = CallingConvention.ThisCall; Mono.Cecil.MethodDefinition defs = null; Exception defError = null; @@ -431,12 +432,12 @@ private int ConvertCall(OpCode src, NeoMethod to, List methodTokens //{ // calltype = 3; //} - else if (IsMixAttribute(defs, out callcodes, out calldata, out var callingConvention)) + else if (IsMixAttribute(defs, out callcodes, out calldata, out callingConvention)) { //only syscall, need to reverse arguments //only opcall, no matter what arguments - calltype = callingConvention == CallingConvention.ThisCall ? 7 : 2; + calltype = 7; } else if (IsContractCall(defs, out callhash)) { @@ -798,41 +799,45 @@ private int ConvertCall(OpCode src, NeoMethod to, List methodTokens } else { - // reverse the arguments order + if (callingConvention == CallingConvention.ThisCall) + { + // reverse the arguments order - //this become very diffcult + //this become very diffcult - // because opcode donot need to flip params - // but syscall need - // calltype7 is opcode? or is syscall? + // because opcode donot need to flip params + // but syscall need + // calltype7 is opcode? or is syscall? - // i will make calltype7 =calltype3 , you can add flip opcode if you need. - if (havethis && calltype == 7) // is syscall - pcount++; - //if ((calltype == 3) || ((calltype == 7) && (callcodes[0] == VM.OpCode.SYSCALL))) - // pcount++; - // calltype == 3 does not exist anymore + // i will make calltype7 =calltype3 , you can add flip opcode if you need. + if (havethis && calltype == 7) // is syscall + pcount++; + //if ((calltype == 3) || ((calltype == 7) && (callcodes[0] == VM.OpCode.SYSCALL))) + // pcount++; + // calltype == 3 does not exist anymore - Convert1by1(VM.OpCode.NOP, src, to); - if (pcount <= 1) - { - } - else if (pcount == 2) - { - Insert1(VM.OpCode.SWAP, "swap 2 param", to); - } - else if (pcount == 3) - { - Insert1(VM.OpCode.REVERSE3, "", to); - } - else if (pcount == 4) - { - Insert1(VM.OpCode.REVERSE4, "", to); - } - else - { - InsertPush(pcount, "swap" + pcount, to); - Insert1(VM.OpCode.REVERSEN, "", to); + + Convert1by1(VM.OpCode.NOP, src, to); + if (pcount <= 1) + { + } + else if (pcount == 2) + { + Insert1(VM.OpCode.SWAP, "swap 2 param", to); + } + else if (pcount == 3) + { + Insert1(VM.OpCode.REVERSE3, "", to); + } + else if (pcount == 4) + { + Insert1(VM.OpCode.REVERSE4, "", to); + } + else + { + InsertPush(pcount, "swap" + pcount, to); + Insert1(VM.OpCode.REVERSEN, "", to); + } } } if (calltype == 1) @@ -846,29 +851,6 @@ private int ConvertCall(OpCode src, NeoMethod to, List methodTokens { Convert1by1(callcodes[0], src, to, Helper.OpDataToBytes(calldata[0])); } - - /* - else if (calltype == 3) - { - byte[] bytes = null; - if (this.outModule.option.useSysCallInteropHash) - { - //now neovm use ineropMethod hash for syscall. - bytes = BitConverter.GetBytes(callname.ToInteropMethodHash()); - } - else - { - bytes = System.Text.Utility.StrictUTF8.GetBytes(callname); - if (bytes.Length > 252) throw new Exception("string is to long"); - } - byte[] outbytes = new byte[bytes.Length + 1]; - outbytes[0] = (byte)bytes.Length; - Array.Copy(bytes, 0, outbytes, 1, bytes.Length); - //bytes.Prepend 函数在 dotnet framework 4.6 编译不过 - _Convert1by1(VM.OpCode.SYSCALL, null, to, outbytes); - return 0; - } - */ else if (calltype == 7) { for (var j = 0; j < callcodes.Length; j++) @@ -881,7 +863,6 @@ private int ConvertCall(OpCode src, NeoMethod to, List methodTokens else { byte[] opdata = Helper.OpDataToBytes(calldata[j]); - Convert1by1(callcodes[j], src, to, opdata); } } From 5930b8209ebe1895eaf2a10999748618bddeae70 Mon Sep 17 00:00:00 2001 From: Shargon Date: Tue, 9 Mar 2021 08:57:24 +0100 Subject: [PATCH 10/11] Rename --- src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs | 23 +++++++++---------- .../CallingConversionAttribute.cs | 16 ------------- src/Neo.SmartContract.Framework/Helper.cs | 4 ++-- .../RightToLeftAttribute.cs | 15 ++++++++++++ 4 files changed, 28 insertions(+), 30 deletions(-) delete mode 100644 src/Neo.SmartContract.Framework/CallingConversionAttribute.cs create mode 100644 src/Neo.SmartContract.Framework/RightToLeftAttribute.cs diff --git a/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs b/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs index d5650e624..43a97e4cf 100644 --- a/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs +++ b/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs @@ -241,7 +241,7 @@ public bool IsNonCall(Mono.Cecil.MethodDefinition defs) return false; } - public bool IsMixAttribute(MethodDefinition defs, out VM.OpCode[] opcodes, out string[] opdata, out CallingConvention callingConvention) + public bool IsMixAttribute(MethodDefinition defs, out VM.OpCode[] opcodes, out string[] opdata, out bool rightToLeft) { // ============================================ // Integrates attributes: OpCode/Syscall/Script @@ -249,7 +249,7 @@ public bool IsMixAttribute(MethodDefinition defs, out VM.OpCode[] opcodes, out s opcodes = null; opdata = null; - callingConvention = CallingConvention.ThisCall; + rightToLeft = true; if (defs == null) return false; @@ -265,7 +265,7 @@ public bool IsMixAttribute(MethodDefinition defs, out VM.OpCode[] opcodes, out s if (count_attrs == 0) return false; // no OpCode/Syscall/Script Attribute - bool callingConventionSet = false; + bool rightToLeftSet = false; opcodes = new VM.OpCode[count_attrs]; opdata = new string[count_attrs]; @@ -301,10 +301,10 @@ public bool IsMixAttribute(MethodDefinition defs, out VM.OpCode[] opcodes, out s i++; } - else if (attr.AttributeType.FullName == "Neo.SmartContract.Framework.CallingConversionAttribute") + else if (attr.AttributeType.FullName == "Neo.SmartContract.Framework.RightToLeftAttribute") { - callingConvention = Enum.Parse(attr.ConstructorArguments[0].Value.ToString()); - callingConventionSet = true; + rightToLeft = (bool)attr.ConstructorArguments[0].Value; + rightToLeftSet = true; ext++; } @@ -316,9 +316,9 @@ public bool IsMixAttribute(MethodDefinition defs, out VM.OpCode[] opcodes, out s { // all attributes are OpCode or Syscall or Script (plus ExtensionAttribute which is automatic) - if (!callingConventionSet && count_attrs == 1 && opcodes[0] != VM.OpCode.SYSCALL) + if (!rightToLeftSet && count_attrs == 1 && opcodes[0] != VM.OpCode.SYSCALL) { - callingConvention = CallingConvention.Cdecl; + rightToLeft = false; } return true; } @@ -382,7 +382,7 @@ private int ConvertCall(OpCode src, NeoMethod to, List methodTokens UInt160 callhash = null; VM.OpCode[] callcodes = null; string[] calldata = null; - CallingConvention callingConvention = CallingConvention.ThisCall; + bool rightToLeft = true; Mono.Cecil.MethodDefinition defs = null; Exception defError = null; @@ -432,7 +432,7 @@ private int ConvertCall(OpCode src, NeoMethod to, List methodTokens //{ // calltype = 3; //} - else if (IsMixAttribute(defs, out callcodes, out calldata, out callingConvention)) + else if (IsMixAttribute(defs, out callcodes, out calldata, out rightToLeft)) { //only syscall, need to reverse arguments //only opcall, no matter what arguments @@ -799,7 +799,7 @@ private int ConvertCall(OpCode src, NeoMethod to, List methodTokens } else { - if (callingConvention == CallingConvention.ThisCall) + if (rightToLeft) { // reverse the arguments order @@ -816,7 +816,6 @@ private int ConvertCall(OpCode src, NeoMethod to, List methodTokens // pcount++; // calltype == 3 does not exist anymore - Convert1by1(VM.OpCode.NOP, src, to); if (pcount <= 1) { diff --git a/src/Neo.SmartContract.Framework/CallingConversionAttribute.cs b/src/Neo.SmartContract.Framework/CallingConversionAttribute.cs deleted file mode 100644 index d7358cd1a..000000000 --- a/src/Neo.SmartContract.Framework/CallingConversionAttribute.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace Neo.SmartContract.Framework -{ - [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] - public class CallingConversionAttribute : Attribute - { - public CallingConvention CallingConversion { get; private set; } - - public CallingConversionAttribute(CallingConvention callingConvention) - { - CallingConversion = callingConvention; - } - } -} diff --git a/src/Neo.SmartContract.Framework/Helper.cs b/src/Neo.SmartContract.Framework/Helper.cs index d545683c4..cc3a3f316 100644 --- a/src/Neo.SmartContract.Framework/Helper.cs +++ b/src/Neo.SmartContract.Framework/Helper.cs @@ -175,7 +175,7 @@ public static byte ToByte(this int source) [OpCode(OpCode.LEFT)] public extern static byte[] Take(this byte[] source, int count); - [CallingConversion(CallingConvention.Cdecl)] + [RightToLeft(false)] [OpCode(OpCode.LEFT)] [OpCode(OpCode.CONVERT, StackItemType.ByteString)] public extern static string Take(this string source, int count); @@ -186,7 +186,7 @@ public static byte ToByte(this int source) [OpCode(OpCode.RIGHT)] public extern static byte[] Last(this byte[] source, int count); - [CallingConversion(CallingConvention.Cdecl)] + [RightToLeft(false)] [OpCode(OpCode.RIGHT)] [OpCode(OpCode.CONVERT, StackItemType.ByteString)] public extern static string Last(this string source, int count); diff --git a/src/Neo.SmartContract.Framework/RightToLeftAttribute.cs b/src/Neo.SmartContract.Framework/RightToLeftAttribute.cs new file mode 100644 index 000000000..3f0aac6b8 --- /dev/null +++ b/src/Neo.SmartContract.Framework/RightToLeftAttribute.cs @@ -0,0 +1,15 @@ +using System; + +namespace Neo.SmartContract.Framework +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] + public class RightToLeftAttribute : Attribute + { + public bool RightToLeft { get; private set; } + + public RightToLeftAttribute(bool rightToLeft) + { + RightToLeft = rightToLeft; + } + } +} From 7a23fda1cfd3a51ed4ac35dc17a08cb3f8f87fb0 Mon Sep 17 00:00:00 2001 From: Shargon Date: Tue, 9 Mar 2021 08:59:12 +0100 Subject: [PATCH 11/11] Remove empty if --- src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs b/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs index 43a97e4cf..f1b3921e5 100644 --- a/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs +++ b/src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs @@ -817,10 +817,7 @@ private int ConvertCall(OpCode src, NeoMethod to, List methodTokens // calltype == 3 does not exist anymore Convert1by1(VM.OpCode.NOP, src, to); - if (pcount <= 1) - { - } - else if (pcount == 2) + if (pcount == 2) { Insert1(VM.OpCode.SWAP, "swap 2 param", to); } @@ -832,7 +829,7 @@ private int ConvertCall(OpCode src, NeoMethod to, List methodTokens { Insert1(VM.OpCode.REVERSE4, "", to); } - else + else if (pcount > 4) { InsertPush(pcount, "swap" + pcount, to); Insert1(VM.OpCode.REVERSEN, "", to);