Skip to content

Commit

Permalink
add support for fixed statement (single var)
Browse files Browse the repository at this point in the history
  • Loading branch information
adrianoc committed Oct 18, 2019
1 parent e7e033b commit 67a6f65
Show file tree
Hide file tree
Showing 9 changed files with 131 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.locals (System.Int32& V_0)
IL_0000: ldarg.0
IL_0001: ldflda System.Int32 FixedStatementTest::i
IL_0006: stloc V_0
IL_000a: ldloc V_0
IL_000e: conv.u
IL_000f: ret
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@

unsafe void FixedStatement()
class FixedStatementTest
{
int i = 0;
fixed (int* p = &i) { }
public int i;
unsafe int* FixedStatement()
{
fixed (int* p = &i)
{
return p;
}
}
}
14 changes: 14 additions & 0 deletions Cecilifier.Core.Tests/Tests/Integration/StatementTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using NUnit.Framework;

namespace Cecilifier.Core.Tests.Integration
{
[TestFixture]
public class StatementTests : IntegrationResourceBasedTest
{
[Test]
public void TestFixedStatement()
{
AssertResourceTestWithExplicitExpectation(@"Statements/FixedStatement", "System.Int32* FixedStatementTest::FixedStatement()");
}
}
}
18 changes: 16 additions & 2 deletions Cecilifier.Core/AST/ExpressionVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -501,14 +501,19 @@ private void ProcessProperty(SimpleNameSyntax node, IPropertySymbol propertySymb
}
}

private void ProcessField(IFieldSymbol fieldSymbol)
private void ProcessField(SimpleNameSyntax node, IFieldSymbol fieldSymbol)
{
if (fieldSymbol.IsStatic && fieldSymbol.IsDefinedInCurrentType(Context))
{
throw new Exception("Static field handling not implemented yet");
}

AddCilInstruction(ilVar, OpCodes.Ldarg_0);

if (HandleLoadAddress(ilVar, fieldSymbol.Type, (CSharpSyntaxNode) node.Parent, OpCodes.Ldflda, fieldSymbol.Name, MemberKind.Field, fieldSymbol.ContainingType.Name))
{
return;
}
AddCilInstruction(ilVar, OpCodes.Ldfld, Context.DefinitionVariables.GetVariable(fieldSymbol.Name, MemberKind.Field, fieldSymbol.ContainingType.Name).VariableName);
}

Expand All @@ -523,6 +528,15 @@ private void ProcessLocalVariable(SimpleNameSyntax localVar, SymbolInfo varInfo)

AddCilInstruction(ilVar, OpCodes.Ldloc, Context.DefinitionVariables.GetVariable(symbol.Name, MemberKind.LocalVariable).VariableName);
HandlePotentialDelegateInvocationOn(localVar, symbol.Type, ilVar);
HandlePotentialFixedLoad(localVar, symbol);
}

private void HandlePotentialFixedLoad(SyntaxNode localVar, ILocalSymbol symbol)
{
if (!symbol.IsFixed)
return;

AddCilInstruction(ilVar, OpCodes.Conv_U);
}

private void ProcessMethodCall(SimpleNameSyntax node, IMethodSymbol method)
Expand Down Expand Up @@ -653,7 +667,7 @@ private void HandleIdentifier(SimpleNameSyntax node)
break;

case SymbolKind.Field:
ProcessField(member.Symbol as IFieldSymbol);
ProcessField(node, member.Symbol as IFieldSymbol);
break;

case SymbolKind.Property:
Expand Down
6 changes: 6 additions & 0 deletions Cecilifier.Core/AST/IVisitorContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,12 @@ internal interface IVisitorContext
void TriggerInstructionAdded(string instVar);

ITypeResolver TypeResolver { get; }

#region Flags Handling
IDisposable WithFlag(string name);
bool HasFlag(string name);

#endregion
}

internal interface ITypeResolver
Expand Down
39 changes: 33 additions & 6 deletions Cecilifier.Core/AST/StatementVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,16 @@ public override void VisitUnsafeStatement(UnsafeStatementSyntax node)
LogUnsupportedSyntax(node);
}

public override void VisitFixedStatement(FixedStatementSyntax node)
{
using (Context.WithFlag("fixed"))
{
HandleVariableDeclaration(node.Declaration);
}

Visit(node.Statement);
}

