Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Implement DefineInitializedData(...) and UninitializedData(...), refa…
…ctor field/method/type token logic because of global members
  • Loading branch information
buyaa-n committed Jan 10, 2024
commit c09a88462cef65a929a6fe373f83a6700e322d17
Original file line number Diff line number Diff line change
Expand Up @@ -282,4 +282,7 @@
<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>
</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
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ internal sealed class FieldBuilderImpl : FieldBuilder
internal List<CustomAttributeWrapper>? _customAttributes;
internal object? _defaultValue = DBNull.Value;
internal FieldDefinitionHandle _handle;
internal int _rvaSize;
internal byte[]? _rvaData;

internal FieldBuilderImpl(TypeBuilderImpl typeBuilder, string fieldName, Type type, FieldAttributes attributes, Type[]? requiredCustomModifiers, Type[]? optionalCustomModifiers)
{
Expand All @@ -41,6 +43,7 @@ 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 @@ -104,6 +107,13 @@ internal static void ValidateDefaultValueType(object? defaultValue, Type destina
}
}

internal void SetData(byte[]? data, int size)
{
_rvaData = data ?? new byte[size];
_rvaSize = size;
_attributes |= FieldAttributes.HasFieldRVA;
}

protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
// Handle pseudo custom attributes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ internal Type GetTypeFromCoreAssembly(CoreTypeId typeId)
return null;
}

internal void AppendMetadata(MethodBodyStreamEncoder methodBodyEncoder)
internal void AppendMetadata(MethodBodyStreamEncoder methodBodyEncoder, BlobBuilder fieldDataBuilder)
{
// Add module metadata
ModuleDefinitionHandle moduleHandle = _metadataBuilder.AddModule(
Expand All @@ -127,14 +127,11 @@ internal void AppendMetadata(MethodBodyStreamEncoder methodBodyEncoder)
methodList: MetadataTokens.MethodDefinitionHandle(1));

WriteCustomAttributes(_customAttributes, moduleHandle);

_typeDefinitions.Sort((x, y) => x.MetadataToken.CompareTo(y.MetadataToken));

// All generic parameters for all types and methods should be written in specific order
List<GenericTypeParameterBuilderImpl> genericParams = new();

PopulateTokensForTypesAndItsMembers();
// Add global members
WriteFields(_globalTypeBuilder);
WriteFields(_globalTypeBuilder, fieldDataBuilder);
WriteMethods(_globalTypeBuilder._methodDefinitions, genericParams, methodBodyEncoder);

// Add each type definition to metadata table.
Expand Down Expand Up @@ -173,7 +170,7 @@ internal void AppendMetadata(MethodBodyStreamEncoder methodBodyEncoder)
WriteInterfaceImplementations(typeBuilder, typeHandle);
WriteCustomAttributes(typeBuilder._customAttributes, typeHandle);
WriteProperties(typeBuilder);
WriteFields(typeBuilder);
WriteFields(typeBuilder, fieldDataBuilder);
WriteMethods(typeBuilder._methodDefinitions, genericParams, methodBodyEncoder);
WriteEvents(typeBuilder);
}
Expand Down Expand Up @@ -325,17 +322,20 @@ private void PopulateEventDefinitionHandles(List<EventBuilderImpl> eventDefiniti
}
}

internal void PopulateTypeAndItsMembersTokens(TypeBuilderImpl typeBuilder)
private void PopulateTokensForTypesAndItsMembers()
{
typeBuilder._handle = MetadataTokens.TypeDefinitionHandle(++_nextTypeDefRowId);
typeBuilder._firstMethodToken = _nextMethodDefRowId;
typeBuilder._firstFieldToken = _nextFieldDefRowId;
typeBuilder._firstPropertyToken = _nextPropertyRowId;
typeBuilder._firstEventToken = _nextEventRowId;
PopulateMethodDefinitionHandles(typeBuilder._methodDefinitions);
PopulateFieldDefinitionHandles(typeBuilder._fieldDefinitions);
PopulatePropertyDefinitionHandles(typeBuilder._propertyDefinitions);
PopulateEventDefinitionHandles(typeBuilder._eventDefinitions);
foreach (TypeBuilderImpl typeBuilder in _typeDefinitions)
{
typeBuilder._handle = MetadataTokens.TypeDefinitionHandle(++_nextTypeDefRowId);
typeBuilder._firstMethodToken = _nextMethodDefRowId;
typeBuilder._firstFieldToken = _nextFieldDefRowId;
typeBuilder._firstPropertyToken = _nextPropertyRowId;
typeBuilder._firstEventToken = _nextEventRowId;
PopulateMethodDefinitionHandles(typeBuilder._methodDefinitions);
PopulateFieldDefinitionHandles(typeBuilder._fieldDefinitions);
PopulatePropertyDefinitionHandles(typeBuilder._propertyDefinitions);
PopulateEventDefinitionHandles(typeBuilder._eventDefinitions);
}
}

