Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add trycatch support #186

Merged
merged 30 commits into from
May 6, 2020
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
c6ff7b8
parseTryCatch
lightszero Jan 21, 2020
f4d9e68
fix try endpos problem
lightszero Jan 21, 2020
ceb4bda
add parse code for no catch and no finally
lightszero Jan 21, 2020
b2bfc79
update trycatch
lightszero Feb 16, 2020
049361f
Merge branch 'master' into Branch_lights_trycatch
lightszero Feb 17, 2020
827a885
add a unittest
lightszero Feb 26, 2020
3332eb3
Merge branch 'Branch_lights_trycatch' of https://github.com/neo-proje…
lightszero Feb 26, 2020
1ebb167
Merge branch 'master' into Branch_lights_trycatch
lightszero Mar 20, 2020
574ee79
Merge branch 'master' into Branch_lights_trycatch
lightszero Mar 22, 2020
2e08b28
Merge branch 'master' into Branch_lights_trycatch
lightszero Apr 13, 2020
2969df5
Merge branch 'master' into Branch_lights_trycatch
lightszero Apr 14, 2020
782f62c
fix compile error on compiler
lightszero Apr 16, 2020
61db134
fix compiler about trycatch
lightszero Apr 16, 2020
23b262d
fix opcodes
lightszero Apr 16, 2020
cc9a64a
fix optimizer for try catch
lightszero Apr 16, 2020
335d1cd
open optimize for trycatch unittest
lightszero Apr 16, 2020
ae81673
Fix format
shargon Apr 16, 2020
917ad37
Merge branch 'master' into Branch_lights_trycatch
lightszero Apr 24, 2020
e7dd660
Merge branch 'master' into Branch_lights_trycatch
lightszero Apr 26, 2020
61f5c8c
Merge branch 'master' into Branch_lights_trycatch
lightszero Apr 26, 2020
f602eb8
fix UT (#255)
ShawnYun Apr 26, 2020
c462e25
add try-finally ut (#259)
Apr 29, 2020
5991a10
Merge branch 'master' into Branch_lights_trycatch
lightszero Apr 29, 2020
bef47cb
add commont for exception paramcount.
lightszero Apr 30, 2020
5f97e0a
Update src/Neo.Compiler.MSIL/MSIL/Converter.cs
shargon Apr 30, 2020
0ffbe6a
Update src/Neo.Compiler.MSIL/MSIL/Converter.cs
shargon Apr 30, 2020
e891851
add try-catch failure ut (#261)
Apr 30, 2020
3089c6d
fix some skip leaves problem.
lightszero May 2, 2020
8d7a6e5
Merge branch 'master' into Branch_lights_trycatch
lightszero May 2, 2020
a523a02
Reduce changes
shargon May 2, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions src/Neo.Compiler.MSIL/MSIL/Conv_Multi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1308,21 +1308,34 @@ private int ConvertNewObj(ILMethod from, OpCode src, NeoMethod to)
var _type = (src.tokenUnknown as Mono.Cecil.MethodReference);
if (_type.FullName == "System.Void System.Numerics.BigInteger::.ctor(System.Byte[])")
{
return 0;//donothing;
return 0; // donothing;
}
else if (_type.DeclaringType.FullName.Contains("Exception"))
{
// NeoVM `catch` instruction need one exception parameter
Convert1by1(VM.OpCode.NOP, src, to);

var pcount = _type.Parameters.Count;
for (var i = 0; i < pcount; i++)
//pcount must be 1
//if more then one, drop them.
//if pcount==0,add one.
if (pcount == 0) // If there is no parameter, insert one pararmeter
{
ConvertPushString("usererror", src, to);
}
else if (pcount > 1)
{
Insert1(VM.OpCode.DROP, "", to);
// Keep the first exception parameter
for (var i = 0; i < pcount - 1; i++)
{
Insert1(VM.OpCode.DROP, "", to);
}
}
return 0;
}
var type = _type.Resolve();

//Replace the New Array operation if there is an [OpCode] on the constructor
// Replace the New Array operation if there is an [OpCode] on the constructor
foreach (var m in type.DeclaringType.Methods)
{
if (m.IsConstructor && m.HasCustomAttributes)
Expand Down
104 changes: 95 additions & 9 deletions src/Neo.Compiler.MSIL/MSIL/Converter.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
Expand Down Expand Up @@ -346,23 +347,83 @@ private void ConvertAddrInMethod(NeoMethod to)
{
if (c.needfix)
{
try
if (c.code == VM.OpCode.TRY_L)
{
var _addr = addrconv[c.srcaddr];
Int32 addroff = (Int32)(_addr - c.addr);
c.bytes = BitConverter.GetBytes(addroff);
c.needfix = false;
var srcCatch = BitConverter.ToInt32(c.bytes, 0);
var srcFinal = BitConverter.ToInt32(c.bytes, 4);
if (srcCatch == -1)
{
var bytesCatch = new byte[] { 0, 0, 0, 0 };
Array.Copy(bytesCatch, 0, c.bytes, 0, 4);
}
else
{
var _addrCatch = addrconv[srcCatch];
Int32 addroffCatch = (Int32)(_addrCatch - c.addr);
var bytesCatch = BitConverter.GetBytes(addroffCatch);
Array.Copy(bytesCatch, 0, c.bytes, 0, 4);
}
if (srcFinal == -1)
{
var bytesFinal = new byte[] { 0, 0, 0, 0 };
Array.Copy(bytesFinal, 0, c.bytes, 4, 4);
}
else
{
var _addrFinal = addrconv[srcFinal];
int addroffFinal = (int)(_addrFinal - c.addr);
var bytesFinal = BitConverter.GetBytes(addroffFinal);
Array.Copy(bytesFinal, 0, c.bytes, 4, 4);
}
}
catch
else
{
throw new Exception("cannot convert addr in: " + to.name + "\r\n");
try
{
var _addr = addrconv[c.srcaddr];
int addroff = (int)(_addr - c.addr);
c.bytes = BitConverter.GetBytes(addroff);
c.needfix = false;
}
catch
{
throw new Exception("cannot convert addr in: " + to.name + "\r\n");
}
}
}
}
}

private int ConvertCode(ILMethod method, OpCode src, NeoMethod to)
{
//add try code
if (method.tryPositions.Contains(src.addr))
{
foreach (var info in method.tryInfos)
{
if (info.addr_Try_Begin == src.addr)
{
if (info.catch_Infos.Count > 1)
throw new Exception("only support one catch for now.");

var buf = new byte[8];
var catchAddr = -1;
if (info.catch_Infos.Count == 1)
{
var first = info.catch_Infos.First().Value;
catchAddr = first.addrBegin;
}
var bytesCatch = BitConverter.GetBytes(catchAddr);
var bytesFinally = BitConverter.GetBytes(info.addr_Finally_Begin);

Array.Copy(bytesCatch, 0, buf, 0, 4);
Array.Copy(bytesFinally, 0, buf, 4, 4);
var trycode = Convert1by1(VM.OpCode.TRY_L, src, to, buf);
trycode.needfix = true;
shargon marked this conversation as resolved.
Show resolved Hide resolved
break;
}
}
}
int skipcount = 0;
switch (src.code)
{
Expand Down Expand Up @@ -479,14 +540,39 @@ private int ConvertCode(ILMethod method, OpCode src, NeoMethod to)
// Address convert required
case CodeEx.Br:
case CodeEx.Br_S:
case CodeEx.Leave:
case CodeEx.Leave_S:
{
var code = Convert1by1(VM.OpCode.JMP_L, src, to, new byte[] { 0, 0, 0, 0 });
code.needfix = true;
code.srcaddr = src.tokenAddr_Index;
}
break;
case CodeEx.Leave:
case CodeEx.Leave_S:
{//will support try catch

var tryinfo = method.GetTryInfo(src.addr, out ILMethod.TryCodeType type);

//leaves in try
//leaves in catch
if (type == ILMethod.TryCodeType.Try || type == ILMethod.TryCodeType.Catch)
{
var code = Convert1by1(VM.OpCode.ENDTRY_L, src, to, new byte[] { 0, 0, 0, 0 });
code.needfix = true;
code.srcaddr = src.tokenAddr_Index;
}
else //or else just jmp
{
var code = Convert1by1(VM.OpCode.JMP_L, src, to, new byte[] { 0, 0, 0, 0 });
code.needfix = true;
code.srcaddr = src.tokenAddr_Index;
}
}
break;
case CodeEx.Endfinally:
{
//need vm add these opcodes
var code = Convert1by1(VM.OpCode.ENDFINALLY, src, to);
}
break;
case CodeEx.Switch:
{
Expand Down
187 changes: 186 additions & 1 deletion src/Neo.Compiler.MSIL/MSIL/ILModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,23 @@ public override string ToString()
}
}

public class ILCatchInfo
{
public int addrBegin;
public int addrEnd;
public string catchType;
}

public class ILTryInfo
{
public int addr_Try_Begin = -1;
public int addr_Try_End = -1;
public int addr_Try_End_F = -1;//IL try catch,try final is 2 different Block,need to process that.
public Dictionary<string, ILCatchInfo> catch_Infos = new Dictionary<string, ILCatchInfo>();
public int addr_Finally_Begin = -1;
public int addr_Finally_End = -1;
}

public class ILMethod
{
public ILType type = null;
Expand All @@ -208,7 +225,8 @@ public class ILMethod
public List<NeoParam> body_Variables = new List<NeoParam>();
public SortedDictionary<int, OpCode> body_Codes = new SortedDictionary<int, OpCode>();
public string fail = null;

public List<ILTryInfo> tryInfos = new List<ILTryInfo>();
public List<int> tryPositions = new List<int>();
public ILMethod(ILType type, Mono.Cecil.MethodDefinition method, ILogger logger = null)
{
this.type = type;
Expand Down Expand Up @@ -269,8 +287,175 @@ public ILMethod(ILType type, Mono.Cecil.MethodDefinition method, ILogger logger
c.InitToken(code.Operand);
this.body_Codes.Add(c.addr, c);
}
if (method.Body.HasExceptionHandlers)
{
var mapTryInfos = new Dictionary<string, ILTryInfo>();
foreach (var e in method.Body.ExceptionHandlers)
{
if (e.HandlerType == Mono.Cecil.Cil.ExceptionHandlerType.Catch)
{
var key = e.TryStart.Offset + "_" + e.TryEnd.Offset;
if (mapTryInfos.ContainsKey(key) == false)
mapTryInfos[key] = new ILTryInfo();

var tryinfo = mapTryInfos[key];
tryinfo.addr_Try_Begin = e.TryStart.Offset;
tryinfo.addr_Try_End = e.TryEnd.Offset;

var catchtypestr = e.CatchType.FullName;

tryinfo.catch_Infos[catchtypestr] = new ILCatchInfo()
{
addrBegin = e.HandlerStart.Offset,
addrEnd = e.HandlerEnd.Offset,
catchType = catchtypestr
};
}
else if (e.HandlerType == Mono.Cecil.Cil.ExceptionHandlerType.Finally)
{
int start = e.TryStart.Offset;
int end = e.TryEnd.Offset;
Mono.Cecil.Cil.ExceptionHandler handler = null;
foreach (var tryinfocatch in method.Body.ExceptionHandlers)
{
if (tryinfocatch.HandlerType == Mono.Cecil.Cil.ExceptionHandlerType.Catch && tryinfocatch.TryStart.Offset == e.TryStart.Offset && tryinfocatch.TryEnd.Offset <= e.TryEnd.Offset)
{//find include catch element.
if (handler == null)
handler = tryinfocatch;
else if (handler.TryEnd.Offset < tryinfocatch.TryEnd.Offset)
handler = tryinfocatch;
}
}
if (handler != null)
{
start = handler.TryStart.Offset;
end = handler.TryEnd.Offset;
}

var key = start + "_" + end;

if (mapTryInfos.ContainsKey(key) == false)
mapTryInfos[key] = new ILTryInfo();

var tryinfo = mapTryInfos[key];
tryinfo.addr_Try_Begin = start;
tryinfo.addr_Try_End = end;
tryinfo.addr_Try_End_F = e.TryEnd.Offset;

tryinfo.addr_Finally_Begin = e.HandlerStart.Offset;
tryinfo.addr_Finally_End = e.HandlerEnd.Offset;
}
else
{
throw new Exception("not support yet." + e.HandlerType);
}
}
this.tryInfos = new List<ILTryInfo>(mapTryInfos.Values);
foreach (var info in this.tryInfos)
{
if (this.tryPositions.Contains(info.addr_Try_Begin) == false)
this.tryPositions.Add(info.addr_Try_Begin);
}
}
}
}
}

public enum TryCodeType
{
None,
Try,
Try_Final,
Catch,
Final,
}
public ILTryInfo GetTryInfo(int addr, out TryCodeType type)
{
type = TryCodeType.None;
ILTryInfo last = null;
int begin = -1;
int end = -1;
foreach (var info in tryInfos)
{
//check try first
if (info.addr_Try_Begin <= addr && addr < info.addr_Try_End)
{
if (last == null)
{
type = TryCodeType.Try;
last = info;
begin = info.addr_Try_Begin;
end = last.addr_Try_End;
}
else if (begin <= info.addr_Try_Begin && last.addr_Try_End < end)
{
type = TryCodeType.Try;
last = info;
begin = info.addr_Try_Begin;
end = last.addr_Try_End;
}
}

//then code in final but not in try
if (info.addr_Try_Begin <= addr && addr < info.addr_Try_End_F)
{
if (last == null)
{
type = TryCodeType.Try_Final;
last = info;
begin = info.addr_Try_Begin;
end = last.addr_Try_End_F;
}
else if (begin <= info.addr_Try_Begin && last.addr_Try_End_F < end)
{
type = TryCodeType.Try_Final;
last = info;
begin = info.addr_Try_Begin;
end = last.addr_Try_End_F;
}
}

//find match finally
if (info.addr_Finally_Begin <= addr && addr < info.addr_Finally_End)
{
if (last == null)
{
type = TryCodeType.Final;
last = info;
begin = info.addr_Finally_Begin;
end = last.addr_Finally_End;
}
else if (begin <= info.addr_Finally_Begin && last.addr_Finally_End < end)
{
type = TryCodeType.Final;
last = info;
begin = info.addr_Finally_Begin;
end = last.addr_Finally_End;
}
}
//find match catch
foreach (var c in info.catch_Infos)
{
if (c.Value.addrBegin <= addr && addr < c.Value.addrEnd)
{
if (last == null)
{
type = TryCodeType.Catch;
last = info;
begin = c.Value.addrBegin;
end = c.Value.addrEnd;
}
else if (begin <= c.Value.addrBegin && c.Value.addrBegin < end)
{
type = TryCodeType.Catch;
last = info;
begin = c.Value.addrBegin;
end = c.Value.addrEnd;
}
}
}
}
return last;
}

public int GetLastCodeAddr(int srcaddr)
Expand Down
Loading