Skip to content

Commit

Permalink
Abstract LocalBuilder, emit LocalBuilder in ILGenerator
Browse files Browse the repository at this point in the history
  • Loading branch information
buyaa-n committed Oct 25, 2023
1 parent ae7f502 commit 22108d2
Show file tree
Hide file tree
Showing 21 changed files with 371 additions and 78 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -162,14 +162,14 @@
<Compile Include="$(BclSourcesRoot)\System\Reflection\Emit\CustomAttributeBuilder.cs" />
<Compile Include="$(BclSourcesRoot)\System\Reflection\Emit\DynamicILGenerator.cs" />
<Compile Include="$(BclSourcesRoot)\System\Reflection\Emit\DynamicMethod.CoreCLR.cs" />
<Compile Include="$(BclSourcesRoot)\System\Reflection\Emit\LocalBuilder.cs" />
<Compile Include="$(BclSourcesRoot)\System\Reflection\Emit\RuntimeAssemblyBuilder.cs" />
<Compile Include="$(BclSourcesRoot)\System\Reflection\Emit\RuntimeConstructorBuilder.cs" />
<Compile Include="$(BclSourcesRoot)\System\Reflection\Emit\RuntimeEnumBuilder.cs" />
<Compile Include="$(BclSourcesRoot)\System\Reflection\Emit\RuntimeEventBuilder.cs" />
<Compile Include="$(BclSourcesRoot)\System\Reflection\Emit\RuntimeFieldBuilder.cs" />
<Compile Include="$(BclSourcesRoot)\System\Reflection\Emit\RuntimeGenericTypeParameterBuilder.cs" />
<Compile Include="$(BclSourcesRoot)\System\Reflection\Emit\RuntimeILGenerator.cs" />
<Compile Include="$(BclSourcesRoot)\System\Reflection\Emit\RuntimeLocalBuilder.cs" />
<Compile Include="$(BclSourcesRoot)\System\Reflection\Emit\RuntimeMethodBuilder.cs" />
<Compile Include="$(BclSourcesRoot)\System\Reflection\Emit\RuntimeModuleBuilder.cs" />
<Compile Include="$(BclSourcesRoot)\System\Reflection\Emit\RuntimeParameterBuilder.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ public override LocalBuilder DeclareLocal(Type localType, bool pinned)
{
ArgumentNullException.ThrowIfNull(localType);

LocalBuilder localBuilder;
RuntimeLocalBuilder localBuilder;

RuntimeType? rtType = localType as RuntimeType;

if (rtType == null)
throw new ArgumentException(SR.Argument_MustBeRuntimeType);

localBuilder = new LocalBuilder(m_localCount, localType, m_methodBuilder, pinned);
localBuilder = new RuntimeLocalBuilder(m_localCount, localType, m_methodBuilder, pinned);
// add the localType to local signature
m_localSignature.AddArgument(localType, pinned);
m_localCount++;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -819,8 +819,8 @@ public override void Emit(OpCode opcode, LocalBuilder local)
ArgumentNullException.ThrowIfNull(local);

// Puts the opcode onto the IL stream followed by the information for local variable local.
int tempVal = local.GetLocalIndex();
if (local.GetMethodBuilder() != m_methodBuilder)
int tempVal = local.LocalIndex;
if (local.Method != m_methodBuilder)
{
throw new ArgumentException(SR.Argument_UnmatchedMethodForLocal, nameof(local));
}
Expand Down Expand Up @@ -1185,7 +1185,7 @@ public override LocalBuilder DeclareLocal(Type localType, bool pinned)
// add the localType to local signature
m_localSignature.AddArgument(localType, pinned);

return new LocalBuilder(m_localCount++, localType, methodBuilder, pinned);
return new RuntimeLocalBuilder(m_localCount++, localType, methodBuilder, pinned);
}

