Skip to content

Commit

Permalink
Improve missing method handling, better exception handling is now pos…
Browse files Browse the repository at this point in the history
…sible
  • Loading branch information
liiir1985 committed Nov 30, 2023
1 parent e997f03 commit 51d4c0c
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 15 deletions.
38 changes: 25 additions & 13 deletions ILRuntime/CLR/Method/ILMethod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -736,29 +736,41 @@ unsafe void InitToken(ref OpCode code, object token, Dictionary<Mono.Cecil.Cil.I
case OpCodeEnum.Ldvirtftn:
case OpCodeEnum.Callvirt:
{
bool invalidToken;
var m = appdomain.GetMethod(token, declaringType, this, out invalidToken);
if (m != null)
try
{
if(code.Code == OpCodeEnum.Callvirt && m is ILMethod)
bool invalidToken;
var m = appdomain.GetMethod(token, declaringType, this, out invalidToken);
if (m != null)
{
ILMethod ilm = (ILMethod)m;
if (!ilm.def.IsAbstract && !ilm.def.IsVirtual && !ilm.DeclearingType.IsInterface)
code.Code = OpCodeEnum.Call;
if (code.Code == OpCodeEnum.Callvirt && m is ILMethod)
{
ILMethod ilm = (ILMethod)m;
if (!ilm.def.IsAbstract && !ilm.def.IsVirtual && !ilm.DeclearingType.IsInterface)
code.Code = OpCodeEnum.Call;
}
if (invalidToken)
code.TokenInteger = m.GetHashCode();
else
code.TokenInteger = token.GetHashCode();
}
if (invalidToken)
code.TokenInteger = m.GetHashCode();
else
code.TokenInteger = token.GetHashCode();
{
//Cannot find method or the method is dummy
MethodReference _ref = (MethodReference)token;
int paramCnt = _ref.HasParameters ? _ref.Parameters.Count : 0;
if (_ref.HasThis)
paramCnt++;
code.TokenLong = paramCnt;
}
}
else
catch(Exception e)
{
//Cannot find method or the method is dummy
appdomain.CacheException(e);
MethodReference _ref = (MethodReference)token;
int paramCnt = _ref.HasParameters ? _ref.Parameters.Count : 0;
if (_ref.HasThis)
paramCnt++;
code.TokenLong = paramCnt;
code.TokenLong = (long)paramCnt | ((long)e.GetHashCode() << 32);
}
}
break;
Expand Down
13 changes: 13 additions & 0 deletions ILRuntime/Runtime/Enviorment/AppDomain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ public class AppDomain
List<IType> typesByIndex = new List<IType>();
ThreadSafeDictionary<int, IType> mapTypeToken = new ThreadSafeDictionary<int, IType>();
ThreadSafeDictionary<int, IMethod> mapMethod = new ThreadSafeDictionary<int, IMethod>();
ThreadSafeDictionary<int, Exception> mapException = new ThreadSafeDictionary<int, Exception>();
ThreadSafeDictionary<long, string> mapString = new ThreadSafeDictionary<long, string>();
Dictionary<System.Reflection.MethodBase, CLRRedirectionDelegate> redirectMap = new Dictionary<System.Reflection.MethodBase, CLRRedirectionDelegate>();
Dictionary<System.Reflection.FieldInfo, CLRFieldGetterDelegate> fieldGetterMap = new Dictionary<System.Reflection.FieldInfo, CLRFieldGetterDelegate>();
Expand Down Expand Up @@ -1544,6 +1545,18 @@ bool IsInvalidMethodReference(MethodReference _ref)
}
return false;
}

internal void CacheException(Exception ex)
{
mapException[ex.GetHashCode()] = ex;
}

internal Exception GetException(int token)
{
if (mapException.TryGetValue(token, out var ex))
return ex;
return null;
}


internal IMethod GetMethod(object token, ILType contextType, ILMethod contextMethod, out bool invalidToken)
Expand Down
9 changes: 9 additions & 0 deletions ILRuntime/Runtime/Intepreter/ILIntepreter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1971,6 +1971,15 @@ public object Run(ILMethod method, object instance, object[] p)
IMethod m = domain.GetMethod(ip->TokenInteger);
if (m == null)
{
int exToken = (int)(((ulong)ip->TokenLong & 0xFFFFFFFF00000000) >> 32);
if (exToken > 0)
{
var ex = domain.GetException(exToken);
if (ex != null)
{
throw new ILRuntimeException(ex.Message, this, method, ex);
}
}
//Irrelevant method
int cnt = (int)ip->TokenLong;
//Balance the stack
Expand Down
26 changes: 25 additions & 1 deletion ILRuntimeTestBase/TestFramework/TestClass3.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
#define TEST_MISSING_METHOD
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
Expand Down Expand Up @@ -103,6 +104,29 @@ public void Emit<T>(T obj)
{
LoadAsset("123", obj);
}

#if TEST_MISSING_METHOD
public int missingField;
public void MissingMethodGeneric<T>(T obj)
{

}

public void MissingMethod()
{

}

public static void MissingStaticMethod()
{

}
#endif
}

#if TEST_MISSING_METHOD
public class MissingType
{
}
#endif
}
47 changes: 46 additions & 1 deletion TestCases/CLRBindingTest.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using ILRuntimeTest;
using ILRuntime.Runtime.CLRBinding;
using ILRuntime.Runtime.Intepreter;
using ILRuntimeTest;
using ILRuntimeTest.TestFramework;
using System;
using System.Collections.Generic;
using System.Linq;
Expand Down Expand Up @@ -139,5 +142,47 @@ public static void CLRBindingTestEnd()
{
ILRuntimeTest.TestBase.TestSession.LastSession.Appdomain.AllowUnboundCLRMethod = true;
}

[ILRuntimeTest.ILRuntimeTest(ExpectException = typeof(ILRuntimeException))]
public static void CLRBindingTestMissing01()
{
ILRuntimeTest.TestFramework.TestCLRBinding binding = new ILRuntimeTest.TestFramework.TestCLRBinding();
binding.MissingMethod();
}

[ILRuntimeTest.ILRuntimeTest(ExpectException = typeof(ILRuntimeException))]
public static void CLRBindingTestMissing02()
{
ILRuntimeTest.TestFramework.TestCLRBinding binding = new ILRuntimeTest.TestFramework.TestCLRBinding();
binding.MissingMethodGeneric<TestCls2>(null);
}

[ILRuntimeTest.ILRuntimeTest(ExpectException = typeof(ILRuntimeException))]
public static void CLRBindingTestMissing03()
{
ILRuntimeTest.TestFramework.TestCLRBinding binding = new ILRuntimeTest.TestFramework.TestCLRBinding();
binding.missingField = 123;
}

[ILRuntimeTest.ILRuntimeTest(ExpectException = typeof(ILRuntimeException))]
public static void CLRBindingTestMissing04()
{
ILRuntimeTest.TestFramework.TestCLRBinding binding = new ILRuntimeTest.TestFramework.TestCLRBinding();
binding.Emit<MissingType>(null);
}

[ILRuntimeTest.ILRuntimeTest(ExpectException = typeof(ILRuntimeException))]
public static void CLRBindingTestMissing05()
{
ILRuntimeTest.TestFramework.TestCLRBinding binding = new ILRuntimeTest.TestFramework.TestCLRBinding();
binding.MissingMethodGeneric<MissingType>(null);
}

[ILRuntimeTest.ILRuntimeTest(ExpectException = typeof(ILRuntimeException))]
public static void CLRBindingTestMissing08()
{
MissingType mt = new MissingType();

}
}
}

0 comments on commit 51d4c0c

Please sign in to comment.