Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ internal void InternalEmit(OpCode opcode)
m_ILStream[m_length++] = (byte)opcodeValue;
}

UpdateStackSize(opcode, opcode.StackChange());
UpdateStackSize(opcode, opcode.StackDifference());
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ internal OpCode(OpCodeValues value, int flags)
internal bool EndsUncondJmpBlk() =>
(m_flags & EndsUncondJmpBlkFlag) != 0;

internal int StackChange() =>
public int StackDifference() =>
m_flags >> StackChangeShift;

public OperandType OperandType => (OperandType)(m_flags & OperandTypeMask);
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_NotMethodCallOpcode" xml:space="preserve">
<value>The specified opcode cannot be passed to EmitCall.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
using System.Globalization;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;

namespace System.Reflection.Emit
{
Expand All @@ -23,6 +21,7 @@ internal sealed class FieldBuilderImpl : FieldBuilder
internal int _offset;
internal List<CustomAttributeWrapper>? _customAttributes;
internal object? _defaultValue = DBNull.Value;
internal FieldDefinitionHandle _handle;

internal FieldBuilderImpl(TypeBuilderImpl typeBuilder, string fieldName, Type type, FieldAttributes attributes)
{
Expand Down Expand Up @@ -107,7 +106,7 @@ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan
return;
case "System.Runtime.InteropServices.MarshalAsAttribute":
_attributes |= FieldAttributes.HasFieldMarshal;
_marshallingData = MarshallingData.CreateMarshallingData(con, binaryAttribute, isField : true);
_marshallingData = MarshallingData.CreateMarshallingData(con, binaryAttribute, isField: true);
return;
}

Expand All @@ -124,7 +123,7 @@ protected override void SetOffsetCore(int iOffset)

#region MemberInfo Overrides

public override int MetadataToken => throw new NotImplementedException();
public override int MetadataToken => _handle == default ? 0 : MetadataTokens.GetToken(_handle);

public override Module Module => _typeBuilder.Module;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Buffers.Binary;
using System.Collections.Generic;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace System.Reflection.Emit
Expand All @@ -17,6 +16,8 @@ internal sealed class ILGeneratorImpl : ILGenerator
private readonly InstructionEncoder _il;
private bool _hasDynamicStackAllocation;
private int _maxStackSize;
private int _currentStack;
private List<KeyValuePair<MemberInfo, BlobWriter>> _memberReferences = new();

internal ILGeneratorImpl(MethodBuilder methodBuilder, int size)
{
Expand All @@ -27,7 +28,7 @@ internal ILGeneratorImpl(MethodBuilder methodBuilder, int size)
}

internal int GetMaxStackSize() => _maxStackSize;

internal List<KeyValuePair<MemberInfo, BlobWriter>> GetMemberReferences() => _memberReferences;
internal InstructionEncoder Instructions => _il;
internal bool HasDynamicStackAllocation => _hasDynamicStackAllocation;

Expand All @@ -42,40 +43,53 @@ internal ILGeneratorImpl(MethodBuilder methodBuilder, int size)
public override LocalBuilder DeclareLocal(Type localType, bool pinned) => throw new NotImplementedException();
public override Label DefineLabel() => throw new NotImplementedException();

public override void Emit(OpCode opcode)
private void UpdateStackSize(OpCode opCode)
{
_currentStack += opCode.StackDifference();
_maxStackSize = Math.Max(_maxStackSize, _currentStack);
}

private void UpdateStackSize(OpCode opCode, int stackchange)
{
_currentStack += opCode.StackDifference();
_currentStack += stackchange;
_maxStackSize = Math.Max(_maxStackSize, _currentStack);
}

public void EmitOpcode(OpCode opcode)
{
if (opcode == OpCodes.Localloc)
{
_hasDynamicStackAllocation = true;
}
_il.OpCode((ILOpCode)opcode.Value);

// TODO: for now only count the Opcodes emitted, in order to calculate it correctly we might need to make internal Opcode APIs public
// https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Reflection/Emit/Opcode.cs#L48
_maxStackSize++;
_il.OpCode((ILOpCode)opcode.Value);
UpdateStackSize(opcode);
}

public override void Emit(OpCode opcode) => EmitOpcode(opcode);

public override void Emit(OpCode opcode, byte arg)
{
_il.OpCode((ILOpCode)opcode.Value);
EmitOpcode(opcode);
_builder.WriteByte(arg);
}

public override void Emit(OpCode opcode, double arg)
{
_il.OpCode((ILOpCode)opcode.Value);
EmitOpcode(opcode);
_builder.WriteDouble(arg);
}

public override void Emit(OpCode opcode, float arg)
{
_il.OpCode((ILOpCode)opcode.Value);
EmitOpcode(opcode);
_builder.WriteSingle(arg);
}

public override void Emit(OpCode opcode, short arg)
{
_il.OpCode((ILOpCode)opcode.Value);
EmitOpcode(opcode);
_builder.WriteInt16(arg);
}

Expand All @@ -86,98 +100,91 @@ public override void Emit(OpCode opcode, int arg)
{
if (arg >= -1 && arg <= 8)
{
_il.OpCode(arg switch
EmitOpcode(arg switch
{
-1 => ILOpCode.Ldc_i4_m1,
0 => ILOpCode.Ldc_i4_0,
1 => ILOpCode.Ldc_i4_1,
2 => ILOpCode.Ldc_i4_2,
3 => ILOpCode.Ldc_i4_3,
4 => ILOpCode.Ldc_i4_4,
5 => ILOpCode.Ldc_i4_5,
6 => ILOpCode.Ldc_i4_6,
7 => ILOpCode.Ldc_i4_7,
_ => ILOpCode.Ldc_i4_8,
-1 => OpCodes.Ldc_I4_M1,
0 => OpCodes.Ldc_I4_0,
1 => OpCodes.Ldc_I4_1,
2 => OpCodes.Ldc_I4_2,
3 => OpCodes.Ldc_I4_3,
4 => OpCodes.Ldc_I4_4,
5 => OpCodes.Ldc_I4_5,
6 => OpCodes.Ldc_I4_6,
7 => OpCodes.Ldc_I4_7,
_ => OpCodes.Ldc_I4_8
});
return;
}

if (arg >= -128 && arg <= 127)
{
_il.OpCode(ILOpCode.Ldc_i4_s);
_builder.WriteSByte((sbyte)arg) ;
Emit(OpCodes.Ldc_I4_S, (sbyte)arg);
return;
}
}
else if (opcode.Equals(OpCodes.Ldarg))
{
if ((uint)arg <= 3)
{
_il.OpCode(arg switch
EmitOpcode(arg switch
{
0 => ILOpCode.Ldarg_0,
1 => ILOpCode.Ldarg_1,
2 => ILOpCode.Ldarg_2,
_ => ILOpCode.Ldarg_3,
0 => OpCodes.Ldarg_0,
1 => OpCodes.Ldarg_1,
2 => OpCodes.Ldarg_2,
_ => OpCodes.Ldarg_3,
});
return;
}

if ((uint)arg <= byte.MaxValue)
{
_il.OpCode(ILOpCode.Ldarg_s);
_builder.WriteByte((byte)arg);
Emit(OpCodes.Ldarg_S, (byte)arg);
return;
}

if ((uint)arg <= ushort.MaxValue) // this will be true except on misuse of the opcode
{
_il.OpCode(ILOpCode.Ldarg);
_builder.WriteInt16((short)arg);
Emit(OpCodes.Ldarg, (short)arg);
return;
}
}
else if (opcode.Equals(OpCodes.Ldarga))
{
if ((uint)arg <= byte.MaxValue)
{
_il.OpCode(ILOpCode.Ldarga_s);
_builder.WriteByte((byte)arg);
Emit(OpCodes.Ldarga_S, (byte)arg);
return;
}

if ((uint)arg <= ushort.MaxValue) // this will be true except on misuse of the opcode
{
_il.OpCode(ILOpCode.Ldarga);
_builder.WriteInt16((short)arg);
Emit(OpCodes.Ldarga, (short)arg);
return;
}
}
else if (opcode.Equals(OpCodes.Starg))
{
if ((uint)arg <= byte.MaxValue)
{
_il.OpCode(ILOpCode.Starg_s);
_builder.WriteByte((byte)arg);
Emit(OpCodes.Starg_S, (byte)arg);
return;
}

if ((uint)arg <= ushort.MaxValue) // this will be true except on misuse of the opcode
{
_il.OpCode(ILOpCode.Starg);
_builder.WriteInt16((short)arg);
Emit(OpCodes.Starg, (short)arg);
return;
}
}

// For everything else, put the opcode followed by the arg onto the stream of instructions.
_il.OpCode((ILOpCode)opcode.Value);
EmitOpcode(opcode);
_builder.WriteInt32(arg);
}

public override void Emit(OpCode opcode, long arg)
{
_il.OpCode((ILOpCode)opcode.Value);
EmitOpcode(opcode);
_il.CodeBuilder.WriteInt64(arg);
}

Expand All @@ -187,7 +194,7 @@ public override void Emit(OpCode opcode, string str)
// represented by str.
ModuleBuilder modBuilder = (ModuleBuilder)_methodBuilder.Module;
int tempVal = modBuilder.GetStringMetadataToken(str);
_il.OpCode((ILOpCode)opcode.Value);
EmitOpcode(opcode);
_il.Token(tempVal);
}

Expand All @@ -196,10 +203,88 @@ public override void Emit(OpCode opcode, string str)
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, 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();
public override void Emit(OpCode opcode, Type cls) => throw new NotImplementedException();
public override void EmitCall(OpCode opcode, MethodInfo methodInfo, Type[]? optionalParameterTypes) => throw new NotImplementedException();

public override void Emit(OpCode opcode, FieldInfo field)
{
ArgumentNullException.ThrowIfNull(field);

EmitMember(opcode, field);
}

public override void Emit(OpCode opcode, MethodInfo meth)
{
ArgumentNullException.ThrowIfNull(meth);

if (opcode.Equals(OpCodes.Call) || opcode.Equals(OpCodes.Callvirt) || opcode.Equals(OpCodes.Newobj))
{
EmitCall(opcode, meth, null);
}
else
{
EmitMember(opcode, meth);
}
}

private void EmitMember(OpCode opcode, MemberInfo member)
{
EmitOpcode(opcode);
_memberReferences.Add(new KeyValuePair<MemberInfo, BlobWriter>
(member, new BlobWriter(_il.CodeBuilder.ReserveBytes(sizeof(int)))));
}

public override void Emit(OpCode opcode, Type cls)
{
ArgumentNullException.ThrowIfNull(cls);

EmitOpcode(opcode);
ModuleBuilder module = (ModuleBuilder)_methodBuilder.Module;
_il.Token(module.GetTypeMetadataToken(cls));
}

public override void EmitCall(OpCode opcode, MethodInfo methodInfo, Type[]? optionalParameterTypes)
{
ArgumentNullException.ThrowIfNull(methodInfo);

if (!(opcode.Equals(OpCodes.Call) || opcode.Equals(OpCodes.Callvirt) || opcode.Equals(OpCodes.Newobj)))
throw new ArgumentException(SR.Argument_NotMethodCallOpcode, nameof(opcode));

int stackchange = 0;

// Push the return value if there is one.
if (methodInfo.ReturnType != typeof(void))
{
stackchange++;
}

// Pop the parameters.
if (methodInfo is MethodBuilderImpl builder)
{
stackchange -= builder.ParameterCount;
}
else
{
stackchange -= methodInfo.GetParameters().Length;
}

// Pop the this parameter if the method is non-static and the
// instruction is not newobj.
if (!methodInfo.IsStatic && !opcode.Equals(OpCodes.Newobj))
{
stackchange--;
}

// Pop the optional parameters off the stack.
if (optionalParameterTypes != null)
{
stackchange -= optionalParameterTypes.Length;
}

_il.OpCode((ILOpCode)opcode.Value);
UpdateStackSize(opcode, stackchange);
_memberReferences.Add(new KeyValuePair<MemberInfo, BlobWriter>
(methodInfo, new BlobWriter(_il.CodeBuilder.ReserveBytes(sizeof(int)))));
}

public override void EmitCalli(OpCode opcode, CallingConventions callingConvention, Type? returnType, Type[]? parameterTypes, Type[]? optionalParameterTypes) => throw new NotImplementedException();
public override void EmitCalli(OpCode opcode, CallingConvention unmanagedCallConv, Type? returnType, Type[]? parameterTypes) => throw new NotImplementedException();
public override void EndExceptionBlock() => throw new NotImplementedException();
Expand Down
Loading