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
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using CultureInfo = System.Globalization.CultureInfo;

namespace System.Reflection.Emit
Expand All @@ -14,8 +15,25 @@ internal enum TypeKind
}

// This is a kind of Type object that will represent the compound expression of a parameter type or field type.
#if MONO
[StructLayout(LayoutKind.Sequential)]
#endif
internal sealed class SymbolType : TypeInfo
{
#region Data Members
#region Sync with MonoReflectionDerivedType in object-internals.h
internal Type _baseType = null!;
internal TypeKind _typeKind;
internal int _rank; // count of dimension
#endregion
// If LowerBound and UpperBound is equal, that means one element.
// If UpperBound is less than LowerBound, then the size is not specified.
internal int[] _iaLowerBound;
internal int[] _iaUpperBound; // count of dimension
private string? _format; // format string to form the full name.
private bool _isSzArray = true;
#endregion

public override bool IsAssignableFrom([NotNullWhen(true)] TypeInfo? typeInfo)
{
if (typeInfo == null) return false;
Expand Down Expand Up @@ -46,29 +64,25 @@ public override bool IsAssignableFrom([NotNullWhen(true)] TypeInfo? typeInfo)
return baseType;
}




if (format[curIndex] == '&')
{
// ByRef case

symbolType = new SymbolType(TypeKind.IsByRef);
symbolType = new SymbolType(baseType, TypeKind.IsByRef);
symbolType.SetFormat(format, curIndex, 1);
curIndex++;

if (curIndex != format.Length)
// ByRef has to be the last char!!
throw new ArgumentException(SR.Argument_BadSigFormat);

symbolType.SetElementType(baseType);
return symbolType;
}

if (format[curIndex] == '[')
{
// Array type.
symbolType = new SymbolType(TypeKind.IsArray);
symbolType = new SymbolType(baseType, TypeKind.IsArray);
int startIndex = curIndex;
curIndex++;

Expand All @@ -83,7 +97,7 @@ public override bool IsAssignableFrom([NotNullWhen(true)] TypeInfo? typeInfo)
{
if (format[curIndex] == '*')
{
symbolType.m_isSzArray = false;
symbolType._isSzArray = false;
curIndex++;
}
// consume, one dimension at a time
Expand Down Expand Up @@ -181,18 +195,15 @@ public override bool IsAssignableFrom([NotNullWhen(true)] TypeInfo? typeInfo)

symbolType.SetFormat(format, startIndex, curIndex - startIndex);

// set the base type of array
symbolType.SetElementType(baseType);
return FormCompoundType(format, symbolType, curIndex);
}
else if (format[curIndex] == '*')
{
// pointer type.

symbolType = new SymbolType(TypeKind.IsPointer);
symbolType = new SymbolType(baseType, TypeKind.IsPointer);
symbolType.SetFormat(format, curIndex, 1);
curIndex++;
symbolType.SetElementType(baseType);
return FormCompoundType(format, symbolType, curIndex);
}

Expand All @@ -201,91 +212,75 @@ public override bool IsAssignableFrom([NotNullWhen(true)] TypeInfo? typeInfo)

#endregion

#region Data Members
internal TypeKind m_typeKind;
internal Type m_baseType = null!;
internal int m_cRank; // count of dimension
// If LowerBound and UpperBound is equal, that means one element.
// If UpperBound is less than LowerBound, then the size is not specified.
internal int[] m_iaLowerBound;
internal int[] m_iaUpperBound; // count of dimension
private string? m_format; // format string to form the full name.
private bool m_isSzArray = true;
#endregion

#region Constructor
internal SymbolType(TypeKind typeKind)
internal SymbolType(Type baseType, TypeKind typeKind)
{
m_typeKind = typeKind;
m_iaLowerBound = new int[4];
m_iaUpperBound = new int[4];
ArgumentNullException.ThrowIfNull(baseType);

_baseType = baseType;
_typeKind = typeKind;
_iaLowerBound = new int[4];
_iaUpperBound = new int[4];
}

#endregion

#region Internal Members
internal void SetElementType(Type baseType)
{
ArgumentNullException.ThrowIfNull(baseType);

m_baseType = baseType;
}

private void SetBounds(int lower, int upper)
{
// Increase the rank, set lower and upper bound

if (lower != 0 || upper != -1)
m_isSzArray = false;
_isSzArray = false;

if (m_iaLowerBound.Length <= m_cRank)
if (_iaLowerBound.Length <= _rank)
{
// resize the bound array
int[] iaTemp = new int[m_cRank * 2];
Array.Copy(m_iaLowerBound, iaTemp, m_cRank);
m_iaLowerBound = iaTemp;
Array.Copy(m_iaUpperBound, iaTemp, m_cRank);
m_iaUpperBound = iaTemp;
int[] iaTemp = new int[_rank * 2];
Array.Copy(_iaLowerBound, iaTemp, _rank);
_iaLowerBound = iaTemp;
Array.Copy(_iaUpperBound, iaTemp, _rank);
_iaUpperBound = iaTemp;
}

m_iaLowerBound[m_cRank] = lower;
m_iaUpperBound[m_cRank] = upper;
m_cRank++;
_iaLowerBound[_rank] = lower;
_iaUpperBound[_rank] = upper;
_rank++;
}

internal void SetFormat(string format, int curIndex, int length)
{
// Cache the text display format for this SymbolType

m_format = format.Substring(curIndex, length);
_format = format.Substring(curIndex, length);
}
#endregion

#region Type Overrides

public override bool IsTypeDefinition => false;

public override bool IsSZArray => m_cRank <= 1 && m_isSzArray;
public override bool IsSZArray => _rank <= 1 && _isSzArray;

public override Type MakePointerType()
{
return SymbolType.FormCompoundType(m_format + "*", m_baseType, 0)!;
return FormCompoundType(_format + "*", _baseType, 0)!;
}

public override Type MakeByRefType()
{
return SymbolType.FormCompoundType(m_format + "&", m_baseType, 0)!;
return FormCompoundType(_format + "&", _baseType, 0)!;
}

public override Type MakeArrayType()
{
return SymbolType.FormCompoundType(m_format + "[]", m_baseType, 0)!;
return FormCompoundType(_format + "[]", _baseType, 0)!;
}

public override Type MakeArrayType(int rank)
{
string s = GetRankString(rank);
SymbolType? st = SymbolType.FormCompoundType(m_format + s, m_baseType, 0) as SymbolType;
SymbolType? st = FormCompoundType(_format + s, _baseType, 0) as SymbolType;
return st!;
}

Expand All @@ -294,7 +289,7 @@ public override int GetArrayRank()
if (!IsArray)
throw new NotSupportedException(SR.NotSupported_SubclassOverride);

return m_cRank;
return _rank;
}

public override Guid GUID => throw new NotSupportedException(SR.NotSupported_NonReflectedType);
Expand All @@ -312,7 +307,7 @@ public override Module Module
{
Type baseType;

for (baseType = m_baseType; baseType is SymbolType; baseType = ((SymbolType)baseType).m_baseType) ;
for (baseType = _baseType; baseType is SymbolType; baseType = ((SymbolType)baseType)._baseType) ;

return baseType.Module;
}
Expand All @@ -323,7 +318,7 @@ public override Assembly Assembly
{
Type baseType;

for (baseType = m_baseType; baseType is SymbolType; baseType = ((SymbolType)baseType).m_baseType) ;
for (baseType = _baseType; baseType is SymbolType; baseType = ((SymbolType)baseType)._baseType) ;

return baseType.Assembly;
}
Expand All @@ -336,10 +331,10 @@ public override string Name
get
{
Type baseType;
string? sFormat = m_format;
string? sFormat = _format;

for (baseType = m_baseType; baseType is SymbolType; baseType = ((SymbolType)baseType).m_baseType)
sFormat = ((SymbolType)baseType).m_format + sFormat;
for (baseType = _baseType; baseType is SymbolType; baseType = ((SymbolType)baseType)._baseType)
sFormat = ((SymbolType)baseType)._format + sFormat;

return baseType.Name + sFormat;
}
Expand All @@ -354,7 +349,7 @@ public override string ToString()
return TypeNameBuilder.ToString(this, TypeNameBuilder.Format.ToString)!;
}