private void WriteMethods(List<MethodBuilderImpl> methods, List<GenericTypeParameterBuilderImpl> genericParams, MethodBodyStreamEncoder methodBodyEncoder)
Expand Down Expand Up @@ -422,7 +422,7 @@ private static int AddMethodBody(MethodBuilderImpl method, ILGeneratorImpl il, S
attributes: method.InitLocals ? MethodBodyAttributes.InitLocals : MethodBodyAttributes.None,
hasDynamicStackAllocation: il.HasDynamicStackAllocation);

private void WriteFields(TypeBuilderImpl typeBuilder)
private void WriteFields(TypeBuilderImpl typeBuilder, BlobBuilder fieldDataBuilder)
{
foreach (FieldBuilderImpl field in typeBuilder._fieldDefinitions)
{
Expand All @@ -436,15 +436,21 @@ private void WriteFields(TypeBuilderImpl typeBuilder)
AddFieldLayout(handle, field._offset);
}

if (field._marshallingData != null)
if (field.Attributes.HasFlag(FieldAttributes.HasFieldMarshal) && field._marshallingData != null)
{
AddMarshalling(handle, field._marshallingData.SerializeMarshallingData());
}

if (field._defaultValue != DBNull.Value)
if (field.Attributes.HasFlag(FieldAttributes.HasDefault) && field._defaultValue != DBNull.Value)
{
AddDefaultValue(handle, field._defaultValue);
}

if (field.Attributes.HasFlag(FieldAttributes.HasFieldRVA) && field._rvaSize > 0)
{
_metadataBuilder.AddFieldRelativeVirtualAddress(handle, fieldDataBuilder.Count);
fieldDataBuilder.WriteBytes(field._rvaData!);
}
}
}

Expand Down Expand Up @@ -868,6 +874,21 @@ internal int GetMethodMetadataToken(MethodInfo method, Type[] optionalParameterT
return MetadataTokens.GetToken(GetMethodReference(method, optionalParameterTypes));
}

internal TypeBuilderImpl? FindTypeBuilderWithName(string strTypeName, bool ignoreCase)
{
StringComparison casing = ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;

foreach (TypeBuilderImpl type in _typeDefinitions)
{
if (string.Equals(type.Name, strTypeName, casing))
{
return type;
}
}

return null;
}

public override int GetStringMetadataToken(string stringConstant) => MetadataTokens.GetToken(_metadataBuilder.GetOrAddUserString(stringConstant));

public override int GetTypeMetadataToken(Type type)
Expand Down Expand Up @@ -931,7 +952,9 @@ protected override FieldBuilder DefineInitializedDataCore(string name, byte[] da
throw new InvalidOperationException(SR.InvalidOperation_GlobalsHaveBeenCreated);
}

return _globalTypeBuilder.DefineInitializedData(name, data, attributes);
FieldBuilderImpl field = (FieldBuilderImpl)_globalTypeBuilder.DefineInitializedData(name, data, attributes);
field._handle = MetadataTokens.FieldDefinitionHandle(_nextFieldDefRowId++);
return field;
}

[RequiresUnreferencedCode("P/Invoke marshalling may dynamically access members that could be trimmed.")]
Expand All @@ -958,7 +981,18 @@ protected override TypeBuilder DefineTypeCore(string name, TypeAttributes attr,
return _type;
}

protected override FieldBuilder DefineUninitializedDataCore(string name, int size, FieldAttributes attributes) => throw new NotImplementedException();
protected override FieldBuilder DefineUninitializedDataCore(string name, int size, FieldAttributes attributes)
{
if (_hasGlobalBeenCreated)
{
throw new InvalidOperationException(SR.InvalidOperation_GlobalsHaveBeenCreated);
}

FieldBuilderImpl field = (FieldBuilderImpl)_globalTypeBuilder.DefineUninitializedData(name, size, attributes);
field._handle = MetadataTokens.FieldDefinitionHandle(_nextFieldDefRowId++);
return field;
}

protected override MethodInfo GetArrayMethodCore(Type arrayClass, string methodName, CallingConventions callingConvention, Type? returnType, Type[]? parameterTypes) => throw new NotImplementedException();
protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ internal sealed class TypeBuilderImpl : TypeBuilder
internal List<CustomAttributeWrapper>? _customAttributes;
internal Dictionary<Type, List<(MethodInfo ifaceMethod, MethodInfo targetMethod)>>? _methodOverrides;

// Only for creating the global type
internal TypeBuilderImpl(ModuleBuilderImpl module)
{
_name = "<Module>";
Expand Down Expand Up @@ -117,7 +118,6 @@ protected override TypeInfo CreateTypeInfoCore()
DefineDefaultConstructor(MethodAttributes.Public);
}

_module.PopulateTypeAndItsMembersTokens(this);
ValidateMethods();
_isCreated = true;

Expand All @@ -129,7 +129,7 @@ protected override TypeInfo CreateTypeInfoCore()
return this;
}

