Skip to content

Commit

Permalink
support for pointer types / addressof operator
Browse files Browse the repository at this point in the history
merge
  • Loading branch information
adrianoc committed Oct 15, 2019
1 parent 90a7c92 commit 22e5c2d
Show file tree
Hide file tree
Showing 10 changed files with 96 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,8 @@ private static bool EqualOrEquivalent(Instruction instruction, Instruction curre

case Code.Ldarga_S: return current.OpCode.Code == Code.Ldarga;
case Code.Ldarg_S: return current.OpCode.Code == Code.Ldarg;

case Code.Ldloca_S: return current.OpCode.Code == Code.Ldloca;

case Code.Ldc_I4_S:
case Code.Ldc_I4_0:
Expand Down Expand Up @@ -688,8 +690,7 @@ public bool IgnoreNonRequiredLocalVariableAssignments(Instruction inst)
// We have an *stloc X* followed by an *ldloc X* so lets check if we have any other reference to the same
// local var.
var ignoredInstructions = new HashSet<Instruction>();
ignoredInstructions
.Add(inst.Next); // if no other load from *X* is found we need to ignore current instruction (stloc X) and also the next one (ldloc X)
ignoredInstructions.Add(inst.Next); // if no other load from *X* is found we need to ignore current instruction (stloc X) and also the next one (ldloc X)

var current = inst.Next.Next;
while (current != null)
Expand Down
3 changes: 2 additions & 1 deletion Cecilifier.Core.Tests/Framework/CompilationServices.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ private static string InternalCompile(string targetPath, string source, bool exe

var compilationOptions = new CSharpCompilationOptions(
exe ? OutputKind.ConsoleApplication : OutputKind.DynamicallyLinkedLibrary,
optimizationLevel: OptimizationLevel.Release);
optimizationLevel: OptimizationLevel.Release,
allowUnsafe: true);

var compilation = CSharpCompilation.Create(
Path.GetFileNameWithoutExtension(outputFilePath),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class C
{
unsafe int* AddressOfLocalVariables()
{
int i = 42;
int *p = &i;
return p;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
class C
{
unsafe int* AddressOfParameter(int i)
{
int *p = &i;
return p;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class C
{
unsafe int* AddressOfLocalVariables()
{
int i = 42;
int *p;
p = &i;
return p;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

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

namespace Cecilifier.Core.Tests.Integration
{
[TestFixture]
public class MiscTestCase : IntegrationResourceBasedTest
{
[TestCase("Parameters")]
[TestCase("Parameters2")]
[TestCase("LocalVariables")]
public void TestDelegateInvocation(string storageType)
{
AssertResourceTest($@"Misc/DelegateInvocation_{storageType}");
}

[Test]
public void TestAccessibilityModifiers()
{
AssertResourceTest(@"Misc/AccessibilityModifiers");
}

[Test]
public void TestNamespaces()
{
AssertResourceTest(@"Misc/Namespaces");
}
}
}
using NUnit.Framework;

namespace Cecilifier.Core.Tests.Integration
{
[TestFixture]
public class MiscTestCase : IntegrationResourceBasedTest
{
[TestCase("Parameters")]
[TestCase("Parameters2")]
[TestCase("LocalVariables")]
public void TestDelegateInvocation(string storageType)
{
AssertResourceTest($@"Misc/DelegateInvocation_{storageType}");
}

[Test]
public void TestAccessibilityModifiers()
{
AssertResourceTest(@"Misc/AccessibilityModifiers");
}

[Test]
public void TestNamespaces()
{
AssertResourceTest(@"Misc/Namespaces");
}

[TestCase("AddressOfParameters", TestName = "Parameters")]
[TestCase("AddressOfLocalVariables", TestName = "Local Variables")]
[TestCase("AssignmentOfAddressOfLocalVariables", TestName = "Local Variable Assignment")]
public void TestPointerTypes(string testName)
{
AssertResourceTest($@"Misc/Pointers/{testName}");
}
}
}
26 changes: 16 additions & 10 deletions Cecilifier.Core/AST/ExpressionVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Operations;
using Mono.Cecil.Cil;

namespace Cecilifier.Core.AST
Expand Down Expand Up @@ -260,17 +261,24 @@ public override void VisitMemberAccessExpression(MemberAccessExpressionSyntax ex

public override void VisitThisExpression(ThisExpressionSyntax node)
{
WriteLine("[{0}] : {1}", new StackFrame().GetMethod().Name, node);
LogUnsupportedSyntax(node);
}

public override void VisitPrefixUnaryExpression(PrefixUnaryExpressionSyntax node)
{
WriteLine("[{0}] : {1}", new StackFrame().GetMethod().Name, node);
if (node.OperatorToken.Kind() == SyntaxKind.AmpersandToken)
{
Visit(node.Operand);
}
else
{
LogUnsupportedSyntax(node);
}
}

public override void VisitPostfixUnaryExpression(PostfixUnaryExpressionSyntax node)
{
WriteLine("[{0}] : {1}", new StackFrame().GetMethod().Name, node);
LogUnsupportedSyntax(node);
}

public override void VisitParenthesizedExpression(ParenthesizedExpressionSyntax node)
Expand Down Expand Up @@ -382,11 +390,6 @@ public override void VisitExpressionStatement(ExpressionStatementSyntax node)
}
}

private void WriteLine(string msg, params object[] args)
{
Console.WriteLine(msg, args);
}

private OpCode LoadOpCodeFor(LiteralExpressionSyntax node)
{
var info = Context.SemanticModel.GetTypeInfo(node);
Expand Down Expand Up @@ -514,12 +517,15 @@ private void ProcessLocalVariable(SimpleNameSyntax localVar, SymbolInfo varInfo)
{
var symbol = (ILocalSymbol) varInfo.Symbol;
var localVarParent = (CSharpSyntaxNode) localVar.Parent;
if (symbol.Type.IsValueType && localVarParent.Accept(new UsageVisitor()) == UsageKind.CallTarget)
if ((symbol.Type.IsValueType && localVarParent.Accept(new UsageVisitor()) == UsageKind.CallTarget) || localVarParent.IsKind(SyntaxKind.AddressOfExpression))
{
AddCilInstruction(ilVar, OpCodes.Ldloca_S, Context.DefinitionVariables.GetVariable(symbol.Name, MemberKind.LocalVariable).VariableName);
AddCilInstruction(ilVar, OpCodes.Ldloca, Context.DefinitionVariables.GetVariable(symbol.Name, MemberKind.LocalVariable).VariableName);
if (localVarParent.IsKind(SyntaxKind.AddressOfExpression))
AddCilInstruction(ilVar, OpCodes.Conv_U);
return;
}


AddCilInstruction(ilVar, OpCodes.Ldloc, Context.DefinitionVariables.GetVariable(symbol.Name, MemberKind.LocalVariable).VariableName);
HandlePotentialDelegateInvocationOn(localVar, symbol.Type, ilVar);
}
Expand Down
4 changes: 3 additions & 1 deletion Cecilifier.Core/AST/SyntaxWalkerBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -296,9 +296,11 @@ protected void ProcessParameter(string ilVar, SimpleNameSyntax node, IParameterS
{
var parent = (CSharpSyntaxNode) node.Parent;
//TODO: Get rid of code duplication in ExpressionVisitor.ProcessLocalVariable(IdentifierNameSyntax localVar, SymbolInfo varInfo)
if (paramSymbol.Type.IsValueType && parent.Accept(new UsageVisitor()) == UsageKind.CallTarget)
if ((paramSymbol.Type.IsValueType && parent.Accept(new UsageVisitor()) == UsageKind.CallTarget) || node.Parent.IsKind(SyntaxKind.AddressOfExpression))
{
AddCilInstruction(ilVar, OpCodes.Ldarga, Context.DefinitionVariables.GetVariable(paramSymbol.Name, MemberKind.Parameter).VariableName);
if (node.Parent.IsKind(SyntaxKind.AddressOfExpression))
AddCilInstruction(ilVar, OpCodes.Conv_U);
return;
}

Expand Down
6 changes: 3 additions & 3 deletions Cecilifier.Core/Extensions/MethodExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,7 @@ public static string LocalVariableNameFor(string prefix, params string[] parts)
return parts.Aggregate(prefix, (acc, curr) => acc + "_" + curr);
}

public static string MethodModifiersToCecil(this SyntaxTokenList modifiers, Func<string, IList<SyntaxToken>, string, string> modifiersToCecil, string specificModifiers = null,
IMethodSymbol methodSymbol = null)
public static string MethodModifiersToCecil(this SyntaxTokenList modifiers, Func<string, IList<SyntaxToken>, string, string> modifiersToCecil, string specificModifiers = null, IMethodSymbol methodSymbol = null)
{
var modifiersStr = MapExplicitModifiers(modifiers);

Expand Down Expand Up @@ -160,7 +159,8 @@ private static IEnumerable<SyntaxToken> RemoveSourceModifiersWithNoILEquivalent(
mod => mod.Kind() != SyntaxKind.OverrideKeyword
&& mod.Kind() != SyntaxKind.AbstractKeyword
&& mod.Kind() != SyntaxKind.VirtualKeyword
&& mod.Kind() != SyntaxKind.SealedKeyword);
&& mod.Kind() != SyntaxKind.SealedKeyword
&& mod.Kind() != SyntaxKind.UnsafeKeyword);
}
}
}

0 comments on commit 22e5c2d

Please sign in to comment.