public override string? Namespace => m_baseType.Namespace;
public override string? Namespace => _baseType.Namespace;

public override Type BaseType => typeof(System.Array);

Expand Down Expand Up @@ -473,23 +468,23 @@ protected override TypeAttributes GetAttributeFlagsImpl()
{
// Return the attribute flags of the base type?
Type baseType;
for (baseType = m_baseType; baseType is SymbolType; baseType = ((SymbolType)baseType).m_baseType) ;
for (baseType = _baseType; baseType is SymbolType; baseType = ((SymbolType)baseType)._baseType) ;
return baseType.Attributes;
}

protected override bool IsArrayImpl()
{
return m_typeKind == TypeKind.IsArray;
return _typeKind == TypeKind.IsArray;
}

protected override bool IsPointerImpl()
{
return m_typeKind == TypeKind.IsPointer;
return _typeKind == TypeKind.IsPointer;
}

protected override bool IsByRefImpl()
{
return m_typeKind == TypeKind.IsByRef;
return _typeKind == TypeKind.IsByRef;
}

protected override bool IsPrimitiveImpl()
Expand All @@ -511,12 +506,12 @@ protected override bool IsCOMObjectImpl()

public override Type? GetElementType()
{
return m_baseType;
return _baseType;
}

protected override bool HasElementTypeImpl()
{
return m_baseType != null;
return _baseType != null;
}