public override void UsingNamespace(string usingNamespace)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace System.Reflection.Emit
{
public sealed class LocalBuilder : LocalVariableInfo
internal sealed class RuntimeLocalBuilder : LocalBuilder
{
#region Private Data Members
private readonly int m_localIndex;
Expand All @@ -13,9 +13,9 @@ public sealed class LocalBuilder : LocalVariableInfo
#endregion

#region Constructor
internal LocalBuilder(int localIndex, Type localType, MethodInfo methodBuilder)
internal RuntimeLocalBuilder(int localIndex, Type localType, MethodInfo methodBuilder)
: this(localIndex, localType, methodBuilder, false) { }
internal LocalBuilder(int localIndex, Type localType, MethodInfo methodBuilder, bool isPinned)
internal RuntimeLocalBuilder(int localIndex, Type localType, MethodInfo methodBuilder, bool isPinned)
{
m_isPinned = isPinned;
m_localIndex = localIndex;
Expand All @@ -24,21 +24,11 @@ internal LocalBuilder(int localIndex, Type localType, MethodInfo methodBuilder,
}
#endregion

#region Internal Members
internal int GetLocalIndex()
{
return m_localIndex;
}
internal MethodInfo GetMethodBuilder()
{
return m_methodBuilder;
}
#endregion

#region LocalVariableInfo Override
public override bool IsPinned => m_isPinned;
public override Type LocalType => m_localType;
public override int LocalIndex => m_localIndex;
public override MethodInfo Method => m_methodBuilder;
#endregion
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,6 @@
<Compile Include="System\Reflection\Emit\CustomAttributeBuilder.cs" />
<Compile Include="System\Reflection\Emit\DynamicILInfo.cs" />
<Compile Include="System\Reflection\Emit\DynamicMethod.cs" />
<Compile Include="System\Reflection\Emit\LocalBuilder.cs" />
<Compile Include="System\Reflection\Emit\ReflectionEmitThrower.cs" />
<Compile Include="System\Reflection\Emit\SignatureHelper.cs" />
<Compile Include="System\Reflection\EnumInfo.cs" />
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,6 @@
<Compile Include="$(MSBuildThisFileDirectory)System\IFormatProvider.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IFormattable.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Index.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\Emit\ILGenerator.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SearchValues\BitVector256.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SearchValues\ProbabilisticWithAsciiCharSearchValues.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\SearchValues\SingleCharSearchValues.cs" />
Expand Down Expand Up @@ -672,7 +671,9 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\Emit\FieldOnTypeBuilderInstantiation.cs" Condition="'$(FeatureNativeAot)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\Emit\FlowControl.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\Emit\GenericTypeParameterBuilder.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\Emit\ILGenerator.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\Emit\Label.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\Emit\LocalBuilder.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\Emit\MethodBuilder.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\Emit\MethodBuilderInstantiation.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Reflection\Emit\MethodOnTypeBuilderInstantiation.cs" Condition="'$(FeatureNativeAot)' != 'true'" />
Expand Down Expand Up @@ -2719,4 +2720,4 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Numerics\IUnaryPlusOperators.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Numerics\IUnsignedNumber.cs" />
</ItemGroup>
</Project>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System.Reflection.Emit
{
public abstract class LocalBuilder : LocalVariableInfo
{
/// <summary>
/// Initializes a new instance of the <see cref="LocalBuilder"/> class.
/// </summary>
/// <remarks>
/// This constructor is invoked by derived classes.
/// </remarks>
protected LocalBuilder() { }

/// <summary>
/// Returns the method where the local variable declared.
/// </summary>
/// <remarks>Can be used for validating the containing method when referencing the local.</remarks>
public abstract MethodInfo Method { get; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,13 @@ public virtual void ThrowException([System.Diagnostics.CodeAnalysis.DynamicallyA
public static bool operator ==(System.Reflection.Emit.Label a, System.Reflection.Emit.Label b) { throw null; }
public static bool operator !=(System.Reflection.Emit.Label a, System.Reflection.Emit.Label b) { throw null; }
}
public sealed partial class LocalBuilder : System.Reflection.LocalVariableInfo
public abstract class LocalBuilder : System.Reflection.LocalVariableInfo
{
internal LocalBuilder() { }
protected LocalBuilder() { }
public override bool IsPinned { get { throw null; } }
public override int LocalIndex { get { throw null; } }
public override System.Type LocalType { get { throw null; } }
public abstract MethodInfo Method { get; }
}
public abstract partial class ParameterBuilder
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Xunit;

namespace System.Reflection.Emit.Tests
{
// Mono doesn't support LocalBuilder.Method
[ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMonoRuntime))]
public class LocalBuilderMethod
{
[Fact]
public void LocalBuilder_MethodReturnsCorrectMethod()
{
TypeBuilder type = Helpers.DynamicType(TypeAttributes.NotPublic);
MethodBuilder method1 = type.DefineMethod("Method1", MethodAttributes.Public);
MethodBuilder method2 = type.DefineMethod("Method2", MethodAttributes.Public);
ILGenerator ilGenerator1 = method1.GetILGenerator();
ILGenerator ilGenerator2 = method2.GetILGenerator();
LocalBuilder local1 = ilGenerator1.DeclareLocal(typeof(int));
LocalBuilder local2 = ilGenerator2.DeclareLocal(typeof(string), true);

Assert.Equal(method1, local1.Method);
Assert.Equal(method2, local2.Method);
}

[Fact]
public void LocalBuilder_UseLocalsThatBelongsToTheMethod()
{
TypeBuilder type = Helpers.DynamicType(TypeAttributes.NotPublic);
MethodBuilder method1 = type.DefineMethod("Method1", MethodAttributes.Public);
MethodBuilder method2 = type.DefineMethod("Method2", MethodAttributes.Public);
ILGenerator ilGenerator1 = method1.GetILGenerator();
ILGenerator ilGenerator2 = method2.GetILGenerator();
LocalBuilder local1 = ilGenerator1.DeclareLocal(typeof(short));
LocalBuilder local2 = ilGenerator2.DeclareLocal(typeof(long), true);

ilGenerator1.Emit(OpCodes.Ldloc, local1);
ilGenerator2.Emit(OpCodes.Ldloc, local2);

Assert.Throws<ArgumentException>(() => ilGenerator1.Emit(OpCodes.Ldloc, local2));
Assert.Throws<ArgumentException>(() => ilGenerator2.Emit(OpCodes.Ldloc, local1));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
<Compile Include="LocalBuilder\LocalBuilderIsPinned.cs" />
<Compile Include="LocalBuilder\LocalBuilderLocalIndex.cs" />
<Compile Include="LocalBuilder\LocalBuilderLocalType.cs" />
<Compile Include="LocalBuilder\LocalBuilderMethod.cs" />
<Compile Include="ParameterBuilder\PropertyTests.cs" />
<Compile Include="ParameterBuilder\SetConstant.cs" />
<Compile Include="ParameterBuilder\SetCustomAttributeTests.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,4 +186,7 @@
<data name="InvalidOperation_ShouldNotHaveMethodBody" xml:space="preserve">
<value>Method body should not exist.</value>
</data>
<data name="Argument_UnmatchedMethodForLocal" xml:space="preserve">
<value>Local passed in does not belong to this ILGenerator.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<Compile Include="System\Reflection\Emit\FieldBuilderImpl.cs" />
<Compile Include="System\Reflection\Emit\GenericTypeParameterBuilderImpl.cs" />
<Compile Include="System\Reflection\Emit\ILGeneratorImpl.cs" />
<Compile Include="System\Reflection\Emit\LocalBuilderImpl.cs" />
<Compile Include="System\Reflection\Emit\MethodBuilderImpl.cs" />
<Compile Include="System\Reflection\Emit\ModuleBuilderImpl.cs" />
<Compile Include="System\Reflection\Emit\ParameterBuilderImpl.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Runtime.InteropServices;
Expand All @@ -16,6 +17,8 @@ internal sealed class ILGeneratorImpl : ILGenerator
private bool _hasDynamicStackAllocation;
private int _maxStackSize;
private int _currentStack;
private List<LocalBuilder>? _locals;
private int _localCount;

internal ILGeneratorImpl(MethodBuilder methodBuilder, int size)
{
Expand All @@ -29,6 +32,7 @@ internal ILGeneratorImpl(MethodBuilder methodBuilder, int size)

internal InstructionEncoder Instructions => _il;
internal bool HasDynamicStackAllocation => _hasDynamicStackAllocation;
internal List<LocalBuilder>? Locals => _locals;

public override int ILOffset => _il.Offset;

Expand All @@ -38,7 +42,20 @@ internal ILGeneratorImpl(MethodBuilder methodBuilder, int size)
public override void BeginFaultBlock() => throw new NotImplementedException();
public override void BeginFinallyBlock() => throw new NotImplementedException();
public override void BeginScope() => throw new NotImplementedException();
public override LocalBuilder DeclareLocal(Type localType, bool pinned) => throw new NotImplementedException();
public override LocalBuilder DeclareLocal(Type localType, bool pinned)
{
if (_methodBuilder is not MethodBuilderImpl methodBuilder)
throw new NotSupportedException();

ArgumentNullException.ThrowIfNull(localType);

LocalBuilder local = new LocalBuilderImpl(_localCount++, localType, methodBuilder, pinned);
_locals ??= new();
_locals.Add(local);

return local;
}

public override Label DefineLabel() => throw new NotImplementedException();

private void UpdateStackSize(OpCode opCode)
Expand Down Expand Up @@ -192,7 +209,31 @@ public override void Emit(OpCode opcode, string str)
public override void Emit(OpCode opcode, ConstructorInfo con) => throw new NotImplementedException();
public override void Emit(OpCode opcode, Label label) => throw new NotImplementedException();
public override void Emit(OpCode opcode, Label[] labels) => throw new NotImplementedException();
public override void Emit(OpCode opcode, LocalBuilder local) => throw new NotImplementedException();
public override void Emit(OpCode opcode, LocalBuilder local)
{
ArgumentNullException.ThrowIfNull(local);

if (local.Method != _methodBuilder)
{
throw new ArgumentException(SR.Argument_UnmatchedMethodForLocal, nameof(local));
}

int tempVal = local.LocalIndex;
if (opcode.Name!.StartsWith("ldloca"))
{
_il.LoadLocalAddress(tempVal);
}
else if (opcode.Name.StartsWith("ldloc"))
{
_il.LoadLocal(tempVal);
}
else if (opcode.Name.StartsWith("stloc"))
{
_il.StoreLocal(tempVal);
}

UpdateStackSize(opcode);
}
public override void Emit(OpCode opcode, SignatureHelper signature) => throw new NotImplementedException();
public override void Emit(OpCode opcode, FieldInfo field) => throw new NotImplementedException();
public override void Emit(OpCode opcode, MethodInfo meth) => throw new NotImplementedException();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System.Reflection.Emit
{
internal sealed class LocalBuilderImpl : LocalBuilder
{
#region Private Data Members
private readonly int _localIndex;
private readonly Type _localType;
private readonly MethodInfo _method;
private readonly bool _isPinned;
#endregion

#region Constructor
internal LocalBuilderImpl(int index, Type type, MethodInfo method, bool isPinned)
{
_isPinned = isPinned;
_localIndex = index;
_localType = type;
_method = method;
}
#endregion

#region LocalVariableInfo Override
public override bool IsPinned => _isPinned;
public override Type LocalType => _localType;
public override int LocalIndex => _localIndex;
public override MethodInfo Method => _method;
#endregion
}
}
Loading

0 comments on commit 22108d2

Please sign in to comment.