Add support for throw in catch block and inner try with same offset as outer (#8207)
This commit is contained in:
Родитель
8456a8697e
Коммит
3a61e44371
|
@ -152,7 +152,9 @@ namespace Internal.IL
|
|||
_ehInfoNode = new EHInfoNode(_mangledName);
|
||||
}
|
||||
int curRegion = 0;
|
||||
foreach (ILExceptionRegion region in ilExceptionRegions.OrderBy(region => region.TryOffset))
|
||||
foreach (ILExceptionRegion region in ilExceptionRegions.OrderBy(region => region.TryOffset)
|
||||
.ThenByDescending(region => region.TryLength) // outer regions with the same try offset as inner region first - they will have longer lengths, // WASMTODO, except maybe an inner of try {} catch {} which could still be a problem
|
||||
.ThenBy(region => region.HandlerOffset))
|
||||
{
|
||||
_exceptionRegions[curRegion++] = new ExceptionRegion
|
||||
{
|
||||
|
@ -596,12 +598,17 @@ namespace Internal.IL
|
|||
/// Returns the most nested try region the current offset is in
|
||||
/// </summary>
|
||||
private ExceptionRegion GetCurrentTryRegion()
|
||||
{
|
||||
return GetTryRegion(_currentOffset);
|
||||
}
|
||||
|
||||
private ExceptionRegion GetTryRegion(int offset)
|
||||
{
|
||||
// Iterate backwards to find the most nested region
|
||||
for (int i = _exceptionRegions.Length - 1; i >= 0; i--)
|
||||
{
|
||||
ILExceptionRegion region = _exceptionRegions[i].ILRegion;
|
||||
if (IsOffsetContained(_currentOffset - 1, region.TryOffset, region.TryLength))
|
||||
if (IsOffsetContained(offset - 1, region.TryOffset, region.TryLength))
|
||||
{
|
||||
return _exceptionRegions[i];
|
||||
}
|
||||
|
@ -2864,7 +2871,7 @@ namespace Internal.IL
|
|||
|
||||
var arguments = new StackEntry[] { new ExpressionEntry(StackValueKind.ObjRef, "managedPtr", managedPtr),
|
||||
new ExpressionEntry(StackValueKind.Int32, "idxStart", LLVMValueRef.CreateConstInt(LLVMTypeRef.Int32, 0xFFFFFFFFu, false)),
|
||||
new ExpressionEntry(StackValueKind.Int32, "idxTryLandingStart", LLVMValueRef.CreateConstInt(LLVMTypeRef.Int32, (ulong)tryRegion.ILRegion.TryOffset, false)),
|
||||
new ExpressionEntry(StackValueKind.Int32, "idxCurrentBlockStart", LLVMValueRef.CreateConstInt(LLVMTypeRef.Int32, (ulong)_currentBasicBlock.StartOffset, false)),
|
||||
new ExpressionEntry(StackValueKind.NativeInt, "shadowStack", _currentFunclet.GetParam(0)),
|
||||
new ExpressionEntry(StackValueKind.ByRef, "refFrameIter", ehInfoIterator),
|
||||
new ExpressionEntry(StackValueKind.ByRef, "tryRegionIdx", tryRegionIdx),
|
||||
|
@ -2918,6 +2925,7 @@ namespace Internal.IL
|
|||
|
||||
if (_leaveTargets != null)
|
||||
{
|
||||
LLVMBasicBlockRef switchReturnBlock = default;
|
||||
foreach (var leaveTarget in _leaveTargets)
|
||||
{
|
||||
var targetBlock = _basicBlocks[leaveTarget];
|
||||
|
@ -2926,6 +2934,27 @@ namespace Internal.IL
|
|||
{
|
||||
@switch.AddCase(BuildConstInt32(targetBlock.StartOffset), GetLLVMBasicBlockForBlock(targetBlock));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// leave destination is in a different funclet, this happens when an exception is thrown/rethrown from inside a catch handler and the throw is not directly in a try handler
|
||||
// In this case we need to return out of this funclet to get back to the containing funclet. Logic checks we are actually in a catch funclet as opposed to a finally or the main function funclet
|
||||
ExceptionRegion currentRegion = GetTryRegion(_currentBasicBlock.StartOffset);
|
||||
if (currentRegion != null && _currentBasicBlock.StartOffset >= currentRegion.ILRegion.HandlerOffset && _currentBasicBlock.StartOffset < currentRegion.ILRegion.HandlerOffset + currentRegion.ILRegion.HandlerLength
|
||||
&& currentRegion.ILRegion.Kind == ILExceptionRegionKind.Catch)
|
||||
{
|
||||
if (switchReturnBlock == default)
|
||||
{
|
||||
switchReturnBlock = _currentFunclet.AppendBasicBlock("SwitchReturn");
|
||||
}
|
||||
@switch.AddCase(BuildConstInt32(targetBlock.StartOffset), switchReturnBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (switchReturnBlock != default)
|
||||
{
|
||||
landingPadBuilder.PositionAtEnd(switchReturnBlock);
|
||||
landingPadBuilder.BuildRet(landingPadBuilder.BuildLoad(leaveDestination, "loadLeaveDest"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5221,10 +5250,11 @@ namespace Internal.IL
|
|||
while (i >= 0)
|
||||
{
|
||||
int tryStart = _exceptionRegions[i].ILRegion.TryOffset;
|
||||
int tryLength = _exceptionRegions[i].ILRegion.TryLength;
|
||||
for (var j = 0; j < _exceptionRegions.Length; j++)
|
||||
{
|
||||
ExceptionRegion exceptionRegion = _exceptionRegions[j];
|
||||
if (exceptionRegion.ILRegion.TryOffset != tryStart) continue;
|
||||
if (exceptionRegion.ILRegion.TryOffset != tryStart || exceptionRegion.ILRegion.TryLength != tryLength) continue;
|
||||
// if (i > 0)
|
||||
// {
|
||||
// ExceptionRegion previousClause = _exceptionRegions[i - 1];
|
||||
|
@ -5261,8 +5291,7 @@ namespace Internal.IL
|
|||
|
||||
builder.EmitCompressedUInt((uint)exceptionRegion.ILRegion.TryOffset);
|
||||
|
||||
uint tryLength = (uint)exceptionRegion.ILRegion.TryLength;
|
||||
builder.EmitCompressedUInt((tryLength << 2) | (uint)clauseKind);
|
||||
builder.EmitCompressedUInt(((uint)tryLength << 2) | (uint)clauseKind);
|
||||
|
||||
RelocType rel = (_compilation.NodeFactory.Target.IsWindows)
|
||||
? RelocType.IMAGE_REL_BASED_ABSOLUTE
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace System.Runtime
|
|||
}
|
||||
|
||||
// TODO: temporary to try things out, when working look to see how to refactor with FindFirstPassHandler
|
||||
private static bool FindFirstPassHandlerWasm(object exception, uint idxStart, uint idxTryLandingStart /* the start IL idx of the try region for the landing pad, will use in place of PC */,
|
||||
private static bool FindFirstPassHandlerWasm(object exception, uint idxStart, uint idxCurrentBlockStart /* the start IL idx of the current block for the landing pad, will use in place of PC */,
|
||||
void* shadowStack, ref EHClauseIterator clauseIter, out uint tryRegionIdx, out byte* pHandler)
|
||||
{
|
||||
pHandler = (byte*)0;
|
||||
|
@ -74,7 +74,7 @@ namespace System.Runtime
|
|||
EHClauseIterator.RhEHClauseKindWasm clauseKind = ehClause._clauseKind;
|
||||
if (((clauseKind != EHClauseIterator.RhEHClauseKindWasm.RH_EH_CLAUSE_TYPED) &&
|
||||
(clauseKind != EHClauseIterator.RhEHClauseKindWasm.RH_EH_CLAUSE_FILTER))
|
||||
|| !ehClause.ContainsCodeOffset(idxTryLandingStart))
|
||||
|| !ehClause.ContainsCodeOffset(idxCurrentBlockStart))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -1412,6 +1412,8 @@ internal static class Program
|
|||
TestFilter();
|
||||
|
||||
TestFilterNested();
|
||||
|
||||
TestCatchAndThrow();
|
||||
}
|
||||
|
||||
private static void TestTryCatchNoException()
|
||||
|
@ -1624,6 +1626,32 @@ internal static class Program
|
|||
EndTest(exceptionFlowSequence == @"In middle catchRunning outer filterIn outer catchRunning inner filterIn inner catch");
|
||||
}
|
||||
|
||||
private static void TestCatchAndThrow()
|
||||
{
|
||||
StartTest("Test catch and throw different exception");
|
||||
int caught = 0;
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
throw new Exception("first");
|
||||
}
|
||||
catch
|
||||
{
|
||||
caught += 1;
|
||||
throw new Exception("second");
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
if(e.Message == "second")
|
||||
{
|
||||
caught += 10;
|
||||
}
|
||||
}
|
||||
EndTest(caught == 11);
|
||||
}
|
||||
|
||||
static bool Print(string s)
|
||||
{
|
||||
exceptionFlowSequence += $"Running {s} filter";
|
||||
|
|
Загрузка…
Ссылка в новой задаче