public override void VisitBlock(BlockSyntax node)
{
using (Context.DefinitionVariables.EnterScope())
Expand All @@ -78,12 +88,7 @@ public override void VisitIfStatement(IfStatementSyntax node)

public override void VisitLocalDeclarationStatement(LocalDeclarationStatementSyntax node)
{
var methodVar = Context.DefinitionVariables.GetLastOf(MemberKind.Method).VariableName;
foreach (var localVar in node.Declaration.Variables)
{
AddLocalVariable(node.Declaration.Type, localVar, methodVar);
ProcessVariableInitialization(localVar);
}
HandleVariableDeclaration(node.Declaration);
}

public override void VisitTryStatement(TryStatementSyntax node)
Expand Down Expand Up @@ -194,10 +199,22 @@ void SetFinallyStart(string instVar)

private void AddLocalVariable(TypeSyntax type, VariableDeclaratorSyntax localVar, string methodVar)
{
var isFixedStatement = Context.HasFlag("fixed");
if (isFixedStatement)
{
type = ((PointerTypeSyntax) type).ElementType;
}

var resolvedVarType = type.IsVar
? ResolveExpressionType(localVar.Initializer.Value)
: ResolveType(type);


if (isFixedStatement)
{
resolvedVarType = $"{resolvedVarType}.MakeByReferenceType()";
}

var cecilVarDeclName = TempLocalVar($"lv_{localVar.Identifier.ValueText}");
AddCecilExpression("var {0} = new VariableDefinition({1});", cecilVarDeclName, resolvedVarType);
AddCecilExpression("{0}.Body.Variables.Add({1});", methodVar, cecilVarDeclName);
Expand All @@ -216,6 +233,16 @@ private void ProcessVariableInitialization(VariableDeclaratorSyntax localVar)
AddCilInstruction(_ilVar, OpCodes.Stloc, localVarDef.VariableName);
}

private void HandleVariableDeclaration(VariableDeclarationSyntax declaration)
{
var methodVar = Context.DefinitionVariables.GetLastOf(MemberKind.Method).VariableName;
foreach (var localVar in declaration.Variables)
{
AddLocalVariable(declaration.Type, localVar, methodVar);
ProcessVariableInitialization(localVar);
}
}

private struct ExceptionHandlerEntry
{
public ExceptionHandlerType Kind;
Expand Down
6 changes: 3 additions & 3 deletions Cecilifier.Core/AST/SyntaxWalkerBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -319,12 +319,12 @@ protected void ProcessParameter(string ilVar, SimpleNameSyntax node, IParameterS
}
}

protected bool HandleLoadAddress(string ilVar, ITypeSymbol symbol, CSharpSyntaxNode parent, OpCode opCode, string symbolName, MemberKind memberKind)
protected bool HandleLoadAddress(string ilVar, ITypeSymbol symbol, CSharpSyntaxNode parent, OpCode opCode, string symbolName, MemberKind memberKind, string parentName = null)
{
if ((symbol.IsValueType && parent.Accept(new UsageVisitor()) == UsageKind.CallTarget) || parent.IsKind(SyntaxKind.AddressOfExpression))
{
AddCilInstruction(ilVar, opCode, Context.DefinitionVariables.GetVariable(symbolName, memberKind).VariableName);
if (parent.IsKind(SyntaxKind.AddressOfExpression))
AddCilInstruction(ilVar, opCode, Context.DefinitionVariables.GetVariable(symbolName, memberKind, parentName).VariableName);
if (!Context.HasFlag("fixed") && parent.IsKind(SyntaxKind.AddressOfExpression))
AddCilInstruction(ilVar, OpCodes.Conv_U);

return true;
Expand Down
21 changes: 21 additions & 0 deletions Cecilifier.Core/Misc/CecilifierContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace Cecilifier.Core.Misc
{
internal class CecilifierContext : IVisitorContext
{
private readonly ISet<string> flags = new HashSet<string>();
private readonly LinkedList<string> output = new LinkedList<string>();

private int currentFieldId;
Expand Down Expand Up @@ -103,6 +104,26 @@ public void TriggerInstructionAdded(string instVar)
{
InstructionAdded?.Invoke(instVar);
}

public IDisposable WithFlag(string name)
{
return new ContextFlagReseter(this, name);
}

public bool HasFlag(string name)
{
return flags.Contains(name);
}

internal void SetFlag(string name)
{
flags.Add(name);
}

internal void ClearFlag(string name)
{
flags.Remove(name);
}
}

internal class TypeResolverImpl : ITypeResolver
Expand Down
22 changes: 22 additions & 0 deletions Cecilifier.Core/Misc/ContextFlagReseter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System;

namespace Cecilifier.Core.Misc
{
internal class ContextFlagReseter : IDisposable
{
private readonly CecilifierContext _context;
private readonly string _flagName;

public ContextFlagReseter(CecilifierContext context, string flagName)
{
_context = context;
_flagName = flagName;
_context.SetFlag(flagName);
}

public void Dispose()
{
_context.ClearFlag(_flagName);
}
}
}

0 comments on commit 67a6f65

Please sign in to comment.