internal void ValidateMethods()
private void ValidateMethods()
{
for (int i = 0; i < _methodDefinitions.Count; i++)
{
Expand Down Expand Up @@ -364,7 +364,13 @@ protected override GenericTypeParameterBuilder[] DefineGenericParametersCore(par
return _typeParameters = typeParameters;
}

protected override FieldBuilder DefineInitializedDataCore(string name, byte[] data, FieldAttributes attributes) => throw new NotImplementedException();
protected override FieldBuilder DefineInitializedDataCore(string name, byte[] data, FieldAttributes attributes)
{
// This method will define an initialized Data in .sdata.
// We will create a fake TypeDef to represent the data with size. This TypeDef
// will be the signature for the Field.
return DefineDataHelper(name, data, data.Length, attributes);
}

protected override MethodBuilder DefineMethodCore(string name, MethodAttributes attributes, CallingConventions callingConvention,
Type? returnType, Type[]? returnTypeRequiredCustomModifiers, Type[]? returnTypeOptionalCustomModifiers, Type[]? parameterTypes,
Expand Down Expand Up @@ -529,9 +535,58 @@ protected override PropertyBuilder DefinePropertyCore(string name, PropertyAttri
return property;
}

protected override ConstructorBuilder DefineTypeInitializerCore() => throw new NotImplementedException();
protected override FieldBuilder DefineUninitializedDataCore(string name, int size, FieldAttributes attributes) => throw new NotImplementedException();
protected override ConstructorBuilder DefineTypeInitializerCore()
{
ThrowIfCreated();

const MethodAttributes attr = MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName;

return new ConstructorBuilderImpl(ConstructorInfo.TypeConstructorName, attr, CallingConventions.Standard, null, null, null, _module, this);
}

protected override FieldBuilder DefineUninitializedDataCore(string name, int size, FieldAttributes attributes)
{
// This method will define an uninitialized Data in .sdata.
// We will create a fake TypeDef to represent the data with size. This TypeDef
// will be the signature for the Field.
return DefineDataHelper(name, null, size, attributes);
}

private FieldBuilder DefineDataHelper(string name, byte[]? data, int size, FieldAttributes attributes)
{
ArgumentException.ThrowIfNullOrEmpty(name);

if (size <= 0 || size >= 0x003f0000)
{
throw new ArgumentException(SR.Argument_BadSizeForData, nameof(size));
}

ThrowIfCreated();

// form the value class name
string strValueClassName = $"$ArrayType${size}";

// Is this already defined in this module?
TypeBuilderImpl? valueClassType = _module.FindTypeBuilderWithName(strValueClassName, false);

if (valueClassType == null)
{
TypeAttributes typeAttributes = TypeAttributes.Public | TypeAttributes.ExplicitLayout | TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.AnsiClass;

// Define the backing value class
valueClassType = (TypeBuilderImpl)_module.DefineType(strValueClassName, typeAttributes, typeof(ValueType), PackingSize.Size1, size);
valueClassType.CreateType();
}

FieldBuilder fdBuilder = DefineField(name, valueClassType, attributes | FieldAttributes.Static);

// now we need to set the RVA
((FieldBuilderImpl)fdBuilder).SetData(data, size);
return fdBuilder;
}

protected override bool IsCreatedCore() => _isCreated;

protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
// Handle pseudo custom attributes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,9 @@ public void AssemblyWithDifferentTypes()
fb.SetCustomAttribute(cattrb);
tbFields.CreateType();

// Data TODO: not supported yet
//module.DefineUninitializedData("data1", 16, FieldAttributes.Public);
//module.DefineInitializedData("data2", new byte[] { 1, 2, 3, 4, 5, 6 }, FieldAttributes.Public);
// Data
module.DefineUninitializedData("Data1", 16, FieldAttributes.Public);
module.DefineInitializedData("Data2", new byte[] { 1, 2, 3, 4, 5, 6 }, FieldAttributes.Public);

// Methods and signatures
TypeBuilder tb5 = module.DefineType("TypeMethods", TypeAttributes.Public, typeof(object));
Expand Down Expand Up @@ -347,11 +347,11 @@ void CheckAssembly(Assembly a)
field = type4.GetField("FieldCAttr");
CheckCattr(field.GetCustomAttributesData());

// TODO: Global fields
/*field = a.ManifestModule.GetField("Data1");
// Global fields
field = a.ManifestModule.GetField("Data1");
Assert.NotNull(field);
field = a.ManifestModule.GetField("Data2");
Assert.NotNull(field);*/
Assert.NotNull(field);

// Methods and signatures
var typeMethods = a.GetType("TypeMethods");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public void DefineLiteral(Type underlyingType, object literalValue)

FieldInfo testField = testEnum.GetField("FieldOne");
Assert.Equal(enumBuilder.Name, testField.DeclaringType.Name);
Assert.Equal(FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal, literal.Attributes);
Assert.Equal(FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal | FieldAttributes.HasDefault, literal.Attributes);
Assert.Equal(enumBuilder.AsType().FullName, testField.FieldType.FullName);
}
}
Expand Down
Loading