From 980c6e7e967d4ad2870a9444c245fb054fdcfeea Mon Sep 17 00:00:00 2001 From: Hecate2 <2474101468@qq.com> Date: Wed, 15 Jan 2025 10:44:01 +0800 Subject: [PATCH 1/4] fix break in try-catch-finally --- .../MethodConvert/Statement/BreakStatement.cs | 31 +++- .../Statement/CommonForEachStatement.cs | 16 ++ .../MethodConvert/Statement/DoStatement.cs | 4 + .../MethodConvert/Statement/ForStatement.cs | 4 + .../Statement/LabeledStatement.cs | 1 + .../MethodConvert/Statement/Statement.cs | 45 +++++ .../Statement/SwitchStatement.cs | 4 + .../MethodConvert/Statement/TryStatement.cs | 6 + .../MethodConvert/Statement/WhileStatement.cs | 4 + .../Analysers/InstructionCoverage.cs | 10 +- .../Contract_Break.cs | 57 +++++++ .../TestingArtifacts/Contract_Assert.cs | 12 +- .../TestingArtifacts/Contract_Break.cs | 156 ++++++++++++++++++ .../TestingArtifacts/Contract_TryCatch.cs | 49 +++--- .../UnitTest_Break.cs | 16 ++ 15 files changed, 376 insertions(+), 39 deletions(-) create mode 100644 tests/Neo.Compiler.CSharp.TestContracts/Contract_Break.cs create mode 100644 tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Break.cs create mode 100644 tests/Neo.Compiler.CSharp.UnitTests/UnitTest_Break.cs diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Statement/BreakStatement.cs b/src/Neo.Compiler.CSharp/MethodConvert/Statement/BreakStatement.cs index 1339bef1a..7c1299fba 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Statement/BreakStatement.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Statement/BreakStatement.cs @@ -44,10 +44,33 @@ internal partial class MethodConvert private void ConvertBreakStatement(BreakStatementSyntax syntax) { using (InsertSequencePoint(syntax)) - if (_tryStack.TryPeek(out ExceptionHandling? result) && result.BreakTargetCount == 0) - Jump(OpCode.ENDTRY_L, _breakTargets.Peek()); - else - Jump(OpCode.JMP_L, _breakTargets.Peek()); + { + int nestedTryWithFinally = 0; + foreach (StatementContext sc in _generalStatementStack) + { + if (sc.BreakTarget != null) + { + if (nestedTryWithFinally == 0) + Jump(OpCode.JMP_L, sc.BreakTarget); + else + Jump(OpCode.ENDTRY_L, sc.BreakTarget); + return; + } + if (sc.StatementSyntax is TryStatementSyntax && sc.FinallyTarget != null) + { + if (nestedTryWithFinally > 0) + throw new CompilationException(sc.StatementSyntax, DiagnosticId.SyntaxNotSupported, "Neo VM does not support `break` from multi-layered nested try-catch with finally."); + if (sc.TryState != ExceptionHandlingState.Finally) + nestedTryWithFinally++; + else // Not likely to happen. C# syntax analyzer should forbid break in finally + throw new CompilationException(sc.StatementSyntax, DiagnosticId.SyntaxNotSupported, "Cannot break in finally."); + } + } + // break is not handled + throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Cannot find what to break. " + + $"If not syntax error, this is probably a compiler bug. " + + $"Check whether the compiler is leaving out a push into {nameof(_generalStatementStack)}."); + } } } } diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Statement/CommonForEachStatement.cs b/src/Neo.Compiler.CSharp/MethodConvert/Statement/CommonForEachStatement.cs index 82a4a9670..dea86ada5 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Statement/CommonForEachStatement.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Statement/CommonForEachStatement.cs @@ -73,6 +73,8 @@ private void ConvertIteratorForEachStatement(SemanticModel model, ForEachStateme byte elementIndex = AddLocalVariable(elementSymbol); PushContinueTarget(continueTarget); PushBreakTarget(breakTarget); + StatementContext sc = new(syntax, breakTarget: breakTarget, continueTarget: continueTarget); + _generalStatementStack.Push(sc); using (InsertSequencePoint(syntax.ForEachKeyword)) { ConvertExpression(model, syntax.Expression); @@ -97,6 +99,8 @@ private void ConvertIteratorForEachStatement(SemanticModel model, ForEachStateme RemoveLocalVariable(elementSymbol); PopContinueTarget(); PopBreakTarget(); + if (_generalStatementStack.Pop() != sc) + throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Bad statement stack handling inside."); } /// @@ -151,6 +155,8 @@ private void ConvertIteratorForEachVariableStatement(SemanticModel model, ForEac byte iteratorIndex = AddAnonymousVariable(); PushContinueTarget(continueTarget); PushBreakTarget(breakTarget); + StatementContext sc = new(syntax, breakTarget: breakTarget, continueTarget: continueTarget); + _generalStatementStack.Push(sc); using (InsertSequencePoint(syntax.ForEachKeyword)) { ConvertExpression(model, syntax.Expression); @@ -190,6 +196,8 @@ private void ConvertIteratorForEachVariableStatement(SemanticModel model, ForEac RemoveLocalVariable(symbol); PopContinueTarget(); PopBreakTarget(); + if (_generalStatementStack.Pop() != sc) + throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Bad statement stack handling inside."); } /// @@ -220,6 +228,8 @@ private void ConvertArrayForEachStatement(SemanticModel model, ForEachStatementS byte elementIndex = AddLocalVariable(elementSymbol); PushContinueTarget(continueTarget); PushBreakTarget(breakTarget); + StatementContext sc = new(syntax, breakTarget: breakTarget, continueTarget: continueTarget); + _generalStatementStack.Push(sc); using (InsertSequencePoint(syntax.ForEachKeyword)) { ConvertExpression(model, syntax.Expression); @@ -255,6 +265,8 @@ private void ConvertArrayForEachStatement(SemanticModel model, ForEachStatementS RemoveLocalVariable(elementSymbol); PopContinueTarget(); PopBreakTarget(); + if (_generalStatementStack.Pop() != sc) + throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Bad statement stack handling inside."); } /// @@ -284,6 +296,8 @@ private void ConvertArrayForEachVariableStatement(SemanticModel model, ForEachVa byte iIndex = AddAnonymousVariable(); PushContinueTarget(continueTarget); PushBreakTarget(breakTarget); + StatementContext sc = new(syntax, breakTarget: breakTarget, continueTarget: continueTarget); + _generalStatementStack.Push(sc); using (InsertSequencePoint(syntax.ForEachKeyword)) { ConvertExpression(model, syntax.Expression); @@ -334,6 +348,8 @@ private void ConvertArrayForEachVariableStatement(SemanticModel model, ForEachVa RemoveLocalVariable(symbol); PopContinueTarget(); PopBreakTarget(); + if (_generalStatementStack.Pop() != sc) + throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Bad statement stack handling inside."); } } } diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Statement/DoStatement.cs b/src/Neo.Compiler.CSharp/MethodConvert/Statement/DoStatement.cs index 5cfd50795..61ef83c92 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Statement/DoStatement.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Statement/DoStatement.cs @@ -48,6 +48,8 @@ private void ConvertDoStatement(SemanticModel model, DoStatementSyntax syntax) JumpTarget breakTarget = new(); PushContinueTarget(continueTarget); PushBreakTarget(breakTarget); + StatementContext sc = new(syntax, breakTarget: breakTarget, continueTarget: continueTarget); + _generalStatementStack.Push(sc); startTarget.Instruction = AddInstruction(OpCode.NOP); ConvertStatement(model, syntax.Statement); continueTarget.Instruction = AddInstruction(OpCode.NOP); @@ -56,6 +58,8 @@ private void ConvertDoStatement(SemanticModel model, DoStatementSyntax syntax) breakTarget.Instruction = AddInstruction(OpCode.NOP); PopContinueTarget(); PopBreakTarget(); + if (_generalStatementStack.Pop() != sc) + throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Bad statement stack handling inside."); } } } diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Statement/ForStatement.cs b/src/Neo.Compiler.CSharp/MethodConvert/Statement/ForStatement.cs index 2b844ed13..bcb344c5b 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Statement/ForStatement.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Statement/ForStatement.cs @@ -62,6 +62,8 @@ private void ConvertForStatement(SemanticModel model, ForStatementSyntax syntax) JumpTarget breakTarget = new(); PushContinueTarget(continueTarget); PushBreakTarget(breakTarget); + StatementContext sc = new(syntax, breakTarget: breakTarget, continueTarget: continueTarget); + _generalStatementStack.Push(sc); foreach (var (variable, symbol) in variables) { byte variableIndex = AddLocalVariable(symbol); @@ -99,6 +101,8 @@ private void ConvertForStatement(SemanticModel model, ForStatementSyntax syntax) RemoveLocalVariable(symbol); PopContinueTarget(); PopBreakTarget(); + if (_generalStatementStack.Pop() != sc) + throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Bad statement stack handling inside."); } } } diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Statement/LabeledStatement.cs b/src/Neo.Compiler.CSharp/MethodConvert/Statement/LabeledStatement.cs index 4f1855111..4a94710f3 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Statement/LabeledStatement.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Statement/LabeledStatement.cs @@ -51,6 +51,7 @@ private void ConvertLabeledStatement(SemanticModel model, LabeledStatementSyntax instruction.OpCode = OpCode.JMP_L; target.Instruction = AddInstruction(OpCode.NOP); ConvertStatement(model, syntax.Statement); + //_generalStatementStack.Peek().AddLabel(symbol, target); } } } diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Statement/Statement.cs b/src/Neo.Compiler.CSharp/MethodConvert/Statement/Statement.cs index 5923bd5e6..bc1ddf548 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Statement/Statement.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Statement/Statement.cs @@ -10,11 +10,56 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Neo.VM; +using System.Collections.Generic; namespace Neo.Compiler { internal partial class MethodConvert { + /// + /// Store the contexts of goto, break, continue targets + /// + internal class StatementContext(StatementSyntax statementSyntax, + JumpTarget? breakTarget = null, JumpTarget? continueTarget = null, + ExceptionHandlingState? tryState = null, + JumpTarget? catchTarget = null, JumpTarget? finallyTarget = null, JumpTarget? endFinallyTarget = null, + Dictionary? gotoLabels = null, + Dictionary? switchLabels = null + //StatementSyntax? parentStatement = null, + //HashSet? childrenStatements = null + ) + { + public readonly StatementSyntax StatementSyntax = statementSyntax; + public readonly JumpTarget? BreakTarget = breakTarget; + public readonly JumpTarget? ContinueTarget = continueTarget; + public /*readonly*/ ExceptionHandlingState? TryState = tryState; + public readonly JumpTarget? CatchTarget = catchTarget; + public readonly JumpTarget? FinallyTarget = finallyTarget; + public readonly JumpTarget? EndFinallyTarget = endFinallyTarget; + public /*readonly*/ Dictionary? GotoLabels = gotoLabels; + public /*readonly*/ Dictionary? SwitchLabels = switchLabels; + //public readonly StatementSyntax? ParentStatement = parentStatement; + //public readonly HashSet? ChildrenStatements = childrenStatements; + + public bool AddLabel(ILabelSymbol label, JumpTarget target) + { + if (GotoLabels == null) + GotoLabels = []; + return GotoLabels.TryAdd(label, target); + } + public bool AddLabel(SwitchLabelSyntax label, JumpTarget target) + { + if (SwitchLabels == null) + SwitchLabels = []; + return SwitchLabels.TryAdd(label, target); + } + public bool ContainsLabel(ILabelSymbol label) => GotoLabels is not null && GotoLabels.ContainsKey(label); + public bool ContainsLabel(SwitchLabelSyntax label) => SwitchLabels is not null && SwitchLabels.ContainsKey(label); + } + + private readonly Stack _generalStatementStack = new(); + private void ConvertStatement(SemanticModel model, StatementSyntax statement) { switch (statement) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Statement/SwitchStatement.cs b/src/Neo.Compiler.CSharp/MethodConvert/Statement/SwitchStatement.cs index 0070053c2..d62585e92 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Statement/SwitchStatement.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Statement/SwitchStatement.cs @@ -57,6 +57,8 @@ private void ConvertSwitchStatement(SemanticModel model, SwitchStatementSyntax s JumpTarget breakTarget = new(); byte anonymousIndex = AddAnonymousVariable(); PushBreakTarget(breakTarget); + StatementContext sc = new(syntax, breakTarget: breakTarget, switchLabels: labels.ToDictionary()); + _generalStatementStack.Push(sc); using (InsertSequencePoint(syntax.Expression)) { ConvertExpression(model, syntax.Expression); @@ -111,6 +113,8 @@ private void ConvertSwitchStatement(SemanticModel model, SwitchStatementSyntax s breakTarget.Instruction = AddInstruction(OpCode.NOP); PopSwitchLabels(); PopBreakTarget(); + if (_generalStatementStack.Pop() != sc) + throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Bad statement stack handling inside."); } } } diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Statement/TryStatement.cs b/src/Neo.Compiler.CSharp/MethodConvert/Statement/TryStatement.cs index b65d24582..020dc6a30 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Statement/TryStatement.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Statement/TryStatement.cs @@ -53,6 +53,8 @@ private void ConvertTryStatement(SemanticModel model, TryStatementSyntax syntax) JumpTarget catchTarget = new(); JumpTarget finallyTarget = new(); JumpTarget endTarget = new(); + StatementContext sc = new(syntax, catchTarget: catchTarget, finallyTarget: finallyTarget, endFinallyTarget: endTarget, tryState: ExceptionHandlingState.Try); + _generalStatementStack.Push(sc); AddInstruction(new Instruction { OpCode = OpCode.TRY_L, Target = catchTarget, Target2 = finallyTarget }); _tryStack.Push(new ExceptionHandling { State = ExceptionHandlingState.Try }); ConvertStatement(model, syntax.Block); @@ -65,6 +67,7 @@ private void ConvertTryStatement(SemanticModel model, TryStatementSyntax syntax) if (catchClause.Filter is not null) throw new CompilationException(catchClause.Filter, DiagnosticId.CatchFilter, $"Unsupported syntax: {catchClause.Filter}"); _tryStack.Peek().State = ExceptionHandlingState.Catch; + sc.TryState = ExceptionHandlingState.Catch; ILocalSymbol? exceptionSymbol = null; byte exceptionIndex; if (catchClause.Declaration is null) @@ -92,12 +95,15 @@ private void ConvertTryStatement(SemanticModel model, TryStatementSyntax syntax) if (syntax.Finally is not null) { _tryStack.Peek().State = ExceptionHandlingState.Finally; + sc.TryState = ExceptionHandlingState.Finally; finallyTarget.Instruction = AddInstruction(OpCode.NOP); ConvertStatement(model, syntax.Finally.Block); AddInstruction(OpCode.ENDFINALLY); } endTarget.Instruction = AddInstruction(OpCode.NOP); _tryStack.Pop(); + if (_generalStatementStack.Pop() != sc) + throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Bad statement stack handling inside."); } } } diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Statement/WhileStatement.cs b/src/Neo.Compiler.CSharp/MethodConvert/Statement/WhileStatement.cs index 6daeeff07..9c226a86b 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Statement/WhileStatement.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Statement/WhileStatement.cs @@ -45,6 +45,8 @@ private void ConvertWhileStatement(SemanticModel model, WhileStatementSyntax syn JumpTarget breakTarget = new(); PushContinueTarget(continueTarget); PushBreakTarget(breakTarget); + StatementContext sc = new(syntax, breakTarget: breakTarget, continueTarget: continueTarget); + _generalStatementStack.Push(sc); continueTarget.Instruction = AddInstruction(OpCode.NOP); using (InsertSequencePoint(syntax.Condition)) { @@ -56,6 +58,8 @@ private void ConvertWhileStatement(SemanticModel model, WhileStatementSyntax syn breakTarget.Instruction = AddInstruction(OpCode.NOP); PopContinueTarget(); PopBreakTarget(); + if (_generalStatementStack.Pop() != sc) + throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Bad statement stack handling inside."); } } } diff --git a/src/Neo.Compiler.CSharp/Optimizer/Analysers/InstructionCoverage.cs b/src/Neo.Compiler.CSharp/Optimizer/Analysers/InstructionCoverage.cs index 6fd146dc4..171127a59 100644 --- a/src/Neo.Compiler.CSharp/Optimizer/Analysers/InstructionCoverage.cs +++ b/src/Neo.Compiler.CSharp/Optimizer/Analysers/InstructionCoverage.cs @@ -30,7 +30,7 @@ public enum TryType FINALLY = 1 << 3, } - [DebuggerDisplay("{catchAddr}, {finallyAddr}, {tryStateType}, {continueAfterFinally}")] + [DebuggerDisplay("{catchAddr}, {finallyAddr}, {tryType}, {continueAfterFinally}")] public struct TryState { public int catchAddr { get; init; } @@ -248,7 +248,7 @@ public BranchType CoverInstruction(int addr, Stack? tryStack = null, if (continueAfterFinally) return coveredMap[entranceAddr] = CoverInstruction(finallyAddr, tryStack, jumpFromBasicBlockEntranceAddr: entranceAddr); // FINALLY is OK, but throwed in previous TRY (without catch) or CATCH - return BranchType.THROW; // Do not set coveredMap[entranceAddr] = BranchType.THROW; + return value; // Do not set coveredMap[entranceAddr] = BranchType.THROW; } //if (instruction.OpCode != OpCode.NOP) { @@ -274,7 +274,8 @@ public BranchType CoverInstruction(int addr, Stack? tryStack = null, returnedType = BranchType.ABORT; foreach (int callaTarget in pushaTargets.Keys) { - BranchType singleCallaResult = CoverInstruction(callaTarget, tryStack, jumpFromBasicBlockEntranceAddr: entranceAddr); + // Use `tryStack: null` to avoid using current try stack in a deeper call stack + BranchType singleCallaResult = CoverInstruction(callaTarget, tryStack: null, jumpFromBasicBlockEntranceAddr: entranceAddr); if (singleCallaResult < returnedType) returnedType = singleCallaResult; // TODO: if a PUSHA cannot be covered, do not add it as a CALLA target @@ -283,7 +284,8 @@ public BranchType CoverInstruction(int addr, Stack? tryStack = null, else { int callTarget = ComputeJumpTarget(addr, instruction); - returnedType = CoverInstruction(callTarget, tryStack, jumpFromBasicBlockEntranceAddr: entranceAddr); + // Use `tryStack: null` to avoid using current try stack in a deeper call stack + returnedType = CoverInstruction(callTarget, tryStack: null, jumpFromBasicBlockEntranceAddr: entranceAddr); } if (returnedType == BranchType.OK) return coveredMap[entranceAddr] = CoverInstruction(addr + instruction.Size, tryStack, continueFromBasicBlockEntranceAddr: entranceAddr); diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Break.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Break.cs new file mode 100644 index 000000000..9ff7792af --- /dev/null +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Break.cs @@ -0,0 +1,57 @@ +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Attributes; +using Neo.SmartContract.Framework.Services; + +namespace Neo.Compiler.CSharp.TestContracts +{ + public class Contract_Break : SmartContract.Framework.SmartContract + { + public static void BreakInTryCatch() + { + Storage.Put("\xff\x00", "\x00"); + foreach (object i in Storage.Find("\xff")) + try { break; } + finally { Storage.Put("\xff\x00", "\x01"); } + ExecutionEngine.Assert(Storage.Get("\xff\x00")! == "\x01"); + foreach (object i in Storage.Find("\xff")) + try { throw new System.Exception(); } + catch + { + do { break; } + while (true); + Storage.Put("\xff\x00", "\x00"); + break; // break foreach; should execute finally + } + finally + { + ExecutionEngine.Assert(Storage.Get("\xff\x00")! == "\x00"); + foreach (int _ in new int[] { 0, 1, 2 }) + { + Storage.Put("\xff\x00", "\x02"); + break; + } + } + ExecutionEngine.Assert(Storage.Get("\xff\x00")! == "\x02"); + foreach (object i in Storage.Find("\xff")) + try + { + for (int j = 0; j < 3;) + break; + throw new System.Exception(); + } + catch + { + int j = 0; + while (j < 3) + break; + break; // foreach; should execute finally + } + finally + { + ExecutionEngine.Assert(Storage.Get("\xff\x00")! == "\x02"); + Storage.Put("\xff\x00", "\x03"); + } + ExecutionEngine.Assert(Storage.Get("\xff\x00")! == "\x03"); + } + } +} diff --git a/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Assert.cs b/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Assert.cs index 62bcccb86..4b462439f 100644 --- a/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Assert.cs +++ b/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Assert.cs @@ -15,7 +15,7 @@ public abstract class Contract_Assert(Neo.SmartContract.Testing.SmartContractIni /// /// Optimization: "All" /// - public static Neo.SmartContract.NefFile Nef => Neo.IO.Helper.AsSerializable(Convert.FromBase64String(@"TkVGM1Rlc3RpbmdFbmdpbmUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGhXAQAQcAg5EXAJOQBkcGhAVwEAEHA063ARcGhAVwIAEHA7CA003HA9CnERcD0FEnA/aEBXAgAQcDsRFxFwDAlleGNlcHRpb246cTS2cD0FEnA/aEBXAgAQcDsHDBFwPQBxEnA9ADSbQDbfjGM=")); + public static Neo.SmartContract.NefFile Nef => Neo.IO.Helper.AsSerializable(Convert.FromBase64String(@"TkVGM1Rlc3RpbmdFbmdpbmUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGtXAQAQcAg5EXAJOQBkcGhAVwEAEHA063ARcGhAVwIAEHA7CA003HA9CnERcD0FEnA/aEBXAgAQcDsRFxFwDAlleGNlcHRpb246cTS2cD0FEnA/aEBXAgAQcDsHDBFwPQtxEnA9BjSbcD9oQKrgmAI=")); #endregion @@ -73,19 +73,23 @@ public abstract class Contract_Assert(Neo.SmartContract.Testing.SmartContractIni /// Unsafe method /// /// - /// Script: VwIAEHA7BwwRcD0AcRJwPQA0mw== + /// Script: VwIAEHA7BwwRcD0LcRJwPQY0m3A/aEA= /// INITSLOT 0200 [64 datoshi] /// PUSH0 [1 datoshi] /// STLOC0 [2 datoshi] /// TRY 070C [4 datoshi] /// PUSH1 [1 datoshi] /// STLOC0 [2 datoshi] - /// ENDTRY 00 [4 datoshi] + /// ENDTRY 0B [4 datoshi] /// STLOC1 [2 datoshi] /// PUSH2 [1 datoshi] /// STLOC0 [2 datoshi] - /// ENDTRY 00 [4 datoshi] + /// ENDTRY 06 [4 datoshi] /// CALL 9B [512 datoshi] + /// STLOC0 [2 datoshi] + /// ENDFINALLY [4 datoshi] + /// LDLOC0 [2 datoshi] + /// RET [0 datoshi] /// [DisplayName("testAssertInFinally")] public abstract BigInteger? TestAssertInFinally(); diff --git a/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Break.cs b/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Break.cs new file mode 100644 index 000000000..306a105ff --- /dev/null +++ b/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Break.cs @@ -0,0 +1,156 @@ +using Neo.Cryptography.ECC; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Numerics; + +namespace Neo.SmartContract.Testing; + +public abstract class Contract_Break(Neo.SmartContract.Testing.SmartContractInitialize initialize) : Neo.SmartContract.Testing.SmartContract(initialize), IContractInfo +{ + #region Compiled data + + public static Neo.SmartContract.Manifest.ContractManifest Manifest => Neo.SmartContract.Manifest.ContractManifest.Parse(@"{""name"":""Contract_Break"",""groups"":[],""features"":{},""supportedstandards"":[],""abi"":{""methods"":[{""name"":""breakInTryCatch"",""parameters"":[],""returntype"":""Void"",""offset"":0,""safe"":false}],""events"":[]},""permissions"":[],""trusts"":[],""extra"":{""nef"":{""optimization"":""All""}}}"); + + /// + /// Optimization: "All" + /// + public static Neo.SmartContract.NefFile Nef => Neo.IO.Helper.AsSerializable(Convert.FromBase64String(@"TkVGM1Rlc3RpbmdFbmdpbmUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP1DAVcGAAwBAAwC/wA1CgEAABAMAf81EQEAAHAiG2hB81S/HXE7AAU9FwwBAQwC/wA15gAAAD9oQZwI7Zwk4QwC/wA19AAAAAwBAZc5EAwB/zXWAAAAcCJWaEHzVL8dcTsPHgwJZXhjZXB0aW9uOnIMAQAMAv8ANaAAAAA9OQwC/wA1tQAAAAwBAJc5EhEQE8BKcspzEHQiEWpsznUMAQIMAv8ANHMiBmxrMO8/aEGcCO2cJKYMAv8ANH4MAQKXORAMAf80Y3AiPGhB81S/HXE7FR4QcmoTtUUMCWV4Y2VwdGlvbjpyEHNrE7VFPR8MAv8ANEUMAQKXOQwBAwwC/wA0Fz9oQZwI7ZwkwAwC/wA0KAwBA5c5QFcAAnl4QZv2Z85B5j8YhEBXAAJ5eEH2tGviQd8wuJpAVwABeEH2tGviQZJd6DFAEImfDw==")); + + #endregion + + #region Unsafe methods + + /// + /// Unsafe method + /// + /// + /// Script: VwYADAEADAL/ADUKAQAAEAwB/zURAQAAcCIbaEHzVL8dcTsABT0XDAEBDAL/ADXmAAAAP2hBnAjtnCThDAL/ADX0AAAADAEBlzkQDAH/NdYAAABwIlZoQfNUvx1xOw8eDAlleGNlcHRpb246cgwBAAwC/wA1oAAAAD05DAL/ADW1AAAADAEAlzkSERATwEpyynMQdCIRamzOdQwBAgwC/wA0cyIGbGsw7z9oQZwI7ZwkpgwC/wA0fgwBApc5EAwB/zRjcCI8aEHzVL8dcTsVHhByahO1RQwJZXhjZXB0aW9uOnIQc2sTtUU9HwwC/wA0RQwBApc5DAEDDAL/ADQXP2hBnAjtnCTADAL/ADQoDAEDlzlA + /// INITSLOT 0600 [64 datoshi] + /// PUSHDATA1 00 [8 datoshi] + /// PUSHDATA1 FF00 [8 datoshi] + /// CALL_L 0A010000 [512 datoshi] + /// PUSH0 [1 datoshi] + /// PUSHDATA1 FF '?' [8 datoshi] + /// CALL_L 11010000 [512 datoshi] + /// STLOC0 [2 datoshi] + /// JMP 1B [2 datoshi] + /// LDLOC0 [2 datoshi] + /// SYSCALL F354BF1D 'System.Iterator.Value' [16 datoshi] + /// STLOC1 [2 datoshi] + /// TRY 0005 [4 datoshi] + /// ENDTRY 17 [4 datoshi] + /// PUSHDATA1 01 [8 datoshi] + /// PUSHDATA1 FF00 [8 datoshi] + /// CALL_L E6000000 [512 datoshi] + /// ENDFINALLY [4 datoshi] + /// LDLOC0 [2 datoshi] + /// SYSCALL 9C08ED9C 'System.Iterator.Next' [32768 datoshi] + /// JMPIF E1 [2 datoshi] + /// PUSHDATA1 FF00 [8 datoshi] + /// CALL_L F4000000 [512 datoshi] + /// PUSHDATA1 01 [8 datoshi] + /// EQUAL [32 datoshi] + /// ASSERT [1 datoshi] + /// PUSH0 [1 datoshi] + /// PUSHDATA1 FF '?' [8 datoshi] + /// CALL_L D6000000 [512 datoshi] + /// STLOC0 [2 datoshi] + /// JMP 56 [2 datoshi] + /// LDLOC0 [2 datoshi] + /// SYSCALL F354BF1D 'System.Iterator.Value' [16 datoshi] + /// STLOC1 [2 datoshi] + /// TRY 0F1E [4 datoshi] + /// PUSHDATA1 657863657074696F6E 'exception' [8 datoshi] + /// THROW [512 datoshi] + /// STLOC2 [2 datoshi] + /// PUSHDATA1 00 [8 datoshi] + /// PUSHDATA1 FF00 [8 datoshi] + /// CALL_L A0000000 [512 datoshi] + /// ENDTRY 39 [4 datoshi] + /// PUSHDATA1 FF00 [8 datoshi] + /// CALL_L B5000000 [512 datoshi] + /// PUSHDATA1 00 [8 datoshi] + /// EQUAL [32 datoshi] + /// ASSERT [1 datoshi] + /// PUSH2 [1 datoshi] + /// PUSH1 [1 datoshi] + /// PUSH0 [1 datoshi] + /// PUSH3 [1 datoshi] + /// PACK [2048 datoshi] + /// DUP [2 datoshi] + /// STLOC2 [2 datoshi] + /// SIZE [4 datoshi] + /// STLOC3 [2 datoshi] + /// PUSH0 [1 datoshi] + /// STLOC4 [2 datoshi] + /// JMP 11 [2 datoshi] + /// LDLOC2 [2 datoshi] + /// LDLOC4 [2 datoshi] + /// PICKITEM [64 datoshi] + /// STLOC5 [2 datoshi] + /// PUSHDATA1 02 [8 datoshi] + /// PUSHDATA1 FF00 [8 datoshi] + /// CALL 73 [512 datoshi] + /// JMP 06 [2 datoshi] + /// LDLOC4 [2 datoshi] + /// LDLOC3 [2 datoshi] + /// JMPLT EF [2 datoshi] + /// ENDFINALLY [4 datoshi] + /// LDLOC0 [2 datoshi] + /// SYSCALL 9C08ED9C 'System.Iterator.Next' [32768 datoshi] + /// JMPIF A6 [2 datoshi] + /// PUSHDATA1 FF00 [8 datoshi] + /// CALL 7E [512 datoshi] + /// PUSHDATA1 02 [8 datoshi] + /// EQUAL [32 datoshi] + /// ASSERT [1 datoshi] + /// PUSH0 [1 datoshi] + /// PUSHDATA1 FF '?' [8 datoshi] + /// CALL 63 [512 datoshi] + /// STLOC0 [2 datoshi] + /// JMP 3C [2 datoshi] + /// LDLOC0 [2 datoshi] + /// SYSCALL F354BF1D 'System.Iterator.Value' [16 datoshi] + /// STLOC1 [2 datoshi] + /// TRY 151E [4 datoshi] + /// PUSH0 [1 datoshi] + /// STLOC2 [2 datoshi] + /// LDLOC2 [2 datoshi] + /// PUSH3 [1 datoshi] + /// LT [8 datoshi] + /// DROP [2 datoshi] + /// PUSHDATA1 657863657074696F6E 'exception' [8 datoshi] + /// THROW [512 datoshi] + /// STLOC2 [2 datoshi] + /// PUSH0 [1 datoshi] + /// STLOC3 [2 datoshi] + /// LDLOC3 [2 datoshi] + /// PUSH3 [1 datoshi] + /// LT [8 datoshi] + /// DROP [2 datoshi] + /// ENDTRY 1F [4 datoshi] + /// PUSHDATA1 FF00 [8 datoshi] + /// CALL 45 [512 datoshi] + /// PUSHDATA1 02 [8 datoshi] + /// EQUAL [32 datoshi] + /// ASSERT [1 datoshi] + /// PUSHDATA1 03 [8 datoshi] + /// PUSHDATA1 FF00 [8 datoshi] + /// CALL 17 [512 datoshi] + /// ENDFINALLY [4 datoshi] + /// LDLOC0 [2 datoshi] + /// SYSCALL 9C08ED9C 'System.Iterator.Next' [32768 datoshi] + /// JMPIF C0 [2 datoshi] + /// PUSHDATA1 FF00 [8 datoshi] + /// CALL 28 [512 datoshi] + /// PUSHDATA1 03 [8 datoshi] + /// EQUAL [32 datoshi] + /// ASSERT [1 datoshi] + /// RET [0 datoshi] + /// + [DisplayName("breakInTryCatch")] + public abstract void BreakInTryCatch(); + + #endregion +} diff --git a/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_TryCatch.cs b/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_TryCatch.cs index 6fe6a998c..7c3e4a49b 100644 --- a/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_TryCatch.cs +++ b/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_TryCatch.cs @@ -10,12 +10,12 @@ public abstract class Contract_TryCatch(Neo.SmartContract.Testing.SmartContractI { #region Compiled data - public static Neo.SmartContract.Manifest.ContractManifest Manifest => Neo.SmartContract.Manifest.ContractManifest.Parse(@"{""name"":""Contract_TryCatch"",""groups"":[],""features"":{},""supportedstandards"":[],""abi"":{""methods"":[{""name"":""try01"",""parameters"":[{""name"":""throwException"",""type"":""Boolean""},{""name"":""enterCatch"",""type"":""Boolean""},{""name"":""enterFinally"",""type"":""Boolean""}],""returntype"":""Integer"",""offset"":0,""safe"":false},{""name"":""try02"",""parameters"":[{""name"":""throwException"",""type"":""Boolean""},{""name"":""enterCatch"",""type"":""Boolean""},{""name"":""enterFinally"",""type"":""Boolean""}],""returntype"":""Integer"",""offset"":92,""safe"":false},{""name"":""try03"",""parameters"":[{""name"":""throwException"",""type"":""Boolean""},{""name"":""enterCatch"",""type"":""Boolean""},{""name"":""enterFinally"",""type"":""Boolean""}],""returntype"":""Integer"",""offset"":101,""safe"":false},{""name"":""tryNest"",""parameters"":[{""name"":""throwInTry"",""type"":""Boolean""},{""name"":""throwInCatch"",""type"":""Boolean""},{""name"":""throwInFinally"",""type"":""Boolean""},{""name"":""enterOuterCatch"",""type"":""Boolean""}],""returntype"":""Integer"",""offset"":196,""safe"":false},{""name"":""throwInCatch"",""parameters"":[{""name"":""throwInTry"",""type"":""Boolean""},{""name"":""throwInCatch"",""type"":""Boolean""},{""name"":""enterFinally"",""type"":""Boolean""}],""returntype"":""Integer"",""offset"":346,""safe"":false},{""name"":""tryFinally"",""parameters"":[{""name"":""throwException"",""type"":""Boolean""},{""name"":""enterFinally"",""type"":""Boolean""}],""returntype"":""Integer"",""offset"":403,""safe"":false},{""name"":""tryFinallyAndRethrow"",""parameters"":[{""name"":""throwException"",""type"":""Boolean""},{""name"":""enterFinally"",""type"":""Boolean""}],""returntype"":""Integer"",""offset"":487,""safe"":false},{""name"":""tryCatch"",""parameters"":[{""name"":""throwException"",""type"":""Boolean""},{""name"":""enterCatch"",""type"":""Boolean""}],""returntype"":""Integer"",""offset"":565,""safe"":false},{""name"":""tryWithTwoFinally"",""parameters"":[{""name"":""throwInInner"",""type"":""Boolean""},{""name"":""throwInOuter"",""type"":""Boolean""},{""name"":""enterInnerCatch"",""type"":""Boolean""},{""name"":""enterOuterCatch"",""type"":""Boolean""},{""name"":""enterInnerFinally"",""type"":""Boolean""},{""name"":""enterOuterFinally"",""type"":""Boolean""}],""returntype"":""Integer"",""offset"":645,""safe"":false},{""name"":""tryecpointCast"",""parameters"":[{""name"":""useInvalidECpoint"",""type"":""Boolean""},{""name"":""enterCatch"",""type"":""Boolean""},{""name"":""enterFinally"",""type"":""Boolean""}],""returntype"":""Integer"",""offset"":969,""safe"":false},{""name"":""tryvalidByteString2Ecpoint"",""parameters"":[{""name"":""enterCatch"",""type"":""Boolean""},{""name"":""enterFinally"",""type"":""Boolean""}],""returntype"":""Integer"",""offset"":1106,""safe"":false},{""name"":""tryinvalidByteArray2UInt160"",""parameters"":[{""name"":""useInvalidECpoint"",""type"":""Boolean""},{""name"":""enterCatch"",""type"":""Boolean""},{""name"":""enterFinally"",""type"":""Boolean""}],""returntype"":""Integer"",""offset"":1230,""safe"":false},{""name"":""tryvalidByteArray2UInt160"",""parameters"":[{""name"":""enterCatch"",""type"":""Boolean""},{""name"":""enterFinally"",""type"":""Boolean""}],""returntype"":""Integer"",""offset"":1354,""safe"":false},{""name"":""tryinvalidByteArray2UInt256"",""parameters"":[{""name"":""useInvalidECpoint"",""type"":""Boolean""},{""name"":""enterCatch"",""type"":""Boolean""},{""name"":""enterFinally"",""type"":""Boolean""}],""returntype"":""Integer"",""offset"":1465,""safe"":false},{""name"":""tryvalidByteArray2UInt256"",""parameters"":[{""name"":""enterCatch"",""type"":""Boolean""},{""name"":""enterFinally"",""type"":""Boolean""}],""returntype"":""Integer"",""offset"":1599,""safe"":false},{""name"":""tryNULL2Ecpoint_1"",""parameters"":[{""name"":""setToNull"",""type"":""Boolean""},{""name"":""enterCatch"",""type"":""Boolean""},{""name"":""enterFinally"",""type"":""Boolean""}],""returntype"":""Array"",""offset"":1711,""safe"":false},{""name"":""tryNULL2Uint160_1"",""parameters"":[{""name"":""setToNull"",""type"":""Boolean""},{""name"":""enterCatch"",""type"":""Boolean""},{""name"":""enterFinally"",""type"":""Boolean""}],""returntype"":""Array"",""offset"":1870,""safe"":false},{""name"":""tryNULL2Uint256_1"",""parameters"":[{""name"":""setToNull"",""type"":""Boolean""},{""name"":""enterCatch"",""type"":""Boolean""},{""name"":""enterFinally"",""type"":""Boolean""}],""returntype"":""Array"",""offset"":2029,""safe"":false},{""name"":""tryNULL2Bytestring_1"",""parameters"":[{""name"":""setToNull"",""type"":""Boolean""},{""name"":""enterCatch"",""type"":""Boolean""},{""name"":""enterFinally"",""type"":""Boolean""}],""returntype"":""Array"",""offset"":2188,""safe"":false},{""name"":""throwCall"",""parameters"":[],""returntype"":""Any"",""offset"":184,""safe"":false},{""name"":""tryUncatchableException"",""parameters"":[{""name"":""throwException"",""type"":""Boolean""},{""name"":""enterCatch"",""type"":""Boolean""},{""name"":""enterFinally"",""type"":""Boolean""}],""returntype"":""Integer"",""offset"":2336,""safe"":false}],""events"":[]},""permissions"":[],""trusts"":[],""extra"":{""nef"":{""optimization"":""All""}}}"); + public static Neo.SmartContract.Manifest.ContractManifest Manifest => Neo.SmartContract.Manifest.ContractManifest.Parse(@"{""name"":""Contract_TryCatch"",""groups"":[],""features"":{},""supportedstandards"":[],""abi"":{""methods"":[{""name"":""try01"",""parameters"":[{""name"":""throwException"",""type"":""Boolean""},{""name"":""enterCatch"",""type"":""Boolean""},{""name"":""enterFinally"",""type"":""Boolean""}],""returntype"":""Integer"",""offset"":0,""safe"":false},{""name"":""try02"",""parameters"":[{""name"":""throwException"",""type"":""Boolean""},{""name"":""enterCatch"",""type"":""Boolean""},{""name"":""enterFinally"",""type"":""Boolean""}],""returntype"":""Integer"",""offset"":92,""safe"":false},{""name"":""try03"",""parameters"":[{""name"":""throwException"",""type"":""Boolean""},{""name"":""enterCatch"",""type"":""Boolean""},{""name"":""enterFinally"",""type"":""Boolean""}],""returntype"":""Integer"",""offset"":101,""safe"":false},{""name"":""tryNest"",""parameters"":[{""name"":""throwInTry"",""type"":""Boolean""},{""name"":""throwInCatch"",""type"":""Boolean""},{""name"":""throwInFinally"",""type"":""Boolean""},{""name"":""enterOuterCatch"",""type"":""Boolean""}],""returntype"":""Integer"",""offset"":195,""safe"":false},{""name"":""throwInCatch"",""parameters"":[{""name"":""throwInTry"",""type"":""Boolean""},{""name"":""throwInCatch"",""type"":""Boolean""},{""name"":""enterFinally"",""type"":""Boolean""}],""returntype"":""Integer"",""offset"":343,""safe"":false},{""name"":""tryFinally"",""parameters"":[{""name"":""throwException"",""type"":""Boolean""},{""name"":""enterFinally"",""type"":""Boolean""}],""returntype"":""Integer"",""offset"":400,""safe"":false},{""name"":""tryFinallyAndRethrow"",""parameters"":[{""name"":""throwException"",""type"":""Boolean""},{""name"":""enterFinally"",""type"":""Boolean""}],""returntype"":""Integer"",""offset"":484,""safe"":false},{""name"":""tryCatch"",""parameters"":[{""name"":""throwException"",""type"":""Boolean""},{""name"":""enterCatch"",""type"":""Boolean""}],""returntype"":""Integer"",""offset"":561,""safe"":false},{""name"":""tryWithTwoFinally"",""parameters"":[{""name"":""throwInInner"",""type"":""Boolean""},{""name"":""throwInOuter"",""type"":""Boolean""},{""name"":""enterInnerCatch"",""type"":""Boolean""},{""name"":""enterOuterCatch"",""type"":""Boolean""},{""name"":""enterInnerFinally"",""type"":""Boolean""},{""name"":""enterOuterFinally"",""type"":""Boolean""}],""returntype"":""Integer"",""offset"":640,""safe"":false},{""name"":""tryecpointCast"",""parameters"":[{""name"":""useInvalidECpoint"",""type"":""Boolean""},{""name"":""enterCatch"",""type"":""Boolean""},{""name"":""enterFinally"",""type"":""Boolean""}],""returntype"":""Integer"",""offset"":964,""safe"":false},{""name"":""tryvalidByteString2Ecpoint"",""parameters"":[{""name"":""enterCatch"",""type"":""Boolean""},{""name"":""enterFinally"",""type"":""Boolean""}],""returntype"":""Integer"",""offset"":1101,""safe"":false},{""name"":""tryinvalidByteArray2UInt160"",""parameters"":[{""name"":""useInvalidECpoint"",""type"":""Boolean""},{""name"":""enterCatch"",""type"":""Boolean""},{""name"":""enterFinally"",""type"":""Boolean""}],""returntype"":""Integer"",""offset"":1225,""safe"":false},{""name"":""tryvalidByteArray2UInt160"",""parameters"":[{""name"":""enterCatch"",""type"":""Boolean""},{""name"":""enterFinally"",""type"":""Boolean""}],""returntype"":""Integer"",""offset"":1349,""safe"":false},{""name"":""tryinvalidByteArray2UInt256"",""parameters"":[{""name"":""useInvalidECpoint"",""type"":""Boolean""},{""name"":""enterCatch"",""type"":""Boolean""},{""name"":""enterFinally"",""type"":""Boolean""}],""returntype"":""Integer"",""offset"":1460,""safe"":false},{""name"":""tryvalidByteArray2UInt256"",""parameters"":[{""name"":""enterCatch"",""type"":""Boolean""},{""name"":""enterFinally"",""type"":""Boolean""}],""returntype"":""Integer"",""offset"":1594,""safe"":false},{""name"":""tryNULL2Ecpoint_1"",""parameters"":[{""name"":""setToNull"",""type"":""Boolean""},{""name"":""enterCatch"",""type"":""Boolean""},{""name"":""enterFinally"",""type"":""Boolean""}],""returntype"":""Array"",""offset"":1706,""safe"":false},{""name"":""tryNULL2Uint160_1"",""parameters"":[{""name"":""setToNull"",""type"":""Boolean""},{""name"":""enterCatch"",""type"":""Boolean""},{""name"":""enterFinally"",""type"":""Boolean""}],""returntype"":""Array"",""offset"":1865,""safe"":false},{""name"":""tryNULL2Uint256_1"",""parameters"":[{""name"":""setToNull"",""type"":""Boolean""},{""name"":""enterCatch"",""type"":""Boolean""},{""name"":""enterFinally"",""type"":""Boolean""}],""returntype"":""Array"",""offset"":2024,""safe"":false},{""name"":""tryNULL2Bytestring_1"",""parameters"":[{""name"":""setToNull"",""type"":""Boolean""},{""name"":""enterCatch"",""type"":""Boolean""},{""name"":""enterFinally"",""type"":""Boolean""}],""returntype"":""Array"",""offset"":2183,""safe"":false},{""name"":""throwCall"",""parameters"":[],""returntype"":""Any"",""offset"":183,""safe"":false},{""name"":""tryUncatchableException"",""parameters"":[{""name"":""throwException"",""type"":""Boolean""},{""name"":""enterCatch"",""type"":""Boolean""},{""name"":""enterFinally"",""type"":""Boolean""}],""returntype"":""Integer"",""offset"":2331,""safe"":false}],""events"":[]},""permissions"":[],""trusts"":[],""extra"":{""nef"":{""optimization"":""All""}}}"); /// /// Optimization: "All" /// - public static Neo.SmartContract.NefFile Nef => Neo.IO.Helper.AsSerializable(Convert.FromBase64String(@"TkVGM1Rlc3RpbmdFbmdpbmUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP1xCVcCAxBwOxYeEnB4Jg4MCWV4Y2VwdGlvbjo9QXF5JgQTcD05eiY1aEqcSgIAAACALgQiCkoC////fzIeA/////8AAAAAkUoC////fzIMAwAAAAABAAAAn3BFP2hAVwADenl4NJ5AVwIDEHA7DRUScHgmBTRGRT1BcXkmBBNwPTl6JjVoSpxKAgAAAIAuBCIKSgL///9/Mh4D/////wAAAACRSgL///9/MgwDAAAAAAEAAACfcEU/aEAMCWV4Y2VwdGlvbjpXAgQQcDtWADsNGBJweCYFNORFPUZxE3B5JgU02UU9O3omBDTRaEqcSgIAAACALgQiCkoC////fzIeA/////8AAAAAkUoC////fzIMAwAAAAABAAAAn3BFPz07cXsmNWhKnEoCAAAAgC4EIgpKAv///38yHgP/////AAAAAJFKAv///38yDAMAAAAAAQAAAJ9wRT0CaEBXAgMQcDsWKhFweCYODAlleGNlcHRpb246PRxxEnB5Jg4MCWV4Y2VwdGlvbjo9CHomBBNwPxRwaEBXAQIQcDsAFhJweCYODAlleGNlcHRpb246PTl5JjVoSpxKAgAAAIAuBCIKSgL///9/Mh4D/////wAAAACRSgL///9/MgwDAAAAAAEAAACfcEU/aEBXAQIQcDsAEBJweCYINcT+//9FPTl5JjVoSpxKAgAAAIAuBCIKSgL///9/Mh4D/////wAAAACRSgL///9/MgwDAAAAAAEAAACfcEU/aEBXAgIQcDsQABJweCYINXb+//9FPTtxeSY1aEqcSgIAAACALgQiCkoC////fzIeA/////8AAAAAkUoC////fzIMAwAAAAABAAAAn3BFPQJoQFcCBhBwPM8AAAAHAQAAO0d/aEqcSgIAAACALgQiCkoC////fzIeA/////8AAAAAkUoC////fzIMAwAAAAABAAAAn3BFeCYODAlleGNlcHRpb246PXBxeiY0aBKeSgIAAACALgQiCkoC////fzIeA/////8AAAAAkUoC////fzIMAwAAAAABAAAAn3A9OHwmNGgTnkoCAAAAgC4EIgpKAv///38yHgP/////AAAAAJFKAv///38yDAMAAAAAAQAAAJ9wP3kmDgwJZXhjZXB0aW9uOj1wcXsmNGgUnkoCAAAAgC4EIgpKAv///38yHgP/////AAAAAJFKAv///38yDAMAAAAAAQAAAJ9wPTh9JjRoFZ5KAgAAAIAuBCIKSgL///9/Mh4D/////wAAAACRSgL///9/MgwDAAAAAAEAAACfcD9oQFcCAxBwO0NLEnB4JgwMBgoLDA0ODyIlDCECRwDbLpDZ8CxPn8hiq6ypJyX5W0/dzI1/+lOGk+z0Y6lK2CQJSsoAISgDOnE9QXF5JgQTcD05eiY1aEqcSgIAAACALgQiCkoC////fzIeA/////8AAAAAkUoC////fzIMAwAAAAABAAAAn3BFP2hAVwICEHA7Nj4ScAwhAkcA2y6Q2fAsT5/IYqusqScl+VtP3cyNf/pThpPs9GOpStgkCUrKACEoAzpxPUFxeCYEE3A9OXkmNWhKnEoCAAAAgC4EIgpKAv///38yHgP/////AAAAAJFKAv///38yDAMAAAAAAQAAAJ9wRT9oQFcCAxBwOzY+EnB4JgwMBgoLDA0ODyIYDBR+7hqr62ftHXkdROT1/POukXGocUrYJAlKygAUKAM6cT1BcXkmBBNwPTl6JjVoSpxKAgAAAIAuBCIKSgL///9/Mh4D/////wAAAACRSgL///9/MgwDAAAAAAEAAACfcEU/aEBXAgIQcDspMRJwDBR+7hqr62ftHXkdROT1/POukXGocUrYJAlKygAUKAM6cT1BcXgmBBNwPTl5JjVoSpxKAgAAAIAuBCIKSgL///9/Mh4D/////wAAAACRSgL///9/MgwDAAAAAAEAAACfcEU/aEBXAgMQcDtASBJweCYVDAYKCwwNDg9K2CQrSsoAICglOgwg7c+GeRBOwpEaT+Ka19sjKkk+W5kPsdp68Me5iZSMiSVxPUFxeSYEE3A9OXomNWhKnEoCAAAAgC4EIgpKAv///38yHgP/////AAAAAJFKAv///38yDAMAAAAAAQAAAJ9wRT9oQFcCAhBwOyoyEnAMIO3PhnkQTsKRGk/imtfbIypJPluZD7HaevDHuYmUjIklcT1BcXgmBBNwPTl5JjVoSpxKAgAAAIAuBCIKSgL///9/Mh4D/////wAAAACRSgL///9/MgwDAAAAAAEAAACfcEU/aEBXAwMQcAAhiNsoStgkCUrKACEoAzpxOwwUEnB4JgQLcT16cnkmBBNwPXJ6JjVoSpxKAgAAAIAuBCIKSgL///9/Mh4D/////wAAAACRSgL///9/MgwDAAAAAAEAAACfcEVpcmrYJjVoSpxKAgAAAIAuBCIKSgL///9/Mh4D/////wAAAACRSgL///9/MgwDAAAAAAEAAACfcEU/aWgSv0BXAwMQcAAUiNsoStgkCUrKABQoAzpxOwwUEnB4JgQLcT16cnkmBBNwPXJ6JjVoSpxKAgAAAIAuBCIKSgL///9/Mh4D/////wAAAACRSgL///9/MgwDAAAAAAEAAACfcEVpcmrYJjVoSpxKAgAAAIAuBCIKSgL///9/Mh4D/////wAAAACRSgL///9/MgwDAAAAAAEAAACfcEU/aWgSv0BXAwMQcAAgiNsoStgkCUrKACAoAzpxOwwUEnB4JgQLcT16cnkmBBNwPXJ6JjVoSpxKAgAAAIAuBCIKSgL///9/Mh4D/////wAAAACRSgL///9/MgwDAAAAAAEAAACfcEVpcmrYJjVoSpxKAgAAAIAuBCIKSgL///9/Mh4D/////wAAAACRSgL///9/MgwDAAAAAAEAAACfcEU/aWgSv0BXAwMQcAwDMTIzcTsMFBJweCYEC3E9enJ5JgQTcD1yeiY1aEqcSgIAAACALgQiCkoC////fzIeA/////8AAAAAkUoC////fzIMAwAAAAABAAAAn3BFaXJq2CY1aEqcSgIAAACALgQiCkoC////fzIeA/////8AAAAAkUoC////fzIMAwAAAAABAAAAn3BFP2loEr9AVwIDEHA7CxMScHgmAzg9QXF5JgQTcD05eiY1aEqcSgIAAACALgQiCkoC////fzIeA/////8AAAAAkUoC////fzIMAwAAAAABAAAAn3BFP2hAqNPIkQ==")); + public static Neo.SmartContract.NefFile Nef => Neo.IO.Helper.AsSerializable(Convert.FromBase64String(@"TkVGM1Rlc3RpbmdFbmdpbmUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP1sCVcCAxBwOxYeEnB4Jg4MCWV4Y2VwdGlvbjo9QXF5JgQTcD05eiY1aEqcSgIAAACALgQiCkoC////fzIeA/////8AAAAAkUoC////fzIMAwAAAAABAAAAn3BFP2hAVwADenl4NJ5AVwIDEHA7DBQScHgmBDRFPUFxeSYEE3A9OXomNWhKnEoCAAAAgC4EIgpKAv///38yHgP/////AAAAAJFKAv///38yDAMAAAAAAQAAAJ9wRT9oQAwJZXhjZXB0aW9uOlcCBBBwO1QAOwwWEnB4JgQ05D1FcRNweSYENNo9O3omBDTTaEqcSgIAAACALgQiCkoC////fzIeA/////8AAAAAkUoC////fzIMAwAAAAABAAAAn3BFPz07cXsmNWhKnEoCAAAAgC4EIgpKAv///38yHgP/////AAAAAJFKAv///38yDAMAAAAAAQAAAJ9wRT0CaEBXAgMQcDsWKhFweCYODAlleGNlcHRpb246PRxxEnB5Jg4MCWV4Y2VwdGlvbjo9CHomBBNwPxRwaEBXAQIQcDsAFhJweCYODAlleGNlcHRpb246PTl5JjVoSpxKAgAAAIAuBCIKSgL///9/Mh4D/////wAAAACRSgL///9/MgwDAAAAAAEAAACfcEU/aEBXAQIQcDsADxJweCYHNcb+//89OXkmNWhKnEoCAAAAgC4EIgpKAv///38yHgP/////AAAAAJFKAv///38yDAMAAAAAAQAAAJ9wRT9oQFcCAhBwOw8AEnB4Jgc1ef7//z07cXkmNWhKnEoCAAAAgC4EIgpKAv///38yHgP/////AAAAAJFKAv///38yDAMAAAAAAQAAAJ9wRT0CaEBXAgYQcDzPAAAABwEAADtHf2hKnEoCAAAAgC4EIgpKAv///38yHgP/////AAAAAJFKAv///38yDAMAAAAAAQAAAJ9wRXgmDgwJZXhjZXB0aW9uOj1wcXomNGgSnkoCAAAAgC4EIgpKAv///38yHgP/////AAAAAJFKAv///38yDAMAAAAAAQAAAJ9wPTh8JjRoE55KAgAAAIAuBCIKSgL///9/Mh4D/////wAAAACRSgL///9/MgwDAAAAAAEAAACfcD95Jg4MCWV4Y2VwdGlvbjo9cHF7JjRoFJ5KAgAAAIAuBCIKSgL///9/Mh4D/////wAAAACRSgL///9/MgwDAAAAAAEAAACfcD04fSY0aBWeSgIAAACALgQiCkoC////fzIeA/////8AAAAAkUoC////fzIMAwAAAAABAAAAn3A/aEBXAgMQcDtDSxJweCYMDAYKCwwNDg8iJQwhAkcA2y6Q2fAsT5/IYqusqScl+VtP3cyNf/pThpPs9GOpStgkCUrKACEoAzpxPUFxeSYEE3A9OXomNWhKnEoCAAAAgC4EIgpKAv///38yHgP/////AAAAAJFKAv///38yDAMAAAAAAQAAAJ9wRT9oQFcCAhBwOzY+EnAMIQJHANsukNnwLE+fyGKrrKknJflbT93MjX/6U4aT7PRjqUrYJAlKygAhKAM6cT1BcXgmBBNwPTl5JjVoSpxKAgAAAIAuBCIKSgL///9/Mh4D/////wAAAACRSgL///9/MgwDAAAAAAEAAACfcEU/aEBXAgMQcDs2PhJweCYMDAYKCwwNDg8iGAwUfu4aq+tn7R15HUTk9fzzrpFxqHFK2CQJSsoAFCgDOnE9QXF5JgQTcD05eiY1aEqcSgIAAACALgQiCkoC////fzIeA/////8AAAAAkUoC////fzIMAwAAAAABAAAAn3BFP2hAVwICEHA7KTEScAwUfu4aq+tn7R15HUTk9fzzrpFxqHFK2CQJSsoAFCgDOnE9QXF4JgQTcD05eSY1aEqcSgIAAACALgQiCkoC////fzIeA/////8AAAAAkUoC////fzIMAwAAAAABAAAAn3BFP2hAVwIDEHA7QEgScHgmFQwGCgsMDQ4PStgkK0rKACAoJToMIO3PhnkQTsKRGk/imtfbIypJPluZD7HaevDHuYmUjIklcT1BcXkmBBNwPTl6JjVoSpxKAgAAAIAuBCIKSgL///9/Mh4D/////wAAAACRSgL///9/MgwDAAAAAAEAAACfcEU/aEBXAgIQcDsqMhJwDCDtz4Z5EE7CkRpP4prX2yMqST5bmQ+x2nrwx7mJlIyJJXE9QXF4JgQTcD05eSY1aEqcSgIAAACALgQiCkoC////fzIeA/////8AAAAAkUoC////fzIMAwAAAAABAAAAn3BFP2hAVwMDEHAAIYjbKErYJAlKygAhKAM6cTsMFBJweCYEC3E9enJ5JgQTcD1yeiY1aEqcSgIAAACALgQiCkoC////fzIeA/////8AAAAAkUoC////fzIMAwAAAAABAAAAn3BFaXJq2CY1aEqcSgIAAACALgQiCkoC////fzIeA/////8AAAAAkUoC////fzIMAwAAAAABAAAAn3BFP2loEr9AVwMDEHAAFIjbKErYJAlKygAUKAM6cTsMFBJweCYEC3E9enJ5JgQTcD1yeiY1aEqcSgIAAACALgQiCkoC////fzIeA/////8AAAAAkUoC////fzIMAwAAAAABAAAAn3BFaXJq2CY1aEqcSgIAAACALgQiCkoC////fzIeA/////8AAAAAkUoC////fzIMAwAAAAABAAAAn3BFP2loEr9AVwMDEHAAIIjbKErYJAlKygAgKAM6cTsMFBJweCYEC3E9enJ5JgQTcD1yeiY1aEqcSgIAAACALgQiCkoC////fzIeA/////8AAAAAkUoC////fzIMAwAAAAABAAAAn3BFaXJq2CY1aEqcSgIAAACALgQiCkoC////fzIeA/////8AAAAAkUoC////fzIMAwAAAAABAAAAn3BFP2loEr9AVwMDEHAMAzEyM3E7DBQScHgmBAtxPXpyeSYEE3A9cnomNWhKnEoCAAAAgC4EIgpKAv///38yHgP/////AAAAAJFKAv///38yDAMAAAAAAQAAAJ9wRWlyatgmNWhKnEoCAAAAgC4EIgpKAv///38yHgP/////AAAAAJFKAv///38yDAMAAAAAAQAAAJ9wRT9paBK/QFcCAxBwOwsTEnB4JgM4PUFxeSYEE3A9OXomNWhKnEoCAAAAgC4EIgpKAv///38yHgP/////AAAAAJFKAv///38yDAMAAAAAAQAAAJ9wRT9oQM+f6pI=")); #endregion @@ -138,17 +138,16 @@ public abstract class Contract_TryCatch(Neo.SmartContract.Testing.SmartContractI /// Unsafe method /// /// - /// Script: VwIDEHA7DRUScHgmBTRGRT1BcXkmBBNwPTl6JjVoSpxKAgAAAIAuBCIKSgL///9/Mh4D/////wAAAACRSgL///9/MgwDAAAAAAEAAACfcEU/aEA= + /// Script: VwIDEHA7DBQScHgmBDRFPUFxeSYEE3A9OXomNWhKnEoCAAAAgC4EIgpKAv///38yHgP/////AAAAAJFKAv///38yDAMAAAAAAQAAAJ9wRT9oQA== /// INITSLOT 0203 [64 datoshi] /// PUSH0 [1 datoshi] /// STLOC0 [2 datoshi] - /// TRY 0D15 [4 datoshi] + /// TRY 0C14 [4 datoshi] /// PUSH2 [1 datoshi] /// STLOC0 [2 datoshi] /// LDARG0 [2 datoshi] - /// JMPIFNOT 05 [2 datoshi] - /// CALL 46 [512 datoshi] - /// DROP [2 datoshi] + /// JMPIFNOT 04 [2 datoshi] + /// CALL 45 [512 datoshi] /// ENDTRY 41 [4 datoshi] /// STLOC1 [2 datoshi] /// LDARG1 [2 datoshi] @@ -188,17 +187,16 @@ public abstract class Contract_TryCatch(Neo.SmartContract.Testing.SmartContractI /// Unsafe method /// /// - /// Script: VwICEHA7EAAScHgmCDV2/v//RT07cXkmNWhKnEoCAAAAgC4EIgpKAv///38yHgP/////AAAAAJFKAv///38yDAMAAAAAAQAAAJ9wRT0CaEA= + /// Script: VwICEHA7DwAScHgmBzV5/v//PTtxeSY1aEqcSgIAAACALgQiCkoC////fzIeA/////8AAAAAkUoC////fzIMAwAAAAABAAAAn3BFPQJoQA== /// INITSLOT 0202 [64 datoshi] /// PUSH0 [1 datoshi] /// STLOC0 [2 datoshi] - /// TRY 1000 [4 datoshi] + /// TRY 0F00 [4 datoshi] /// PUSH2 [1 datoshi] /// STLOC0 [2 datoshi] /// LDARG0 [2 datoshi] - /// JMPIFNOT 08 [2 datoshi] - /// CALL_L 76FEFFFF [512 datoshi] - /// DROP [2 datoshi] + /// JMPIFNOT 07 [2 datoshi] + /// CALL_L 79FEFFFF [512 datoshi] /// ENDTRY 3B [4 datoshi] /// STLOC1 [2 datoshi] /// LDARG1 [2 datoshi] @@ -337,17 +335,16 @@ public abstract class Contract_TryCatch(Neo.SmartContract.Testing.SmartContractI /// Unsafe method /// /// - /// Script: VwECEHA7ABAScHgmCDXE/v//RT05eSY1aEqcSgIAAACALgQiCkoC////fzIeA/////8AAAAAkUoC////fzIMAwAAAAABAAAAn3BFP2hA + /// Script: VwECEHA7AA8ScHgmBzXG/v//PTl5JjVoSpxKAgAAAIAuBCIKSgL///9/Mh4D/////wAAAACRSgL///9/MgwDAAAAAAEAAACfcEU/aEA= /// INITSLOT 0102 [64 datoshi] /// PUSH0 [1 datoshi] /// STLOC0 [2 datoshi] - /// TRY 0010 [4 datoshi] + /// TRY 000F [4 datoshi] /// PUSH2 [1 datoshi] /// STLOC0 [2 datoshi] /// LDARG0 [2 datoshi] - /// JMPIFNOT 08 [2 datoshi] - /// CALL_L C4FEFFFF [512 datoshi] - /// DROP [2 datoshi] + /// JMPIFNOT 07 [2 datoshi] + /// CALL_L C6FEFFFF [512 datoshi] /// ENDTRY 39 [4 datoshi] /// LDARG1 [2 datoshi] /// JMPIFNOT 35 [2 datoshi] @@ -500,30 +497,28 @@ public abstract class Contract_TryCatch(Neo.SmartContract.Testing.SmartContractI /// Unsafe method /// /// - /// Script: VwIEEHA7VgA7DRgScHgmBTTkRT1GcRNweSYFNNlFPTt6JgQ00WhKnEoCAAAAgC4EIgpKAv///38yHgP/////AAAAAJFKAv///38yDAMAAAAAAQAAAJ9wRT89O3F7JjVoSpxKAgAAAIAuBCIKSgL///9/Mh4D/////wAAAACRSgL///9/MgwDAAAAAAEAAACfcEU9AmhA + /// Script: VwIEEHA7VAA7DBYScHgmBDTkPUVxE3B5JgQ02j07eiYENNNoSpxKAgAAAIAuBCIKSgL///9/Mh4D/////wAAAACRSgL///9/MgwDAAAAAAEAAACfcEU/PTtxeyY1aEqcSgIAAACALgQiCkoC////fzIeA/////8AAAAAkUoC////fzIMAwAAAAABAAAAn3BFPQJoQA== /// INITSLOT 0204 [64 datoshi] /// PUSH0 [1 datoshi] /// STLOC0 [2 datoshi] - /// TRY 5600 [4 datoshi] - /// TRY 0D18 [4 datoshi] + /// TRY 5400 [4 datoshi] + /// TRY 0C16 [4 datoshi] /// PUSH2 [1 datoshi] /// STLOC0 [2 datoshi] /// LDARG0 [2 datoshi] - /// JMPIFNOT 05 [2 datoshi] + /// JMPIFNOT 04 [2 datoshi] /// CALL E4 [512 datoshi] - /// DROP [2 datoshi] - /// ENDTRY 46 [4 datoshi] + /// ENDTRY 45 [4 datoshi] /// STLOC1 [2 datoshi] /// PUSH3 [1 datoshi] /// STLOC0 [2 datoshi] /// LDARG1 [2 datoshi] - /// JMPIFNOT 05 [2 datoshi] - /// CALL D9 [512 datoshi] - /// DROP [2 datoshi] + /// JMPIFNOT 04 [2 datoshi] + /// CALL DA [512 datoshi] /// ENDTRY 3B [4 datoshi] /// LDARG2 [2 datoshi] /// JMPIFNOT 04 [2 datoshi] - /// CALL D1 [512 datoshi] + /// CALL D3 [512 datoshi] /// LDLOC0 [2 datoshi] /// DUP [2 datoshi] /// INC [4 datoshi] diff --git a/tests/Neo.Compiler.CSharp.UnitTests/UnitTest_Break.cs b/tests/Neo.Compiler.CSharp.UnitTests/UnitTest_Break.cs new file mode 100644 index 000000000..f76a24893 --- /dev/null +++ b/tests/Neo.Compiler.CSharp.UnitTests/UnitTest_Break.cs @@ -0,0 +1,16 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.SmartContract.Testing; +using System.Collections.Generic; + +namespace Neo.Compiler.CSharp.UnitTests +{ + [TestClass] + public class UnitTest_Break : DebugAndTestBase + { + [TestMethod] + public void TestBreakInTry() + { + Contract.BreakInTryCatch(); + } + } +} From 1eceb0065c4edb2e2d42c8649399f265e6346969 Mon Sep 17 00:00:00 2001 From: Hecate2 <2474101468@qq.com> Date: Thu, 16 Jan 2025 12:46:46 +0800 Subject: [PATCH 2/4] break from multiple try --- .../MethodConvert/Statement/BreakStatement.cs | 47 ++++++----- .../Statement/CommonForEachStatement.cs | 8 +- .../MethodConvert/Statement/DoStatement.cs | 2 +- .../MethodConvert/Statement/ForStatement.cs | 2 +- .../MethodConvert/Statement/Statement.cs | 28 ++++++- .../Statement/SwitchStatement.cs | 2 +- .../MethodConvert/Statement/TryStatement.cs | 12 ++- .../MethodConvert/Statement/WhileStatement.cs | 2 +- .../Contract_Break.cs | 24 ++++-- .../TestingArtifacts/Contract_Break.cs | 81 +++++++++++++------ 10 files changed, 146 insertions(+), 62 deletions(-) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Statement/BreakStatement.cs b/src/Neo.Compiler.CSharp/MethodConvert/Statement/BreakStatement.cs index 7c1299fba..3c0ca34a2 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Statement/BreakStatement.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Statement/BreakStatement.cs @@ -10,6 +10,8 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Neo.VM; +using System.Collections.Generic; +using System.Linq; namespace Neo.Compiler { @@ -45,31 +47,36 @@ private void ConvertBreakStatement(BreakStatementSyntax syntax) { using (InsertSequencePoint(syntax)) { - int nestedTryWithFinally = 0; + JumpTarget? breakTarget = null; + List visitedTry = []; // from shallow to deep foreach (StatementContext sc in _generalStatementStack) - { + {// start from the deepest context + // find the final break target if (sc.BreakTarget != null) { - if (nestedTryWithFinally == 0) - Jump(OpCode.JMP_L, sc.BreakTarget); - else - Jump(OpCode.ENDTRY_L, sc.BreakTarget); - return; - } - if (sc.StatementSyntax is TryStatementSyntax && sc.FinallyTarget != null) - { - if (nestedTryWithFinally > 0) - throw new CompilationException(sc.StatementSyntax, DiagnosticId.SyntaxNotSupported, "Neo VM does not support `break` from multi-layered nested try-catch with finally."); - if (sc.TryState != ExceptionHandlingState.Finally) - nestedTryWithFinally++; - else // Not likely to happen. C# syntax analyzer should forbid break in finally - throw new CompilationException(sc.StatementSyntax, DiagnosticId.SyntaxNotSupported, "Cannot break in finally."); + breakTarget = sc.BreakTarget; + break; } + // stage the try stacks on the way + if (sc.StatementSyntax is TryStatementSyntax) + visitedTry.Add(sc); } - // break is not handled - throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Cannot find what to break. " + - $"If not syntax error, this is probably a compiler bug. " + - $"Check whether the compiler is leaving out a push into {nameof(_generalStatementStack)}."); + if (breakTarget == null) + // break is not handled + throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Cannot find what to break. " + + $"If not syntax error, this is probably a compiler bug. " + + $"Check whether the compiler is leaving out a push into {nameof(_generalStatementStack)}."); + + foreach (StatementContext sc in visitedTry) + // start from the most external try + // internal try should ENDTRY, targeting the correct external break target + breakTarget = sc.AddEndTry(breakTarget); + + Jump(OpCode.JMP_L, breakTarget); + // We could use ENDTRY if current statement calling `break` is a try statement, + // but this job can be done by the optimizer + // Note that, do not Jump(OpCode.ENDTRY_L, breakTarget) here, + // because the breakTarget here is already an ENDTRY_L for current try stack. } } } diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Statement/CommonForEachStatement.cs b/src/Neo.Compiler.CSharp/MethodConvert/Statement/CommonForEachStatement.cs index dea86ada5..c4c2237ce 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Statement/CommonForEachStatement.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Statement/CommonForEachStatement.cs @@ -100,7 +100,7 @@ private void ConvertIteratorForEachStatement(SemanticModel model, ForEachStateme PopContinueTarget(); PopBreakTarget(); if (_generalStatementStack.Pop() != sc) - throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Bad statement stack handling inside."); + throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Bad statement stack handling inside. This is a compiler bug."); } /// @@ -197,7 +197,7 @@ private void ConvertIteratorForEachVariableStatement(SemanticModel model, ForEac PopContinueTarget(); PopBreakTarget(); if (_generalStatementStack.Pop() != sc) - throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Bad statement stack handling inside."); + throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Bad statement stack handling inside. This is a compiler bug."); } /// @@ -266,7 +266,7 @@ private void ConvertArrayForEachStatement(SemanticModel model, ForEachStatementS PopContinueTarget(); PopBreakTarget(); if (_generalStatementStack.Pop() != sc) - throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Bad statement stack handling inside."); + throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Bad statement stack handling inside. This is a compiler bug."); } /// @@ -349,7 +349,7 @@ private void ConvertArrayForEachVariableStatement(SemanticModel model, ForEachVa PopContinueTarget(); PopBreakTarget(); if (_generalStatementStack.Pop() != sc) - throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Bad statement stack handling inside."); + throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Bad statement stack handling inside. This is a compiler bug."); } } } diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Statement/DoStatement.cs b/src/Neo.Compiler.CSharp/MethodConvert/Statement/DoStatement.cs index 61ef83c92..bd2057aa2 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Statement/DoStatement.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Statement/DoStatement.cs @@ -59,7 +59,7 @@ private void ConvertDoStatement(SemanticModel model, DoStatementSyntax syntax) PopContinueTarget(); PopBreakTarget(); if (_generalStatementStack.Pop() != sc) - throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Bad statement stack handling inside."); + throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Bad statement stack handling inside. This is a compiler bug."); } } } diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Statement/ForStatement.cs b/src/Neo.Compiler.CSharp/MethodConvert/Statement/ForStatement.cs index bcb344c5b..ae47e9abc 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Statement/ForStatement.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Statement/ForStatement.cs @@ -102,7 +102,7 @@ private void ConvertForStatement(SemanticModel model, ForStatementSyntax syntax) PopContinueTarget(); PopBreakTarget(); if (_generalStatementStack.Pop() != sc) - throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Bad statement stack handling inside."); + throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Bad statement stack handling inside. This is a compiler bug."); } } } diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Statement/Statement.cs b/src/Neo.Compiler.CSharp/MethodConvert/Statement/Statement.cs index bc1ddf548..1997e0657 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Statement/Statement.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Statement/Statement.cs @@ -11,7 +11,9 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Neo.VM; +using Org.BouncyCastle.Asn1.X509; using System.Collections.Generic; +using System.Linq; namespace Neo.Compiler { @@ -39,19 +41,37 @@ internal class StatementContext(StatementSyntax statementSyntax, public readonly JumpTarget? EndFinallyTarget = endFinallyTarget; public /*readonly*/ Dictionary? GotoLabels = gotoLabels; public /*readonly*/ Dictionary? SwitchLabels = switchLabels; + // handles `break`, `continue` and `goto` in multi-layered nested try with finally + // key: target of this ENDTRY + // value: this ENDTRY + public Dictionary? AdditionalEndTryTargetToInstruction { get; protected set; } = null; //public readonly StatementSyntax? ParentStatement = parentStatement; //public readonly HashSet? ChildrenStatements = childrenStatements; + /// Jump target of this added ENDTRY + /// The added ENDTRY + /// + public JumpTarget AddEndTry(JumpTarget target) + { + if (StatementSyntax is not TryStatementSyntax) + throw new CompilationException(StatementSyntax, DiagnosticId.SyntaxNotSupported, $"Can only append ENDTRY for TryStatement. Got {typeof(StatementSyntax)} {StatementSyntax}. This is a compiler bug."); + AdditionalEndTryTargetToInstruction ??= []; + if (AdditionalEndTryTargetToInstruction.TryGetValue(target, out JumpTarget? existingEndTry)) + return existingEndTry; + Instruction i = new() { OpCode = OpCode.ENDTRY_L, Target = target }; + existingEndTry = new JumpTarget() { Instruction = i }; + AdditionalEndTryTargetToInstruction.Add(target, existingEndTry); + return existingEndTry; + } + public bool AddLabel(ILabelSymbol label, JumpTarget target) { - if (GotoLabels == null) - GotoLabels = []; + GotoLabels ??= []; return GotoLabels.TryAdd(label, target); } public bool AddLabel(SwitchLabelSyntax label, JumpTarget target) { - if (SwitchLabels == null) - SwitchLabels = []; + SwitchLabels ??= []; return SwitchLabels.TryAdd(label, target); } public bool ContainsLabel(ILabelSymbol label) => GotoLabels is not null && GotoLabels.ContainsKey(label); diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Statement/SwitchStatement.cs b/src/Neo.Compiler.CSharp/MethodConvert/Statement/SwitchStatement.cs index d62585e92..52f985782 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Statement/SwitchStatement.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Statement/SwitchStatement.cs @@ -114,7 +114,7 @@ private void ConvertSwitchStatement(SemanticModel model, SwitchStatementSyntax s PopSwitchLabels(); PopBreakTarget(); if (_generalStatementStack.Pop() != sc) - throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Bad statement stack handling inside."); + throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Bad statement stack handling inside. This is a compiler bug."); } } } diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Statement/TryStatement.cs b/src/Neo.Compiler.CSharp/MethodConvert/Statement/TryStatement.cs index 020dc6a30..6f19b30c3 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Statement/TryStatement.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Statement/TryStatement.cs @@ -59,6 +59,11 @@ private void ConvertTryStatement(SemanticModel model, TryStatementSyntax syntax) _tryStack.Push(new ExceptionHandling { State = ExceptionHandlingState.Try }); ConvertStatement(model, syntax.Block); Jump(OpCode.ENDTRY_L, endTarget); + if (syntax.Catches.Count == 0 && sc.AdditionalEndTryTargetToInstruction != null) + // handles `break`, `continue` and `goto` in multi-layered nested try with finally + foreach (JumpTarget i in sc.AdditionalEndTryTargetToInstruction.Values) + AddInstruction(i.Instruction!); + if (syntax.Catches.Count > 1) throw new CompilationException(syntax.Catches[1], DiagnosticId.MultiplyCatches, "Only support one single catch."); if (syntax.Catches.Count > 0) @@ -86,6 +91,11 @@ private void ConvertTryStatement(SemanticModel model, TryStatementSyntax syntax) _exceptionStack.Push(exceptionIndex); ConvertStatement(model, catchClause.Block); Jump(OpCode.ENDTRY_L, endTarget); + if (sc.AdditionalEndTryTargetToInstruction != null) + // handles `break`, `continue` and `goto` in multi-layered nested try with finally + foreach (JumpTarget i in sc.AdditionalEndTryTargetToInstruction.Values) + AddInstruction(i.Instruction!); + if (exceptionSymbol is null) RemoveAnonymousVariable(exceptionIndex); else @@ -103,7 +113,7 @@ private void ConvertTryStatement(SemanticModel model, TryStatementSyntax syntax) endTarget.Instruction = AddInstruction(OpCode.NOP); _tryStack.Pop(); if (_generalStatementStack.Pop() != sc) - throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Bad statement stack handling inside."); + throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Bad statement stack handling inside. This is a compiler bug."); } } } diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Statement/WhileStatement.cs b/src/Neo.Compiler.CSharp/MethodConvert/Statement/WhileStatement.cs index 9c226a86b..2643515cd 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Statement/WhileStatement.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Statement/WhileStatement.cs @@ -59,7 +59,7 @@ private void ConvertWhileStatement(SemanticModel model, WhileStatementSyntax syn PopContinueTarget(); PopBreakTarget(); if (_generalStatementStack.Pop() != sc) - throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Bad statement stack handling inside."); + throw new CompilationException(syntax, DiagnosticId.SyntaxNotSupported, $"Bad statement stack handling inside. This is a compiler bug."); } } } diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Break.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Break.cs index 9ff7792af..25134c1ba 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Break.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Break.cs @@ -14,13 +14,17 @@ public static void BreakInTryCatch() finally { Storage.Put("\xff\x00", "\x01"); } ExecutionEngine.Assert(Storage.Get("\xff\x00")! == "\x01"); foreach (object i in Storage.Find("\xff")) - try { throw new System.Exception(); } + try + { + for (int j = 0; j < 3;) + throw new System.Exception(); + } catch { do { break; } while (true); - Storage.Put("\xff\x00", "\x00"); - break; // break foreach; should execute finally + try { break; } // break foreach; should execute finally + finally { Storage.Put("\xff\x00", "\x00"); } } finally { @@ -37,14 +41,24 @@ public static void BreakInTryCatch() { for (int j = 0; j < 3;) break; - throw new System.Exception(); } catch { int j = 0; while (j < 3) break; - break; // foreach; should execute finally + ExecutionEngine.Assert(j == 0); + try + { + Storage.Put("\xff\x00", "\x03"); + throw; + } + catch { break; } // foreach; should execute finally + finally + { + ExecutionEngine.Assert(Storage.Get("\xff\x00")! == "\x03"); + Storage.Put("\xff\x00", "\x02"); + } } finally { diff --git a/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Break.cs b/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Break.cs index 306a105ff..ac164ec9a 100644 --- a/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Break.cs +++ b/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Break.cs @@ -15,7 +15,7 @@ public abstract class Contract_Break(Neo.SmartContract.Testing.SmartContractInit /// /// Optimization: "All" /// - public static Neo.SmartContract.NefFile Nef => Neo.IO.Helper.AsSerializable(Convert.FromBase64String(@"TkVGM1Rlc3RpbmdFbmdpbmUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP1DAVcGAAwBAAwC/wA1CgEAABAMAf81EQEAAHAiG2hB81S/HXE7AAU9FwwBAQwC/wA15gAAAD9oQZwI7Zwk4QwC/wA19AAAAAwBAZc5EAwB/zXWAAAAcCJWaEHzVL8dcTsPHgwJZXhjZXB0aW9uOnIMAQAMAv8ANaAAAAA9OQwC/wA1tQAAAAwBAJc5EhEQE8BKcspzEHQiEWpsznUMAQIMAv8ANHMiBmxrMO8/aEGcCO2cJKYMAv8ANH4MAQKXORAMAf80Y3AiPGhB81S/HXE7FR4QcmoTtUUMCWV4Y2VwdGlvbjpyEHNrE7VFPR8MAv8ANEUMAQKXOQwBAwwC/wA0Fz9oQZwI7ZwkwAwC/wA0KAwBA5c5QFcAAnl4QZv2Z85B5j8YhEBXAAJ5eEH2tGviQd8wuJpAVwABeEH2tGviQZJd6DFAEImfDw==")); + public static Neo.SmartContract.NefFile Nef => Neo.IO.Helper.AsSerializable(Convert.FromBase64String(@"TkVGM1Rlc3RpbmdFbmdpbmUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP2BAVcGAAwBAAwC/wA1SAEAABAMAf81TwEAAHAiG2hB81S/HXE7AAU9FwwBAQwC/wA1JAEAAD9oQZwI7Zwk4QwC/wA1MgEAAAwBAZc5EAwB/zUUAQAAcCJsaEHzVL8dcTsaMRByIg4MCWV4Y2VwdGlvbjpqE7Uk8T1LcjsAByIRPUsMAQAMAv8ANcwAAAA/PfEMAv8ANeAAAAAMAQCXORIREBPASnLKcxB0IhRqbM51DAECDAL/ADWeAAAAIgZsazDsP2hBnAjtnCSQDAL/ADWmAAAADAEClzkQDAH/NYgAAABwIl5oQfNUvx1xOwtAEHJqE7VFPUxyEHNrE7VFaxCXOTsOEwwBAwwC/wA0SWo6dCIZPTYMAv8ANFwMAQOXOQwBAgwC/wA0Lj896QwC/wA0RQwBApc5DAEDDAL/ADQXP2hBnAjtnCSeDAL/ADQoDAEDlzlAVwACeXhBm/ZnzkHmPxiEQFcAAnl4Qfa0a+JB3zC4mkBXAAF4Qfa0a+JBkl3oMUB6sNlU")); #endregion @@ -25,14 +25,14 @@ public abstract class Contract_Break(Neo.SmartContract.Testing.SmartContractInit /// Unsafe method /// /// - /// Script: VwYADAEADAL/ADUKAQAAEAwB/zURAQAAcCIbaEHzVL8dcTsABT0XDAEBDAL/ADXmAAAAP2hBnAjtnCThDAL/ADX0AAAADAEBlzkQDAH/NdYAAABwIlZoQfNUvx1xOw8eDAlleGNlcHRpb246cgwBAAwC/wA1oAAAAD05DAL/ADW1AAAADAEAlzkSERATwEpyynMQdCIRamzOdQwBAgwC/wA0cyIGbGsw7z9oQZwI7ZwkpgwC/wA0fgwBApc5EAwB/zRjcCI8aEHzVL8dcTsVHhByahO1RQwJZXhjZXB0aW9uOnIQc2sTtUU9HwwC/wA0RQwBApc5DAEDDAL/ADQXP2hBnAjtnCTADAL/ADQoDAEDlzlA + /// Script: VwYADAEADAL/ADVIAQAAEAwB/zVPAQAAcCIbaEHzVL8dcTsABT0XDAEBDAL/ADUkAQAAP2hBnAjtnCThDAL/ADUyAQAADAEBlzkQDAH/NRQBAABwImxoQfNUvx1xOxoxEHIiDgwJZXhjZXB0aW9uOmoTtSTxPUtyOwAHIhE9SwwBAAwC/wA1zAAAAD898QwC/wA14AAAAAwBAJc5EhEQE8BKcspzEHQiFGpsznUMAQIMAv8ANZ4AAAAiBmxrMOw/aEGcCO2cJJAMAv8ANaYAAAAMAQKXORAMAf81iAAAAHAiXmhB81S/HXE7C0AQcmoTtUU9THIQc2sTtUVrEJc5Ow4TDAEDDAL/ADRJajp0Ihk9NgwC/wA0XAwBA5c5DAECDAL/ADQuPz3pDAL/ADRFDAEClzkMAQMMAv8ANBc/aEGcCO2cJJ4MAv8ANCgMAQOXOUA= /// INITSLOT 0600 [64 datoshi] /// PUSHDATA1 00 [8 datoshi] /// PUSHDATA1 FF00 [8 datoshi] - /// CALL_L 0A010000 [512 datoshi] + /// CALL_L 48010000 [512 datoshi] /// PUSH0 [1 datoshi] /// PUSHDATA1 FF '?' [8 datoshi] - /// CALL_L 11010000 [512 datoshi] + /// CALL_L 4F010000 [512 datoshi] /// STLOC0 [2 datoshi] /// JMP 1B [2 datoshi] /// LDLOC0 [2 datoshi] @@ -42,34 +42,46 @@ public abstract class Contract_Break(Neo.SmartContract.Testing.SmartContractInit /// ENDTRY 17 [4 datoshi] /// PUSHDATA1 01 [8 datoshi] /// PUSHDATA1 FF00 [8 datoshi] - /// CALL_L E6000000 [512 datoshi] + /// CALL_L 24010000 [512 datoshi] /// ENDFINALLY [4 datoshi] /// LDLOC0 [2 datoshi] /// SYSCALL 9C08ED9C 'System.Iterator.Next' [32768 datoshi] /// JMPIF E1 [2 datoshi] /// PUSHDATA1 FF00 [8 datoshi] - /// CALL_L F4000000 [512 datoshi] + /// CALL_L 32010000 [512 datoshi] /// PUSHDATA1 01 [8 datoshi] /// EQUAL [32 datoshi] /// ASSERT [1 datoshi] /// PUSH0 [1 datoshi] /// PUSHDATA1 FF '?' [8 datoshi] - /// CALL_L D6000000 [512 datoshi] + /// CALL_L 14010000 [512 datoshi] /// STLOC0 [2 datoshi] - /// JMP 56 [2 datoshi] + /// JMP 6C [2 datoshi] /// LDLOC0 [2 datoshi] /// SYSCALL F354BF1D 'System.Iterator.Value' [16 datoshi] /// STLOC1 [2 datoshi] - /// TRY 0F1E [4 datoshi] + /// TRY 1A31 [4 datoshi] + /// PUSH0 [1 datoshi] + /// STLOC2 [2 datoshi] + /// JMP 0E [2 datoshi] /// PUSHDATA1 657863657074696F6E 'exception' [8 datoshi] /// THROW [512 datoshi] + /// LDLOC2 [2 datoshi] + /// PUSH3 [1 datoshi] + /// LT [8 datoshi] + /// JMPIF F1 [2 datoshi] + /// ENDTRY 4B [4 datoshi] /// STLOC2 [2 datoshi] + /// TRY 0007 [4 datoshi] + /// JMP 11 [2 datoshi] + /// ENDTRY 4B [4 datoshi] /// PUSHDATA1 00 [8 datoshi] /// PUSHDATA1 FF00 [8 datoshi] - /// CALL_L A0000000 [512 datoshi] - /// ENDTRY 39 [4 datoshi] + /// CALL_L CC000000 [512 datoshi] + /// ENDFINALLY [4 datoshi] + /// ENDTRY F1 [4 datoshi] /// PUSHDATA1 FF00 [8 datoshi] - /// CALL_L B5000000 [512 datoshi] + /// CALL_L E0000000 [512 datoshi] /// PUSHDATA1 00 [8 datoshi] /// EQUAL [32 datoshi] /// ASSERT [1 datoshi] @@ -84,44 +96,43 @@ public abstract class Contract_Break(Neo.SmartContract.Testing.SmartContractInit /// STLOC3 [2 datoshi] /// PUSH0 [1 datoshi] /// STLOC4 [2 datoshi] - /// JMP 11 [2 datoshi] + /// JMP 14 [2 datoshi] /// LDLOC2 [2 datoshi] /// LDLOC4 [2 datoshi] /// PICKITEM [64 datoshi] /// STLOC5 [2 datoshi] /// PUSHDATA1 02 [8 datoshi] /// PUSHDATA1 FF00 [8 datoshi] - /// CALL 73 [512 datoshi] + /// CALL_L 9E000000 [512 datoshi] /// JMP 06 [2 datoshi] /// LDLOC4 [2 datoshi] /// LDLOC3 [2 datoshi] - /// JMPLT EF [2 datoshi] + /// JMPLT EC [2 datoshi] /// ENDFINALLY [4 datoshi] /// LDLOC0 [2 datoshi] /// SYSCALL 9C08ED9C 'System.Iterator.Next' [32768 datoshi] - /// JMPIF A6 [2 datoshi] + /// JMPIF 90 [2 datoshi] /// PUSHDATA1 FF00 [8 datoshi] - /// CALL 7E [512 datoshi] + /// CALL_L A6000000 [512 datoshi] /// PUSHDATA1 02 [8 datoshi] /// EQUAL [32 datoshi] /// ASSERT [1 datoshi] /// PUSH0 [1 datoshi] /// PUSHDATA1 FF '?' [8 datoshi] - /// CALL 63 [512 datoshi] + /// CALL_L 88000000 [512 datoshi] /// STLOC0 [2 datoshi] - /// JMP 3C [2 datoshi] + /// JMP 5E [2 datoshi] /// LDLOC0 [2 datoshi] /// SYSCALL F354BF1D 'System.Iterator.Value' [16 datoshi] /// STLOC1 [2 datoshi] - /// TRY 151E [4 datoshi] + /// TRY 0B40 [4 datoshi] /// PUSH0 [1 datoshi] /// STLOC2 [2 datoshi] /// LDLOC2 [2 datoshi] /// PUSH3 [1 datoshi] /// LT [8 datoshi] /// DROP [2 datoshi] - /// PUSHDATA1 657863657074696F6E 'exception' [8 datoshi] - /// THROW [512 datoshi] + /// ENDTRY 4C [4 datoshi] /// STLOC2 [2 datoshi] /// PUSH0 [1 datoshi] /// STLOC3 [2 datoshi] @@ -129,7 +140,29 @@ public abstract class Contract_Break(Neo.SmartContract.Testing.SmartContractInit /// PUSH3 [1 datoshi] /// LT [8 datoshi] /// DROP [2 datoshi] - /// ENDTRY 1F [4 datoshi] + /// LDLOC3 [2 datoshi] + /// PUSH0 [1 datoshi] + /// EQUAL [32 datoshi] + /// ASSERT [1 datoshi] + /// TRY 0E13 [4 datoshi] + /// PUSHDATA1 03 [8 datoshi] + /// PUSHDATA1 FF00 [8 datoshi] + /// CALL 49 [512 datoshi] + /// LDLOC2 [2 datoshi] + /// THROW [512 datoshi] + /// STLOC4 [2 datoshi] + /// JMP 19 [2 datoshi] + /// ENDTRY 36 [4 datoshi] + /// PUSHDATA1 FF00 [8 datoshi] + /// CALL 5C [512 datoshi] + /// PUSHDATA1 03 [8 datoshi] + /// EQUAL [32 datoshi] + /// ASSERT [1 datoshi] + /// PUSHDATA1 02 [8 datoshi] + /// PUSHDATA1 FF00 [8 datoshi] + /// CALL 2E [512 datoshi] + /// ENDFINALLY [4 datoshi] + /// ENDTRY E9 [4 datoshi] /// PUSHDATA1 FF00 [8 datoshi] /// CALL 45 [512 datoshi] /// PUSHDATA1 02 [8 datoshi] @@ -141,7 +174,7 @@ public abstract class Contract_Break(Neo.SmartContract.Testing.SmartContractInit /// ENDFINALLY [4 datoshi] /// LDLOC0 [2 datoshi] /// SYSCALL 9C08ED9C 'System.Iterator.Next' [32768 datoshi] - /// JMPIF C0 [2 datoshi] + /// JMPIF 9E [2 datoshi] /// PUSHDATA1 FF00 [8 datoshi] /// CALL 28 [512 datoshi] /// PUSHDATA1 03 [8 datoshi] From e0ed16dc8c50bb7b848097a71ac5358db644b92c Mon Sep 17 00:00:00 2001 From: Hecate2 <2474101468@qq.com> Date: Thu, 16 Jan 2025 16:39:48 +0800 Subject: [PATCH 3/4] remove comments --- .../MethodConvert/Statement/LabeledStatement.cs | 1 - .../MethodConvert/Statement/Statement.cs | 12 +++--------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Statement/LabeledStatement.cs b/src/Neo.Compiler.CSharp/MethodConvert/Statement/LabeledStatement.cs index 4a94710f3..4f1855111 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Statement/LabeledStatement.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Statement/LabeledStatement.cs @@ -51,7 +51,6 @@ private void ConvertLabeledStatement(SemanticModel model, LabeledStatementSyntax instruction.OpCode = OpCode.JMP_L; target.Instruction = AddInstruction(OpCode.NOP); ConvertStatement(model, syntax.Statement); - //_generalStatementStack.Peek().AddLabel(symbol, target); } } } diff --git a/src/Neo.Compiler.CSharp/MethodConvert/Statement/Statement.cs b/src/Neo.Compiler.CSharp/MethodConvert/Statement/Statement.cs index 1997e0657..5f013fde5 100644 --- a/src/Neo.Compiler.CSharp/MethodConvert/Statement/Statement.cs +++ b/src/Neo.Compiler.CSharp/MethodConvert/Statement/Statement.cs @@ -11,9 +11,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Neo.VM; -using Org.BouncyCastle.Asn1.X509; using System.Collections.Generic; -using System.Linq; namespace Neo.Compiler { @@ -28,25 +26,21 @@ internal class StatementContext(StatementSyntax statementSyntax, JumpTarget? catchTarget = null, JumpTarget? finallyTarget = null, JumpTarget? endFinallyTarget = null, Dictionary? gotoLabels = null, Dictionary? switchLabels = null - //StatementSyntax? parentStatement = null, - //HashSet? childrenStatements = null ) { public readonly StatementSyntax StatementSyntax = statementSyntax; public readonly JumpTarget? BreakTarget = breakTarget; public readonly JumpTarget? ContinueTarget = continueTarget; - public /*readonly*/ ExceptionHandlingState? TryState = tryState; + public ExceptionHandlingState? TryState = tryState; public readonly JumpTarget? CatchTarget = catchTarget; public readonly JumpTarget? FinallyTarget = finallyTarget; public readonly JumpTarget? EndFinallyTarget = endFinallyTarget; - public /*readonly*/ Dictionary? GotoLabels = gotoLabels; - public /*readonly*/ Dictionary? SwitchLabels = switchLabels; + public Dictionary? GotoLabels = gotoLabels; + public Dictionary? SwitchLabels = switchLabels; // handles `break`, `continue` and `goto` in multi-layered nested try with finally // key: target of this ENDTRY // value: this ENDTRY public Dictionary? AdditionalEndTryTargetToInstruction { get; protected set; } = null; - //public readonly StatementSyntax? ParentStatement = parentStatement; - //public readonly HashSet? ChildrenStatements = childrenStatements; /// Jump target of this added ENDTRY /// The added ENDTRY From 4dca04572a8292806918a49f9d0b52dbbbcf7193 Mon Sep 17 00:00:00 2001 From: Hecate2 <2474101468@qq.com> Date: Thu, 16 Jan 2025 16:48:52 +0800 Subject: [PATCH 4/4] control exception in test --- .../Contract_Break.cs | 4 +- .../TestingArtifacts/Contract_Break.cs | 40 ++++++++++--------- .../UnitTest_Break.cs | 3 +- 3 files changed, 27 insertions(+), 20 deletions(-) diff --git a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Break.cs b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Break.cs index 25134c1ba..7da9fe9fb 100644 --- a/tests/Neo.Compiler.CSharp.TestContracts/Contract_Break.cs +++ b/tests/Neo.Compiler.CSharp.TestContracts/Contract_Break.cs @@ -6,7 +6,7 @@ namespace Neo.Compiler.CSharp.TestContracts { public class Contract_Break : SmartContract.Framework.SmartContract { - public static void BreakInTryCatch() + public static void BreakInTryCatch(bool exception) { Storage.Put("\xff\x00", "\x00"); foreach (object i in Storage.Find("\xff")) @@ -41,6 +41,8 @@ public static void BreakInTryCatch() { for (int j = 0; j < 3;) break; + if (exception) + throw new System.Exception(); } catch { diff --git a/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Break.cs b/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Break.cs index ac164ec9a..155585a34 100644 --- a/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Break.cs +++ b/tests/Neo.Compiler.CSharp.UnitTests/TestingArtifacts/Contract_Break.cs @@ -10,12 +10,12 @@ public abstract class Contract_Break(Neo.SmartContract.Testing.SmartContractInit { #region Compiled data - public static Neo.SmartContract.Manifest.ContractManifest Manifest => Neo.SmartContract.Manifest.ContractManifest.Parse(@"{""name"":""Contract_Break"",""groups"":[],""features"":{},""supportedstandards"":[],""abi"":{""methods"":[{""name"":""breakInTryCatch"",""parameters"":[],""returntype"":""Void"",""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_Break"",""groups"":[],""features"":{},""supportedstandards"":[],""abi"":{""methods"":[{""name"":""breakInTryCatch"",""parameters"":[{""name"":""exception"",""type"":""Boolean""}],""returntype"":""Void"",""offset"":0,""safe"":false}],""events"":[]},""permissions"":[],""trusts"":[],""extra"":{""nef"":{""optimization"":""All""}}}"); /// /// Optimization: "All" /// - public static Neo.SmartContract.NefFile Nef => Neo.IO.Helper.AsSerializable(Convert.FromBase64String(@"TkVGM1Rlc3RpbmdFbmdpbmUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP2BAVcGAAwBAAwC/wA1SAEAABAMAf81TwEAAHAiG2hB81S/HXE7AAU9FwwBAQwC/wA1JAEAAD9oQZwI7Zwk4QwC/wA1MgEAAAwBAZc5EAwB/zUUAQAAcCJsaEHzVL8dcTsaMRByIg4MCWV4Y2VwdGlvbjpqE7Uk8T1LcjsAByIRPUsMAQAMAv8ANcwAAAA/PfEMAv8ANeAAAAAMAQCXORIREBPASnLKcxB0IhRqbM51DAECDAL/ADWeAAAAIgZsazDsP2hBnAjtnCSQDAL/ADWmAAAADAEClzkQDAH/NYgAAABwIl5oQfNUvx1xOwtAEHJqE7VFPUxyEHNrE7VFaxCXOTsOEwwBAwwC/wA0SWo6dCIZPTYMAv8ANFwMAQOXOQwBAgwC/wA0Lj896QwC/wA0RQwBApc5DAEDDAL/ADQXP2hBnAjtnCSeDAL/ADQoDAEDlzlAVwACeXhBm/ZnzkHmPxiEQFcAAnl4Qfa0a+JB3zC4mkBXAAF4Qfa0a+JBkl3oMUB6sNlU")); + public static Neo.SmartContract.NefFile Nef => Neo.IO.Helper.AsSerializable(Convert.FromBase64String(@"TkVGM1Rlc3RpbmdFbmdpbmUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP2QAVcGAQwBAAwC/wA1VwEAABAMAf81XgEAAHAiG2hB81S/HXE7AAU9FwwBAQwC/wA1MwEAAD9oQZwI7Zwk4QwC/wA1QQEAAAwBAZc5EAwB/zUjAQAAcCJsaEHzVL8dcTsaMRByIg4MCWV4Y2VwdGlvbjpqE7Uk8T1LcjsAByIRPUsMAQAMAv8ANdsAAAA/PfEMAv8ANe8AAAAMAQCXORIREBPASnLKcxB0IhRqbM51DAECDAL/ADWtAAAAIgZsazDsP2hBnAjtnCSQDAL/ADW1AAAADAEClzkQDAH/NZcAAABwIm1oQfNUvx1xOxpPEHJqE7VFeCYODAlleGNlcHRpb246PUxyEHNrE7VFaxCXOTsOEwwBAwwC/wA0SWo6dCIZPTYMAv8ANFwMAQOXOQwBAgwC/wA0Lj896QwC/wA0RQwBApc5DAEDDAL/ADQXP2hBnAjtnCSPDAL/ADQoDAEDlzlAVwACeXhBm/ZnzkHmPxiEQFcAAnl4Qfa0a+JB3zC4mkBXAAF4Qfa0a+JBkl3oMUCP84XP")); #endregion @@ -25,14 +25,14 @@ public abstract class Contract_Break(Neo.SmartContract.Testing.SmartContractInit /// Unsafe method /// /// - /// Script: VwYADAEADAL/ADVIAQAAEAwB/zVPAQAAcCIbaEHzVL8dcTsABT0XDAEBDAL/ADUkAQAAP2hBnAjtnCThDAL/ADUyAQAADAEBlzkQDAH/NRQBAABwImxoQfNUvx1xOxoxEHIiDgwJZXhjZXB0aW9uOmoTtSTxPUtyOwAHIhE9SwwBAAwC/wA1zAAAAD898QwC/wA14AAAAAwBAJc5EhEQE8BKcspzEHQiFGpsznUMAQIMAv8ANZ4AAAAiBmxrMOw/aEGcCO2cJJAMAv8ANaYAAAAMAQKXORAMAf81iAAAAHAiXmhB81S/HXE7C0AQcmoTtUU9THIQc2sTtUVrEJc5Ow4TDAEDDAL/ADRJajp0Ihk9NgwC/wA0XAwBA5c5DAECDAL/ADQuPz3pDAL/ADRFDAEClzkMAQMMAv8ANBc/aEGcCO2cJJ4MAv8ANCgMAQOXOUA= - /// INITSLOT 0600 [64 datoshi] + /// Script: VwYBDAEADAL/ADVXAQAAEAwB/zVeAQAAcCIbaEHzVL8dcTsABT0XDAEBDAL/ADUzAQAAP2hBnAjtnCThDAL/ADVBAQAADAEBlzkQDAH/NSMBAABwImxoQfNUvx1xOxoxEHIiDgwJZXhjZXB0aW9uOmoTtSTxPUtyOwAHIhE9SwwBAAwC/wA12wAAAD898QwC/wA17wAAAAwBAJc5EhEQE8BKcspzEHQiFGpsznUMAQIMAv8ANa0AAAAiBmxrMOw/aEGcCO2cJJAMAv8ANbUAAAAMAQKXORAMAf81lwAAAHAibWhB81S/HXE7Gk8QcmoTtUV4Jg4MCWV4Y2VwdGlvbjo9THIQc2sTtUVrEJc5Ow4TDAEDDAL/ADRJajp0Ihk9NgwC/wA0XAwBA5c5DAECDAL/ADQuPz3pDAL/ADRFDAEClzkMAQMMAv8ANBc/aEGcCO2cJI8MAv8ANCgMAQOXOUA= + /// INITSLOT 0601 [64 datoshi] /// PUSHDATA1 00 [8 datoshi] /// PUSHDATA1 FF00 [8 datoshi] - /// CALL_L 48010000 [512 datoshi] + /// CALL_L 57010000 [512 datoshi] /// PUSH0 [1 datoshi] /// PUSHDATA1 FF '?' [8 datoshi] - /// CALL_L 4F010000 [512 datoshi] + /// CALL_L 5E010000 [512 datoshi] /// STLOC0 [2 datoshi] /// JMP 1B [2 datoshi] /// LDLOC0 [2 datoshi] @@ -42,19 +42,19 @@ public abstract class Contract_Break(Neo.SmartContract.Testing.SmartContractInit /// ENDTRY 17 [4 datoshi] /// PUSHDATA1 01 [8 datoshi] /// PUSHDATA1 FF00 [8 datoshi] - /// CALL_L 24010000 [512 datoshi] + /// CALL_L 33010000 [512 datoshi] /// ENDFINALLY [4 datoshi] /// LDLOC0 [2 datoshi] /// SYSCALL 9C08ED9C 'System.Iterator.Next' [32768 datoshi] /// JMPIF E1 [2 datoshi] /// PUSHDATA1 FF00 [8 datoshi] - /// CALL_L 32010000 [512 datoshi] + /// CALL_L 41010000 [512 datoshi] /// PUSHDATA1 01 [8 datoshi] /// EQUAL [32 datoshi] /// ASSERT [1 datoshi] /// PUSH0 [1 datoshi] /// PUSHDATA1 FF '?' [8 datoshi] - /// CALL_L 14010000 [512 datoshi] + /// CALL_L 23010000 [512 datoshi] /// STLOC0 [2 datoshi] /// JMP 6C [2 datoshi] /// LDLOC0 [2 datoshi] @@ -77,11 +77,11 @@ public abstract class Contract_Break(Neo.SmartContract.Testing.SmartContractInit /// ENDTRY 4B [4 datoshi] /// PUSHDATA1 00 [8 datoshi] /// PUSHDATA1 FF00 [8 datoshi] - /// CALL_L CC000000 [512 datoshi] + /// CALL_L DB000000 [512 datoshi] /// ENDFINALLY [4 datoshi] /// ENDTRY F1 [4 datoshi] /// PUSHDATA1 FF00 [8 datoshi] - /// CALL_L E0000000 [512 datoshi] + /// CALL_L EF000000 [512 datoshi] /// PUSHDATA1 00 [8 datoshi] /// EQUAL [32 datoshi] /// ASSERT [1 datoshi] @@ -103,7 +103,7 @@ public abstract class Contract_Break(Neo.SmartContract.Testing.SmartContractInit /// STLOC5 [2 datoshi] /// PUSHDATA1 02 [8 datoshi] /// PUSHDATA1 FF00 [8 datoshi] - /// CALL_L 9E000000 [512 datoshi] + /// CALL_L AD000000 [512 datoshi] /// JMP 06 [2 datoshi] /// LDLOC4 [2 datoshi] /// LDLOC3 [2 datoshi] @@ -113,25 +113,29 @@ public abstract class Contract_Break(Neo.SmartContract.Testing.SmartContractInit /// SYSCALL 9C08ED9C 'System.Iterator.Next' [32768 datoshi] /// JMPIF 90 [2 datoshi] /// PUSHDATA1 FF00 [8 datoshi] - /// CALL_L A6000000 [512 datoshi] + /// CALL_L B5000000 [512 datoshi] /// PUSHDATA1 02 [8 datoshi] /// EQUAL [32 datoshi] /// ASSERT [1 datoshi] /// PUSH0 [1 datoshi] /// PUSHDATA1 FF '?' [8 datoshi] - /// CALL_L 88000000 [512 datoshi] + /// CALL_L 97000000 [512 datoshi] /// STLOC0 [2 datoshi] - /// JMP 5E [2 datoshi] + /// JMP 6D [2 datoshi] /// LDLOC0 [2 datoshi] /// SYSCALL F354BF1D 'System.Iterator.Value' [16 datoshi] /// STLOC1 [2 datoshi] - /// TRY 0B40 [4 datoshi] + /// TRY 1A4F [4 datoshi] /// PUSH0 [1 datoshi] /// STLOC2 [2 datoshi] /// LDLOC2 [2 datoshi] /// PUSH3 [1 datoshi] /// LT [8 datoshi] /// DROP [2 datoshi] + /// LDARG0 [2 datoshi] + /// JMPIFNOT 0E [2 datoshi] + /// PUSHDATA1 657863657074696F6E 'exception' [8 datoshi] + /// THROW [512 datoshi] /// ENDTRY 4C [4 datoshi] /// STLOC2 [2 datoshi] /// PUSH0 [1 datoshi] @@ -174,7 +178,7 @@ public abstract class Contract_Break(Neo.SmartContract.Testing.SmartContractInit /// ENDFINALLY [4 datoshi] /// LDLOC0 [2 datoshi] /// SYSCALL 9C08ED9C 'System.Iterator.Next' [32768 datoshi] - /// JMPIF 9E [2 datoshi] + /// JMPIF 8F [2 datoshi] /// PUSHDATA1 FF00 [8 datoshi] /// CALL 28 [512 datoshi] /// PUSHDATA1 03 [8 datoshi] @@ -183,7 +187,7 @@ public abstract class Contract_Break(Neo.SmartContract.Testing.SmartContractInit /// RET [0 datoshi] /// [DisplayName("breakInTryCatch")] - public abstract void BreakInTryCatch(); + public abstract void BreakInTryCatch(bool? exception); #endregion } diff --git a/tests/Neo.Compiler.CSharp.UnitTests/UnitTest_Break.cs b/tests/Neo.Compiler.CSharp.UnitTests/UnitTest_Break.cs index f76a24893..042d1f5e4 100644 --- a/tests/Neo.Compiler.CSharp.UnitTests/UnitTest_Break.cs +++ b/tests/Neo.Compiler.CSharp.UnitTests/UnitTest_Break.cs @@ -10,7 +10,8 @@ public class UnitTest_Break : DebugAndTestBase [TestMethod] public void TestBreakInTry() { - Contract.BreakInTryCatch(); + Contract.BreakInTryCatch(true); + Contract.BreakInTryCatch(false); } } }