private void ExecuteMethod(out ObjectInstance retVal, out bool doJmpCall, out MemberReference jmpCallToken)
{
jmpCallToken = null;
doJmpCall = false;
retVal = null;
EvalLoop:
try
{
this.ExecuteMethodCore(out retVal, out doJmpCall, out jmpCallToken);
}
catch (InazumaRuntimeException ex)
{
// TODO: check throwable
// TODO: isuncatchable (ThreadAbort)
var handleEx = false;
if (_methInfo2.Body.HasExceptionHandlers)
{
var curOffset = _instructions[_instructionPtr].Offset;
// Perform a filter scan or regular walk of the EH Table. Filter scan is performed when
// we are evaluating a series of filters to handle the exception until the first handler
// (filter's or otherwise) that will handle the exception.
foreach (var exceptionHandler in _methInfo2.Body.ExceptionHandlers)
{
var handlerOffset = 0;
// First, is the current offset in the try block?
if (exceptionHandler.TryStart.Offset <= curOffset && exceptionHandler.TryEnd.Offset >= curOffset)
{
// CORINFO_EH_CLAUSE_NONE represents 'catch' blocks
if (exceptionHandler.FilterStart == null)
{
// Now, does the catch block handle the thrown exception type?
var excType = _classLoader.LoadTypeFromTypeRef(exceptionHandler.CatchType);
if (ex.ExceptionObject.MethodTable == excType)
{
_opStack.Clear();
_opStack.Push(ex.ExceptionObject);
handlerOffset = _instructions.Select((x, i) => new { Index = i, IsMatched = x == exceptionHandler.HandlerStart }).First(x => x.IsMatched).Index; // TODO: FIXME
handleEx = true;
//_filterNextScan = 0;
}
}
else
{
throw ThrowHelper.NotImplementedYet;
}
// Reset the interpreter loop in preparation of calling the handler.
if (handleEx)
{
// Set the IL offset of the handler.
_instructionPtr = handlerOffset;
// If an exception occurs while attempting to leave a protected scope,
// we empty the 'leave' info stack upon entering the handler.
// TODO: infoStack
// Some things are set up before a call, and must be cleared on an exception caught be the caller.
// A method that returns a struct allocates local space for the return value, and "registers" that
// space and the type so that it's scanned if a GC happens. "Unregister" it if we throw an exception
// in the call, and handle it in the caller. (If it's not handled by the caller, the Interpreter is
// deallocated, so it's value doesn't matter.)
_callThisArg = null;
_args.Clear();
break;
}
}
}
}
if (handleEx)
{
goto EvalLoop;
}
else
{
throw;
}
}
}