Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.

Commit

Permalink
Add support for emitting finally regions in ILEmitter (#27109)
Browse files Browse the repository at this point in the history
This will be needed to properly do cleanups in marshalling stubs.

The usage goes like (I couldn't come up with anything better):

```
var b = codeStream.BeginTry();
//...
codeStream.EndTry(b);
codeStream.BeginHandler(b);
// ...
codeStream.EndHandler(b);

emit.NewFinallyRegion(b);
```
  • Loading branch information
MichalStrehovsky authored and jkotas committed Oct 11, 2019
1 parent d8bbcc4 commit a7ffbba
Show file tree
Hide file tree
Showing 2 changed files with 139 additions and 9 deletions.
39 changes: 37 additions & 2 deletions src/tools/crossgen2/Common/TypeSystem/IL/MethodILDebugView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,45 @@ public string Disassembly
}
sb.AppendLine();

// TODO: exception regions
const string pad = " ";

// TODO: pretty exception regions
foreach (ILExceptionRegion region in _methodIL.GetExceptionRegions())
{
sb.Append(pad);
sb.Append(".try ");
ILDisassembler.AppendOffset(sb, region.TryOffset);
sb.Append(" to ");
ILDisassembler.AppendOffset(sb, region.TryOffset + region.TryLength);

switch (region.Kind)
{
case ILExceptionRegionKind.Catch:
sb.Append(" catch ");
disasm.AppendType(sb, (TypeDesc)_methodIL.GetObject(region.ClassToken));
break;
case ILExceptionRegionKind.Fault:
sb.Append(" fault");
break;
case ILExceptionRegionKind.Filter:
sb.Append(" filter ");
ILDisassembler.AppendOffset(sb, region.FilterOffset);
break;
case ILExceptionRegionKind.Finally:
sb.Append(" finally");
break;
}

sb.Append(" handler ");
ILDisassembler.AppendOffset(sb, region.HandlerOffset);
sb.Append(" to ");
ILDisassembler.AppendOffset(sb, region.HandlerOffset + region.HandlerLength);
sb.AppendLine();
}

while (disasm.HasNextInstruction)
{
sb.Append(" ");
sb.Append(pad);
sb.AppendLine(disasm.GetNextInstruction());
}

Expand Down
109 changes: 102 additions & 7 deletions src/tools/crossgen2/Common/TypeSystem/IL/Stubs/ILEmitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ namespace Internal.IL.Stubs
{
public class ILCodeStream
{
private const int StartOffsetNotSet = -1;

private struct LabelAndOffset
{
public readonly ILCodeLabel Label;
Expand All @@ -37,10 +39,16 @@ public LabelAndOffset(ILCodeLabel label, int offset)
internal ILCodeStream(ILEmitter emitter)
{
_instructions = Array.Empty<byte>();
_startOffsetForLinking = -1;
_startOffsetForLinking = StartOffsetNotSet;
_emitter = emitter;
}

internal int RelativeToAbsoluteOffset(int relativeOffset)
{
Debug.Assert(_startOffsetForLinking != StartOffsetNotSet);
return _startOffsetForLinking + relativeOffset;
}

private void EmitByte(byte b)
{
if (_instructions.Length == _length)
Expand Down Expand Up @@ -417,14 +425,42 @@ public void EmitLabel(ILCodeLabel label)
label.Place(this, _length);
}

public void BeginTry(ILExceptionRegionBuilder builder)
{
Debug.Assert(builder._beginTryStream == null);
builder._beginTryStream = this;
builder._beginTryOffset = _length;
}

public void EndTry(ILExceptionRegionBuilder builder)
{
Debug.Assert(builder._endTryStream == null);
builder._endTryStream = this;
builder._endTryOffset = _length;
}

public void BeginHandler(ILExceptionRegionBuilder builder)
{
Debug.Assert(builder._beginHandlerStream == null);
builder._beginHandlerStream = this;
builder._beginHandlerOffset = _length;
}

public void EndHandler(ILExceptionRegionBuilder builder)
{
Debug.Assert(builder._endHandlerStream == null);
builder._endHandlerStream = this;
builder._endHandlerOffset = _length;
}

internal void PatchLabels()
{
for (int i = 0; i < _offsetsNeedingPatching.Count; i++)
{
LabelAndOffset patch = _offsetsNeedingPatching[i];

Debug.Assert(patch.Label.IsPlaced);
Debug.Assert(_startOffsetForLinking > -1);
Debug.Assert(_startOffsetForLinking != StartOffsetNotSet);

int offset = patch.Offset;

Expand Down Expand Up @@ -456,6 +492,34 @@ public void DefineSequencePoint(string document, int lineNumber)
}
}

public class ILExceptionRegionBuilder
{
internal ILCodeStream _beginTryStream;
internal int _beginTryOffset;

internal ILCodeStream _endTryStream;
internal int _endTryOffset;

internal ILCodeStream _beginHandlerStream;
internal int _beginHandlerOffset;

internal ILCodeStream _endHandlerStream;
internal int _endHandlerOffset;

internal ILExceptionRegionBuilder()
{
}

internal int TryOffset => _beginTryStream.RelativeToAbsoluteOffset(_beginTryOffset);
internal int TryLength => _endTryStream.RelativeToAbsoluteOffset(_endTryOffset) - TryOffset;
internal int HandlerOffset => _beginHandlerStream.RelativeToAbsoluteOffset(_beginHandlerOffset);
internal int HandlerLength => _endHandlerStream.RelativeToAbsoluteOffset(_endHandlerOffset) - HandlerOffset;

internal bool IsDefined =>
_beginTryStream != null && _endTryStream != null
&& _beginHandlerStream != null && _endHandlerStream != null;
}

/// <summary>
/// Represent a token. Use one of the overloads of <see cref="ILEmitter.NewToken"/>
/// to create a new token.
Expand All @@ -473,19 +537,24 @@ public class ILStubMethodIL : MethodIL
private readonly LocalVariableDefinition[] _locals;
private readonly Object[] _tokens;
private readonly MethodDesc _method;
private readonly ILExceptionRegion[] _exceptionRegions;
private readonly MethodDebugInformation _debugInformation;

private const int MaxStackNotSet = -1;
private int _maxStack;

public ILStubMethodIL(MethodDesc owningMethod, byte[] ilBytes, LocalVariableDefinition[] locals, Object[] tokens, MethodDebugInformation debugInfo = null)
public ILStubMethodIL(MethodDesc owningMethod, byte[] ilBytes, LocalVariableDefinition[] locals, Object[] tokens, ILExceptionRegion[] exceptionRegions = null, MethodDebugInformation debugInfo = null)
{
_ilBytes = ilBytes;
_locals = locals;
_tokens = tokens;
_method = owningMethod;
_maxStack = MaxStackNotSet;

if (exceptionRegions == null)
exceptionRegions = Array.Empty<ILExceptionRegion>();
_exceptionRegions = exceptionRegions;

if (debugInfo == null)
debugInfo = MethodDebugInformation.None;
_debugInformation = debugInfo;
Expand Down Expand Up @@ -531,7 +600,7 @@ public override int MaxStack

public override ILExceptionRegion[] GetExceptionRegions()
{
return Array.Empty<ILExceptionRegion>();
return _exceptionRegions;
}
public override bool IsInitLocals
{
Expand Down Expand Up @@ -569,8 +638,7 @@ internal int AbsoluteOffset
get
{
Debug.Assert(IsPlaced);
Debug.Assert(_codeStream._startOffsetForLinking >= 0);
return _codeStream._startOffsetForLinking + _offsetWithinCodeStream;
return _codeStream.RelativeToAbsoluteOffset(_offsetWithinCodeStream);
}
}

Expand All @@ -591,6 +659,7 @@ public class ILEmitter
private ArrayBuilder<ILCodeStream> _codeStreams;
private ArrayBuilder<LocalVariableDefinition> _locals;
private ArrayBuilder<Object> _tokens;
private ArrayBuilder<ILExceptionRegionBuilder> _finallyRegions;

public ILEmitter()
{
Expand Down Expand Up @@ -648,6 +717,13 @@ public ILCodeLabel NewCodeLabel()
return newLabel;
}

public ILExceptionRegionBuilder NewFinallyRegion()
{
var region = new ILExceptionRegionBuilder();
_finallyRegions.Add(region);
return region;
}

public MethodIL Link(MethodDesc owningMethod)
{
int totalLength = 0;
Expand Down Expand Up @@ -694,7 +770,26 @@ public MethodIL Link(MethodDesc owningMethod)
debugInfo = new EmittedMethodDebugInformation(sequencePoints);
}

var result = new ILStubMethodIL(owningMethod, ilInstructions, _locals.ToArray(), _tokens.ToArray(), debugInfo);
ILExceptionRegion[] exceptionRegions = null;

int numberOfExceptionRegions = _finallyRegions.Count;
if (numberOfExceptionRegions > 0)
{
exceptionRegions = new ILExceptionRegion[numberOfExceptionRegions];

for (int i = 0; i < _finallyRegions.Count; i++)
{
ILExceptionRegionBuilder region = _finallyRegions[i];

Debug.Assert(region.IsDefined);

exceptionRegions[i] = new ILExceptionRegion(ILExceptionRegionKind.Finally,
region.TryOffset, region.TryLength, region.HandlerOffset, region.HandlerLength,
classToken: 0, filterOffset: 0);
}
}

var result = new ILStubMethodIL(owningMethod, ilInstructions, _locals.ToArray(), _tokens.ToArray(), exceptionRegions, debugInfo);
result.CheckStackBalance();
return result;
}
Expand Down

0 comments on commit a7ffbba

Please sign in to comment.