Skip to content

Commit

Permalink
Implement remaining unimplemented APIs for Builder types (#96805)
Browse files Browse the repository at this point in the history
* Implement 'DefinPInvokeMethod', save required/optional CustomModifiers, fix bugs found

* Add global method, get method impl and tests

* Implement DefineInitializedData(...) and UninitializedData(...), refactor field/method/type token logic because of global members

* Update src/libraries/System.Reflection.Emit/src/System/Reflection/Emit/TypeBuilderImpl.cs

Co-authored-by: Aaron Robinson <arobins@microsoft.com>

* Load assemblies in unloadable context

Co-authored-by: Steve Harter <steveharter@users.noreply.github.com>

* Add test for DefineUninitializedData(...)

* Set parameter count to 0 for RtFieldInfo

* Throw when member token is not populated when Module.Get***MetadataToken methods called

* Retrieving standalone signature not supported on mono

* Create byte array with the size directly instead of null check

---------

Co-authored-by: Aaron Robinson <arobins@microsoft.com>
Co-authored-by: Steve Harter <steveharter@users.noreply.github.com>
  • Loading branch information
3 people committed Jan 19, 2024
1 parent 993b23f commit 62d33ee
Show file tree
Hide file tree
Showing 23 changed files with 1,405 additions and 441 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -829,7 +829,7 @@ protected override void CreateGlobalFunctionsCore()
if (_hasGlobalBeenCreated)
{
// cannot create globals twice
throw new InvalidOperationException(SR.InvalidOperation_NotADebugModule);
throw new InvalidOperationException(SR.InvalidOperation_GlobalsHaveBeenCreated);
}
_globalTypeBuilder.CreateType();
_hasGlobalBeenCreated = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,12 +256,12 @@ private RuntimeType InitializeFieldType()

public override Type[] GetRequiredCustomModifiers()
{
return GetSignature().GetCustomModifiers(1, true);
return GetSignature().GetCustomModifiers(0, true);
}

public override Type[] GetOptionalCustomModifiers()
{
return GetSignature().GetCustomModifiers(1, false);
return GetSignature().GetCustomModifiers(0, false);
}

internal Signature GetSignature() => new Signature(this, m_declaringType);
Expand Down
21 changes: 21 additions & 0 deletions src/libraries/System.Reflection.Emit/src/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -267,4 +267,25 @@
<data name="Argument_RedefinedLabel" xml:space="preserve">
<value>Label defined multiple times.</value>
</data>
<data name="Argument_BadPInvokeMethod" xml:space="preserve">
<value>PInvoke methods must be static and native and cannot be abstract.</value>
</data>
<data name="Argument_BadPInvokeOnInterface" xml:space="preserve">
<value>PInvoke methods cannot exist on interfaces.</value>
</data>
<data name="Argument_MethodRedefined" xml:space="preserve">
<value>Method has been already defined.</value>
</data>
<data name="Argument_GlobalMembersMustBeStatic" xml:space="preserve">
<value>Global members must be static.</value>
</data>
<data name="InvalidOperation_GlobalsHaveBeenCreated" xml:space="preserve">
<value>Type definition of the global function has been completed.</value>
</data>
<data name="Argument_BadSizeForData" xml:space="preserve">
<value>Data size must be &amp;gt; 1 and &amp;lt; 0x3f0000.</value>
</data>
<data name="InvalidOperation_TokenNotPopulated" xml:space="preserve">
<value>MetadataToken for the member is not generated until the assembly saved.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ internal static AssemblyBuilderImpl DefinePersistedAssembly(AssemblyName name, A
IEnumerable<CustomAttributeBuilder>? assemblyAttributes)
=> new AssemblyBuilderImpl(name, coreAssembly, assemblyAttributes);

private void WritePEImage(Stream peStream, BlobBuilder ilBuilder)
private void WritePEImage(Stream peStream, BlobBuilder ilBuilder, BlobBuilder fieldData)
{
var peHeaderBuilder = new PEHeaderBuilder(
// For now only support DLL, DLL files are considered executable files
Expand All @@ -55,6 +55,7 @@ private void WritePEImage(Stream peStream, BlobBuilder ilBuilder)
header: peHeaderBuilder,
metadataRootBuilder: new MetadataRootBuilder(_metadataBuilder),
ilStream: ilBuilder,
mappedFieldData: fieldData,
strongNameSignatureSize: 0);

// Write executable into the specified stream.
Expand Down Expand Up @@ -91,10 +92,11 @@ internal void Save(Stream stream)
_module.WriteCustomAttributes(_customAttributes, assemblyHandle);

var ilBuilder = new BlobBuilder();
var fieldDataBuilder = new BlobBuilder();
MethodBodyStreamEncoder methodBodyEncoder = new MethodBodyStreamEncoder(ilBuilder);
_module.AppendMetadata(methodBodyEncoder);
_module.AppendMetadata(methodBodyEncoder, fieldDataBuilder);

WritePEImage(stream, ilBuilder);
WritePEImage(stream, ilBuilder, fieldDataBuilder);
_previouslySaved = true;
}

Expand Down Expand Up @@ -137,5 +139,9 @@ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan
}