public override Type UnderlyingSystemType => this;
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 Microsoft.Diagnostics.Runtime.Interop;
using Xunit;

namespace System.Reflection.Emit.Tests
Expand Down Expand Up @@ -81,5 +82,62 @@ public void GetILGenerator_DifferentAttributes(MethodAttributes attributes)
MethodBuilder method = type.DefineMethod(attributes.ToString(), attributes);
Assert.NotNull(method.GetILGenerator());
}

[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMonoRuntime))]
public void LoadPointerTypeInILGeneratedMethod()
{
TypeBuilder type = Helpers.DynamicType(TypeAttributes.Public);
Type pointerType = type.MakePointerType();

MethodBuilder method = type.DefineMethod("TestMethod", MethodAttributes.Public | MethodAttributes.Static, typeof(string), Type.EmptyTypes);
ILGenerator ilGenerator = method.GetILGenerator();

ilGenerator.Emit(OpCodes.Ldtoken, pointerType);
ilGenerator.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle", BindingFlags.Static | BindingFlags.Public));
ilGenerator.Emit(OpCodes.Callvirt, typeof(Type).GetMethod("get_FullName"));
ilGenerator.Emit(OpCodes.Ret);

Type createdType = type.CreateType();
MethodInfo createdMethod = createdType.GetMethod("TestMethod");
Assert.Equal("TestType*", createdMethod.Invoke(null, null));
}

[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMonoRuntime))]
public void LoadArrayTypeInILGeneratedMethod()
{
TypeBuilder type = Helpers.DynamicType(TypeAttributes.Public);
Type arrayType = type.MakeArrayType();

MethodBuilder method = type.DefineMethod("TestMethod", MethodAttributes.Public | MethodAttributes.Static, typeof(string), Type.EmptyTypes);
ILGenerator ilGenerator = method.GetILGenerator();

ilGenerator.Emit(OpCodes.Ldtoken, arrayType);
ilGenerator.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle", BindingFlags.Static | BindingFlags.Public));
ilGenerator.Emit(OpCodes.Callvirt, typeof(Type).GetMethod("get_FullName"));
ilGenerator.Emit(OpCodes.Ret);

Type createdType = type.CreateType();
MethodInfo createdMethod = createdType.GetMethod("TestMethod");
Assert.Equal("TestType[]", createdMethod.Invoke(null, null));
}

[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotMonoRuntime))]
public void LoadByRefTypeInILGeneratedMethod()
{
TypeBuilder type = Helpers.DynamicType(TypeAttributes.Public);
Type byrefType = type.MakeByRefType();

MethodBuilder method = type.DefineMethod("TestMethod", MethodAttributes.Public | MethodAttributes.Static, typeof(string), Type.EmptyTypes);
ILGenerator ilGenerator = method.GetILGenerator();

ilGenerator.Emit(OpCodes.Ldtoken, byrefType);
ilGenerator.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle", BindingFlags.Static | BindingFlags.Public));
ilGenerator.Emit(OpCodes.Callvirt, typeof(Type).GetMethod("get_FullName"));
ilGenerator.Emit(OpCodes.Ret);

Type createdType = type.CreateType();
MethodInfo createdMethod = createdType.GetMethod("TestMethod");
Assert.Equal("TestType&", createdMethod.Invoke(null, null));
}
}
}
Loading