Skip to content

Commit f436f60

Browse files
committed
correct branch return type
1 parent 74fe2fa commit f436f60

File tree

1 file changed

+47
-21
lines changed

1 file changed

+47
-21
lines changed

src/Neo.Compiler.CSharp/Optimizer/Strategies/Reachability.cs

+47-21
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,13 @@ public enum BranchType
3636
OK, // One of the branches may return without exception
3737
THROW, // All branches surely has exceptions, but can be catched
3838
ABORT, // All branches abort, and cannot be catched
39+
UNCOVERED,
3940
}
4041

4142
[Strategy(Priority = int.MaxValue)]
4243
public static (NefFile, ContractManifest, JObject) RemoveUncoveredInstructions(NefFile nef, ContractManifest manifest, JObject debugInfo)
4344
{
44-
Dictionary<int, bool> coveredMap = FindCoveredInstructions(nef, manifest, debugInfo);
45+
Dictionary<int, BranchType> coveredMap = FindCoveredInstructions(nef, manifest, debugInfo);
4546
Script oldScript = nef.Script;
4647
List<(int, Instruction)> oldAddressAndInstructionsList = oldScript.EnumerateInstructions().ToList();
4748
Dictionary<int, Instruction> oldAddressToInstruction = new();
@@ -53,7 +54,7 @@ public static (NefFile, ContractManifest, JObject) RemoveUncoveredInstructions(N
5354
int currentAddress = 0;
5455
foreach ((int a, Instruction i) in oldAddressAndInstructionsList)
5556
{
56-
if (coveredMap[a])
57+
if (coveredMap[a] != BranchType.UNCOVERED)
5758
{
5859
simplifiedInstructionsToAddress.Add(i, currentAddress);
5960
currentAddress += i.Size;
@@ -160,13 +161,13 @@ public static (NefFile, ContractManifest, JObject) RemoveUncoveredInstructions(N
160161
return (nef, manifest, debugInfo);
161162
}
162163

163-
public static Dictionary<int, bool>
164+
public static Dictionary<int, BranchType>
164165
FindCoveredInstructions(NefFile nef, ContractManifest manifest, JToken debugInfo)
165166
{
166167
Script script = nef.Script;
167-
Dictionary<int, bool> coveredMap = new();
168+
Dictionary<int, BranchType> coveredMap = new();
168169
foreach ((int addr, Instruction _) in script.EnumerateInstructions())
169-
coveredMap.Add(addr, false);
170+
coveredMap.Add(addr, BranchType.UNCOVERED);
170171

171172
Dictionary<int, string> publicMethodStartingAddressToName = new();
172173
foreach (ContractMethodDescriptor method in manifest.Abi.Methods)
@@ -201,8 +202,9 @@ public static Dictionary<int, bool>
201202
/// <returns>Whether it is possible to return without exception</returns>
202203
/// <exception cref="BadScriptException"></exception>
203204
/// <exception cref="NotImplementedException"></exception>
204-
public static BranchType CoverInstruction(int addr, Script script, Dictionary<int, bool> coveredMap, Stack<((int returnAddr, int finallyAddr), TryStack stackType)>? stack = null, bool throwed = false)
205+
public static BranchType CoverInstruction(int addr, Script script, Dictionary<int, BranchType> coveredMap, Stack<((int returnAddr, int finallyAddr), TryStack stackType)>? stack = null, bool throwed = false)
205206
{
207+
int entranceAddr = addr;
206208
stack ??= new();
207209
if (stack.Count == 0)
208210
stack.Push(((-1, -1), TryStack.ENTRY));
@@ -244,25 +246,32 @@ public static BranchType CoverInstruction(int addr, Script script, Dictionary<in
244246
HANDLE_NORMAL_CASE:
245247
if (!coveredMap.ContainsKey(addr))
246248
throw new BadScriptException($"wrong address {addr}");
247-
if (coveredMap[addr])
249+
if (coveredMap[addr] != BranchType.UNCOVERED)
248250
// We have visited the code. Skip it.
249-
return BranchType.OK;
251+
return coveredMap[addr];
250252
Instruction instruction = script.GetInstruction(addr);
251253
if (instruction.OpCode != OpCode.NOP)
252-
coveredMap[addr] = true;
254+
coveredMap[addr] = BranchType.OK;
253255

254256
// TODO: ABORTMSG may THROW instead of ABORT. Just throw new NotImplementedException for ABORTMSG?
255257
if (instruction.OpCode == OpCode.ABORT || instruction.OpCode == OpCode.ABORTMSG)
256258
{
257259
// See if we are in a try. There may still be runtime exceptions
258260
((catchAddr, finallyAddr), stackType) = stack.Peek();
259261
if (stackType == TryStack.TRY && catchAddr != -1)
262+
{
260263
// Visit catchAddr because there may still be exceptions at runtime
261-
return CoverInstruction(catchAddr, script, coveredMap, stack: new(stack.Reverse()), throwed: true);
264+
coveredMap[entranceAddr] = CoverInstruction(catchAddr, script, coveredMap, stack: new(stack.Reverse()), throwed: true);
265+
return coveredMap[entranceAddr];
266+
}
262267
if (stackType == TryStack.CATCH && finallyAddr != -1)
268+
{
263269
// Visit finallyAddr because there may still be exceptions at runtime
264-
return CoverInstruction(finallyAddr, script, coveredMap, stack: new(stack.Reverse()), throwed: true);
265-
return BranchType.ABORT;
270+
coveredMap[entranceAddr] = CoverInstruction(finallyAddr, script, coveredMap, stack: new(stack.Reverse()), throwed: true);
271+
return coveredMap[entranceAddr];
272+
}
273+
coveredMap[entranceAddr] = BranchType.ABORT;
274+
return coveredMap[entranceAddr];
266275
}
267276
if (callWithJump.Contains(instruction.OpCode))
268277
{
@@ -278,12 +287,19 @@ public static BranchType CoverInstruction(int addr, Script script, Dictionary<in
278287
// See if we are in a try. There may still be runtime exceptions
279288
((catchAddr, finallyAddr), stackType) = stack.Peek();
280289
if (stackType == TryStack.TRY && catchAddr != -1)
290+
{
281291
// Visit catchAddr because there may still be exceptions at runtime
282-
return CoverInstruction(catchAddr, script, coveredMap, stack: new(stack.Reverse()), throwed: true);
292+
coveredMap[entranceAddr] = CoverInstruction(catchAddr, script, coveredMap, stack: new(stack.Reverse()), throwed: true);
293+
return coveredMap[entranceAddr];
294+
}
283295
if (stackType == TryStack.CATCH && finallyAddr != -1)
296+
{
284297
// Visit finallyAddr because there may still be exceptions at runtime
285-
return CoverInstruction(finallyAddr, script, coveredMap, stack: new(stack.Reverse()), throwed: true);
286-
return BranchType.ABORT;
298+
coveredMap[entranceAddr] = CoverInstruction(finallyAddr, script, coveredMap, stack: new(stack.Reverse()), throwed: true);
299+
return coveredMap[entranceAddr];
300+
}
301+
coveredMap[entranceAddr] = BranchType.ABORT;
302+
return coveredMap[entranceAddr];
287303
}
288304
if (returnedType == BranchType.THROW)
289305
goto HANDLE_THROW;
@@ -298,7 +314,8 @@ public static BranchType CoverInstruction(int addr, Script script, Dictionary<in
298314
if (stackType == TryStack.CATCH && finallyAddr != -1)
299315
// Visit finallyAddr because there may still be exceptions at runtime
300316
CoverInstruction(finallyAddr, script, coveredMap, stack: new(stack.Reverse()), throwed: true);
301-
return BranchType.OK;
317+
coveredMap[entranceAddr] = BranchType.OK;
318+
return coveredMap[entranceAddr];
302319
}
303320
if (tryThrowFinally.Contains(instruction.OpCode))
304321
{
@@ -373,19 +390,27 @@ public static BranchType CoverInstruction(int addr, Script script, Dictionary<in
373390
if (stackType == TryStack.CATCH && finallyAddr != -1)
374391
// Visit finallyAddr because there may still be exceptions at runtime
375392
CoverInstruction(finallyAddr, script, coveredMap, stack: new(stack.Reverse()), throwed: true);
376-
return BranchType.OK;
393+
coveredMap[entranceAddr] = BranchType.OK;
394+
return coveredMap[entranceAddr];
377395
}
378396
if (noJump == BranchType.ABORT && jump == BranchType.ABORT)
379397
{
380398
// See if we are in a try. There may still be runtime exceptions
381399
((catchAddr, finallyAddr), stackType) = stack.Peek();
382400
if (stackType == TryStack.TRY && catchAddr != -1)
401+
{
383402
// Visit catchAddr because there may still be exceptions at runtime
384-
return CoverInstruction(catchAddr, script, coveredMap, stack: new(stack.Reverse()), throwed: true);
403+
coveredMap[entranceAddr] = CoverInstruction(catchAddr, script, coveredMap, stack: new(stack.Reverse()), throwed: true);
404+
return coveredMap[entranceAddr];
405+
}
385406
if (stackType == TryStack.CATCH && finallyAddr != -1)
407+
{
386408
// Visit finallyAddr because there may still be exceptions at runtime
387-
return CoverInstruction(finallyAddr, script, coveredMap, stack: new(stack.Reverse()), throwed: true);
388-
return BranchType.ABORT;
409+
coveredMap[entranceAddr] = CoverInstruction(finallyAddr, script, coveredMap, stack: new(stack.Reverse()), throwed: true);
410+
return coveredMap[entranceAddr];
411+
}
412+
coveredMap[entranceAddr] = BranchType.ABORT;
413+
return coveredMap[entranceAddr];
389414
}
390415
if (noJump == BranchType.THROW || jump == BranchType.THROW) // THROW, ABORT => THROW
391416
goto HANDLE_THROW;
@@ -394,7 +419,8 @@ public static BranchType CoverInstruction(int addr, Script script, Dictionary<in
394419

395420
addr += instruction.Size;
396421
}
397-
return throwed ? BranchType.THROW : BranchType.OK;
422+
coveredMap[entranceAddr] = throwed ? BranchType.THROW : BranchType.OK;
423+
return coveredMap[entranceAddr];
398424
}
399425
}
400426
}

0 commit comments

Comments
 (0)