public override string? FullName => _assemblyName.FullName;

public override Module ManifestModule => _module ?? throw new InvalidOperationException(SR.InvalidOperation_AModuleRequired);

public override AssemblyName GetName(bool copiedName) => (AssemblyName)_assemblyName.Clone();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ internal sealed class ConstructorBuilderImpl : ConstructorBuilder
internal readonly MethodBuilderImpl _methodBuilder;
internal bool _isDefaultConstructor;

public ConstructorBuilderImpl(string name, MethodAttributes attributes, CallingConventions callingConvention,
Type[]? parameterTypes, ModuleBuilderImpl mod, TypeBuilderImpl type)
public ConstructorBuilderImpl(string name, MethodAttributes attributes, CallingConventions callingConvention, Type[]? parameterTypes,
Type[][]? requiredCustomModifiers, Type[][]? optionalCustomModifiers, ModuleBuilderImpl module, TypeBuilderImpl type)
{
_methodBuilder = new MethodBuilderImpl(name, attributes, callingConvention, null, parameterTypes, mod, type);
_methodBuilder = new MethodBuilderImpl(name, attributes, callingConvention, returnType: null, returnTypeRequiredCustomModifiers: null,
returnTypeOptionalCustomModifiers: null, parameterTypes, requiredCustomModifiers, optionalCustomModifiers, module, type);

type._methodDefinitions.Add(_methodBuilder);
}
Expand Down Expand Up @@ -60,7 +61,7 @@ public override CallingConventions CallingConvention
}
}

public override TypeBuilder DeclaringType => _methodBuilder.DeclaringType;
public override Type DeclaringType => _methodBuilder.DeclaringType!;

public override Module Module => _methodBuilder.Module;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,28 +15,34 @@ internal sealed class FieldBuilderImpl : FieldBuilder
private readonly TypeBuilderImpl _typeBuilder;
private readonly string _fieldName;
private readonly Type _fieldType;
private readonly Type[]? _requiredCustomModifiers;
private readonly Type[]? _optionalCustomModifiers;
private FieldAttributes _attributes;

internal MarshallingData? _marshallingData;
internal int _offset;
internal List<CustomAttributeWrapper>? _customAttributes;
internal object? _defaultValue = DBNull.Value;
internal FieldDefinitionHandle _handle;
internal byte[]? _rvaData;

internal FieldBuilderImpl(TypeBuilderImpl typeBuilder, string fieldName, Type type, FieldAttributes attributes)
internal FieldBuilderImpl(TypeBuilderImpl typeBuilder, string fieldName, Type type, FieldAttributes attributes, Type[]? requiredCustomModifiers, Type[]? optionalCustomModifiers)
{
_fieldName = fieldName;
_typeBuilder = typeBuilder;
_fieldType = type;
_attributes = attributes & ~FieldAttributes.ReservedMask;
_offset = -1;
_requiredCustomModifiers = requiredCustomModifiers;
_optionalCustomModifiers = optionalCustomModifiers;
}

protected override void SetConstantCore(object? defaultValue)
{
_typeBuilder.ThrowIfCreated();
ValidateDefaultValueType(defaultValue, _fieldType);
_defaultValue = defaultValue;
_attributes |= FieldAttributes.HasDefault;
}

internal static void ValidateDefaultValueType(object? defaultValue, Type destinationType)
Expand Down Expand Up @@ -100,6 +106,12 @@ internal static void ValidateDefaultValueType(object? defaultValue, Type destina
}
}

internal void SetData(byte[] data)
{
_rvaData = data;
_attributes |= FieldAttributes.HasFieldRVA;
}

protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
// Handle pseudo custom attributes
Expand Down Expand Up @@ -142,9 +154,9 @@ protected override void SetOffsetCore(int iOffset)

public override string Name => _fieldName;

