From 8971d080270767e19c4fe5a8842ec27caae27e8e Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sun, 29 Dec 2024 22:03:47 +0800 Subject: [PATCH] fix inline for null body method (#1211) * fix inline for null body method * fix return value issue for arrowexpression with return value. --- .../MethodConvert/Helpers/ConvertHelpers.cs | 23 +++++++++- .../Contract_Inline.cs | 23 ++++++++++ .../TestingArtifacts/Contract_Inline.cs | 45 ++++++++++++++++++- .../UnitTest_Inline.cs | 12 +++++ 4 files changed, 100 insertions(+), 3 deletions(-) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Helpers/ConvertHelpers.cs b/src/Neo.Compiler.CSharp/MethodConvert/Helpers/ConvertHelpers.cs index d6e5ab345..9baefb566 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Helpers/ConvertHelpers.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Helpers/ConvertHelpers.cs @@ -42,8 +42,29 @@ private bool TryProcessInlineMethods(SemanticModel model, IMethodSymbol symbol, using (InsertSequencePoint(syntax)) { if (arguments is not null) PrepareArgumentsForMethod(model, symbol, arguments); - if (syntax.Body != null) ConvertStatement(model, syntax.Body); + if (syntax.Body != null) + { + ConvertStatement(model, syntax.Body); + } + else if (syntax.ExpressionBody != null) + { + ConvertExpression(model, syntax.ExpressionBody.Expression); + } } + + // If the method has no return value, + // but the expression body has a return value, example: a+=1; + // drop the return value + // Problem: + // [MethodImpl(MethodImplOptions.AggressiveInlining)] + // public void Test() => a+=1; // this will push an int value to the stack + // [MethodImpl(MethodImplOptions.AggressiveInlining)] + // public void Test() { a+=1; } // this will not push value to the stack + if (syntax is MethodDeclarationSyntax methodSyntax + && methodSyntax.ReturnType.ToString() == "void" + && IsExpressionReturningValue(model, methodSyntax)) + AddInstruction(OpCode.DROP); + return true; } diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Inline.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Inline.cs index 84c316978..66ffb529a 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Inline.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Inline.cs @@ -69,5 +69,28 @@ private static int inline_C() { return 3; } + + public static int ArrowMethod() + { + return ArrowInline(1, 2); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int ArrowInline(int a, int b) => a + b; + + + public static void ArrowMethodNoRerurn() + { + ArrowInlineNoReturn(1, 1); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void ArrowInlineNoReturn(int a, int b) => CallMethodThatReturnsInt(a, b); + + + private static int CallMethodThatReturnsInt(int a, int b) + { + return a + b; + } } } diff --git a/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Inline.cs b/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Inline.cs index 22d6ff235..decd09f33 100644 --- a/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Inline.cs +++ b/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Inline.cs @@ -10,17 +10,58 @@ public abstract class Contract_Inline(Neo.SmartContract.Testing.SmartContractIni { #region Compiled data - public static Neo.SmartContract.Manifest.ContractManifest Manifest => Neo.SmartContract.Manifest.ContractManifest.Parse(@"{""name"":""Contract_Inline"",""groups"":[],""features"":{},""supportedstandards"":[],""abi"":{""methods"":[{""name"":""testInline"",""parameters"":[{""name"":""method"",""type"":""String""}],""returntype"":""Integer"",""offset"":0,""safe"":false}],""events"":[]},""permissions"":[],""trusts"":[],""extra"":{""nef"":{""optimization"":""All""}}}"); + public static Neo.SmartContract.Manifest.ContractManifest Manifest => Neo.SmartContract.Manifest.ContractManifest.Parse(@"{""name"":""Contract_Inline"",""groups"":[],""features"":{},""supportedstandards"":[],""abi"":{""methods"":[{""name"":""testInline"",""parameters"":[{""name"":""method"",""type"":""String""}],""returntype"":""Integer"",""offset"":0,""safe"":false},{""name"":""arrowMethod"",""parameters"":[],""returntype"":""Integer"",""offset"":331,""safe"":false},{""name"":""arrowMethodNoRerurn"",""parameters"":[],""returntype"":""Void"",""offset"":381,""safe"":false}],""events"":[]},""permissions"":[],""trusts"":[],""extra"":{""nef"":{""optimization"":""All""}}}"); /// /// Optimization: "All" /// - public static Neo.SmartContract.NefFile Nef => Neo.IO.Helper.AsSerializable(Convert.FromBase64String(@"TkVGM1Rlc3RpbmdFbmdpbmUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP1LAVcBAXhwaAwGaW5saW5llyYEEUBoDBppbmxpbmVfd2l0aF9vbmVfcGFyYW1ldGVyc5cmBBNAaAwcaW5saW5lX3dpdGhfbXVsdGlfcGFyYW1ldGVyc5cmNBMSnkoCAAAAgC4EIgpKAv///38yHgP/////AAAAAJFKAv///38yDAMAAAAAAQAAAJ9AaAwKbm90X2lubGluZZcmBTR0QGgMHm5vdF9pbmxpbmVfd2l0aF9vbmVfcGFyYW1ldGVyc5cmBhM0TkBoDCBub3RfaW5saW5lX3dpdGhfbXVsdGlfcGFyYW1ldGVyc5cmBxMSNChAaAwNaW5saW5lX25lc3RlZJcmBTRHQAgmBQBjQGg6EUBXAAF4QFcAAnh5nkoCAAAAgC4EIgpKAv///38yHgP/////AAAAAJFKAv///38yDAMAAAAAAQAAAJ9AE0Cui6ZE")); + public static Neo.SmartContract.NefFile Nef => Neo.IO.Helper.AsSerializable(Convert.FromBase64String(@"TkVGM1Rlc3RpbmdFbmdpbmUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP24AVcBAXhwaAwGaW5saW5llyYEEUBoDBppbmxpbmVfd2l0aF9vbmVfcGFyYW1ldGVyc5cmBBNAaAwcaW5saW5lX3dpdGhfbXVsdGlfcGFyYW1ldGVyc5cmNBMSnkoCAAAAgC4EIgpKAv///38yHgP/////AAAAAJFKAv///38yDAMAAAAAAQAAAJ9AaAwKbm90X2lubGluZZcmBTR0QGgMHm5vdF9pbmxpbmVfd2l0aF9vbmVfcGFyYW1ldGVyc5cmBhM0TkBoDCBub3RfaW5saW5lX3dpdGhfbXVsdGlfcGFyYW1ldGVyc5cmBxMSNChAaAwNaW5saW5lX25lc3RlZJcmBTRHQAgmBQBjQGg6EUBXAAF4QFcAAnh5nkoCAAAAgC4EIgpKAv///38yHgP/////AAAAAJFKAv///38yDAMAAAAAAQAAAJ9AE0ASEZ5KAgAAAIAuBCIKSgL///9/Mh4D/////wAAAACRSgL///9/MgwDAAAAAAEAAACfQBERNARFQFcAAnh5nkoCAAAAgC4EIgpKAv///38yHgP/////AAAAAJFKAv///38yDAMAAAAAAQAAAJ9Arb2CVw==")); #endregion #region Unsafe methods + /// + /// Unsafe method + /// + /// + /// Script: EhGeSgIAAACALgQiCkoC////fzIeA/////8AAAAAkUoC////fzIMAwAAAAABAAAAn0A= + /// PUSH2 [1 datoshi] + /// PUSH1 [1 datoshi] + /// ADD [8 datoshi] + /// DUP [2 datoshi] + /// PUSHINT32 00000080 [1 datoshi] + /// JMPGE 04 [2 datoshi] + /// JMP 0A [2 datoshi] + /// DUP [2 datoshi] + /// PUSHINT32 FFFFFF7F [1 datoshi] + /// JMPLE 1E [2 datoshi] + /// PUSHINT64 FFFFFFFF00000000 [1 datoshi] + /// AND [8 datoshi] + /// DUP [2 datoshi] + /// PUSHINT32 FFFFFF7F [1 datoshi] + /// JMPLE 0C [2 datoshi] + /// PUSHINT64 0000000001000000 [1 datoshi] + /// SUB [8 datoshi] + /// RET [0 datoshi] + /// + [DisplayName("arrowMethod")] + public abstract BigInteger? ArrowMethod(); + + /// + /// Unsafe method + /// + /// + /// Script: ERE0BEVA + /// PUSH1 [1 datoshi] + /// PUSH1 [1 datoshi] + /// CALL 04 [512 datoshi] + /// DROP [2 datoshi] + /// RET [0 datoshi] + /// + [DisplayName("arrowMethodNoRerurn")] + public abstract void ArrowMethodNoRerurn(); + /// /// Unsafe method /// diff --git a/tests/Neo.Compiler.CSharp.UnitTests/UnitTest_Inline.cs b/tests/Neo.Compiler.CSharp.UnitTests/UnitTest_Inline.cs index 4bb434ea1..e2f591a50 100644 --- a/tests/Neo.Compiler.CSharp.UnitTests/UnitTest_Inline.cs +++ b/tests/Neo.Compiler.CSharp.UnitTests/UnitTest_Inline.cs @@ -35,5 +35,17 @@ public void Test_NestedInline() Assert.AreEqual(new BigInteger(3), Contract.TestInline("inline_nested")); AssertGasConsumed(1071930); } + + [TestMethod] + public void Test_ArrowMethod() + { + Assert.AreEqual(new BigInteger(3), Contract.ArrowMethod()); + } + + [TestMethod] + public void Test_ArrowMethodNoReturn() + { + Contract.ArrowMethodNoRerurn(); + } } }