public override Type? DeclaringType => _typeBuilder;
public override Type? DeclaringType => _typeBuilder._isHiddenGlobalType ? null : _typeBuilder;

public override Type? ReflectedType => _typeBuilder;
public override Type? ReflectedType => DeclaringType;

#endregion

Expand All @@ -159,6 +171,10 @@ public override void SetValue(object? obj, object? val, BindingFlags invokeAttr,

public override FieldAttributes Attributes => _attributes;

public override Type[] GetRequiredCustomModifiers() => _requiredCustomModifiers ?? Type.EmptyTypes;

public override Type[] GetOptionalCustomModifiers() => _optionalCustomModifiers ?? Type.EmptyTypes;

#endregion

#region ICustomAttributeProvider Implementation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ internal GenericTypeParameterBuilderImpl(string name, int genParamPosition, Type
_type = typeBuilder;
}

public GenericTypeParameterBuilderImpl(string name, int genParamPosition, MethodBuilderImpl methodBuilder)
public GenericTypeParameterBuilderImpl(string name, int genParamPosition, MethodBuilderImpl methodBuilder, TypeBuilderImpl typeBuilder)
{
_name = name;
_genParamPosition = genParamPosition;
_methodBuilder = methodBuilder;
_type = methodBuilder.DeclaringType;
_type = typeBuilder;
}

protected override void SetBaseTypeConstraintCore([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type? baseTypeConstraint)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -418,12 +418,12 @@ public override void Emit(OpCode opcode, ConstructorInfo con)

EmitOpcode(opcode);
UpdateStackSize(stackChange);
WriteOrReserveToken(_moduleBuilder.GetMethodMetadataToken(con), con);
WriteOrReserveToken(_moduleBuilder.GetConstructorHandle(con), con);
}

private void WriteOrReserveToken(int token, object member)
private void WriteOrReserveToken(EntityHandle handle, object member)
{
if (token == -1)
if (handle.IsNil)
{
// The member is a `***BuilderImpl` and its token is not yet defined.
// Reserve the token bytes and write them later when its ready
Expand All @@ -432,7 +432,7 @@ private void WriteOrReserveToken(int token, object member)
}
else
{
_il.Token(token);
_il.Token(MetadataTokens.GetToken(handle));
}
}

Expand Down Expand Up @@ -553,7 +553,7 @@ public override void Emit(OpCode opcode, FieldInfo field)
ArgumentNullException.ThrowIfNull(field);

EmitOpcode(opcode);
WriteOrReserveToken(_moduleBuilder.GetFieldMetadataToken(field), field);
WriteOrReserveToken(_moduleBuilder.GetFieldHandle(field), field);
}

public override void Emit(OpCode opcode, MethodInfo meth)
Expand All @@ -567,7 +567,7 @@ public override void Emit(OpCode opcode, MethodInfo meth)
else
{
EmitOpcode(opcode);
WriteOrReserveToken(_moduleBuilder.GetMethodMetadataToken(meth), meth);
WriteOrReserveToken(_moduleBuilder.GetMethodHandle(meth), meth);
}
}

Expand All @@ -576,7 +576,7 @@ public override void Emit(OpCode opcode, Type cls)
ArgumentNullException.ThrowIfNull(cls);

EmitOpcode(opcode);
WriteOrReserveToken(_moduleBuilder.GetTypeMetadataToken(cls), cls);
WriteOrReserveToken(_moduleBuilder.GetTypeHandle(cls), cls);
}

public override void EmitCall(OpCode opcode, MethodInfo methodInfo, Type[]? optionalParameterTypes)
Expand All @@ -592,11 +592,11 @@ public override void EmitCall(OpCode opcode, MethodInfo methodInfo, Type[]? opti
UpdateStackSize(GetStackChange(opcode, methodInfo, optionalParameterTypes));
if (optionalParameterTypes == null || optionalParameterTypes.Length == 0)
{
WriteOrReserveToken(_moduleBuilder.GetMethodMetadataToken(methodInfo), methodInfo);
WriteOrReserveToken(_moduleBuilder.GetMethodHandle(methodInfo), methodInfo);
}
else
{
WriteOrReserveToken(_moduleBuilder.GetMethodMetadataToken(methodInfo, optionalParameterTypes),
WriteOrReserveToken(_moduleBuilder.GetMethodHandle(methodInfo, optionalParameterTypes),
new KeyValuePair<MethodInfo, Type[]>(methodInfo, optionalParameterTypes));
}
}
Expand Down
Loading

0 comments on commit 62d33ee

Please sign in to comment.