Made custom modifier packing more efficient and shared between MethodSignature and MethodBuilder.

This commit is contained in:
jfrijters 2010-04-20 13:06:09 +00:00
Родитель 71b3df3913
Коммит e6d7e01941
4 изменённых файлов: 193 добавлений и 148 удалений

Просмотреть файл

@ -1,5 +1,5 @@
/*
Copyright (C) 2008, 2009 Jeroen Frijters
Copyright (C) 2008-2010 Jeroen Frijters
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -42,8 +42,7 @@ namespace IKVM.Reflection.Emit
private int signature;
private Type returnType;
private Type[] parameterTypes;
private Type[][] optionalCustomModifiers; // last element is for the return type
private Type[][] requiredCustomModifiers;
private Type[][][] modifiers; // see PackedCustomModifiers
private MethodAttributes attributes;
private MethodImplAttributes implFlags;
private ILGenerator ilgen;
@ -71,31 +70,6 @@ namespace IKVM.Reflection.Emit
this.callingConvention = callingConvention;
}
private static Type[][] PackCustomModifiers(Type[] returnTypeCustomModifiers, Type[][] parameterTypeCustomModifiers, int parameterCount)
{
if (returnTypeCustomModifiers == null && parameterTypeCustomModifiers == null)
{
return null;
}
Type[][] newArray = new Type[parameterCount + 1][];
newArray[parameterCount] = Util.Copy(returnTypeCustomModifiers);
if (parameterTypeCustomModifiers != null)
{
for (int i = 0; i < parameterCount; i++)
{
newArray[i] = Util.Copy(parameterTypeCustomModifiers[i]);
}
}
else
{
for (int i = 0; i < parameterCount; i++)
{
newArray[i] = Type.EmptyTypes;
}
}
return newArray;
}
public ILGenerator GetILGenerator()
{
return GetILGenerator(16);
@ -338,8 +312,8 @@ namespace IKVM.Reflection.Emit
{
this.returnType = returnType ?? this.Module.universe.System_Void;
this.parameterTypes = Util.Copy(parameterTypes);
this.requiredCustomModifiers = PackCustomModifiers(returnTypeRequiredCustomModifiers, parameterTypeRequiredCustomModifiers, this.parameterTypes.Length);
this.optionalCustomModifiers = PackCustomModifiers(returnTypeOptionalCustomModifiers, parameterTypeOptionalCustomModifiers, this.parameterTypes.Length);
this.modifiers = PackedCustomModifiers.CreateFromExternal(returnTypeOptionalCustomModifiers, returnTypeRequiredCustomModifiers,
parameterTypeOptionalCustomModifiers, parameterTypeRequiredCustomModifiers, this.parameterTypes.Length);
}
public GenericTypeParameterBuilder[] DefineGenericParameters(params string[] names)
@ -471,24 +445,23 @@ namespace IKVM.Reflection.Emit
}
}
public override Type[] GetOptionalCustomModifiers()
private Type[] GetCustomModifiers(int optOrReq)
{
if (method.optionalCustomModifiers == null)
if (method.modifiers == null || method.modifiers[parameter + 1] == null)
{
return Type.EmptyTypes;
}
int index = parameter == -1 ? method.optionalCustomModifiers.Length - 1 : parameter;
return Util.Copy(method.optionalCustomModifiers[index]);
return Util.Copy(method.modifiers[parameter + 1][optOrReq]);
}
public override Type[] GetOptionalCustomModifiers()
{
return GetCustomModifiers(0);
}
public override Type[] GetRequiredCustomModifiers()
{
if (method.requiredCustomModifiers == null)
{
return Type.EmptyTypes;
}
int index = parameter == -1 ? method.requiredCustomModifiers.Length - 1 : parameter;
return Util.Copy(method.requiredCustomModifiers[index]);
return GetCustomModifiers(1);
}
public override MemberInfo Member
@ -665,7 +638,7 @@ namespace IKVM.Reflection.Emit
{
if (methodSignature == null)
{
methodSignature = MethodSignature.MakeFromBuilder(returnType, parameterTypes, optionalCustomModifiers, requiredCustomModifiers, callingConvention, gtpb == null ? 0 : gtpb.Length);
methodSignature = MethodSignature.MakeFromBuilder(returnType, parameterTypes, modifiers, callingConvention, gtpb == null ? 0 : gtpb.Length);
}
return methodSignature;
}

Просмотреть файл

@ -1,5 +1,5 @@
/*
Copyright (C) 2009 Jeroen Frijters
Copyright (C) 2009-2010 Jeroen Frijters
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -32,26 +32,17 @@ namespace IKVM.Reflection
{
sealed class MethodSignature : Signature
{
// as an optimization, we could pack the custom modifiers (like in MethodBuilder)
private readonly Type returnType;
private readonly Type[] returnTypeOptionalCustomModifiers;
private readonly Type[] returnTypeRequiredCustomModifiers;
private readonly Type[] parameterTypes;
private readonly Type[][] parameterOptionalCustomModifiers;
private readonly Type[][] parameterRequiredCustomModifiers;
private readonly Type[][][] modifiers; // see PackedCustomModifiers
private readonly CallingConventions callingConvention;
private readonly int genericParamCount;
private MethodSignature(Type returnType, Type[] returnTypeOptionalCustomModifiers, Type[] returnTypeRequiredCustomModifiers,
Type[] parameterTypes, Type[][] parameterOptionalCustomModifiers, Type[][] parameterRequiredCustomModifiers,
CallingConventions callingConvention, int genericParamCount)
private MethodSignature(Type returnType, Type[] parameterTypes, Type[][][] modifiers, CallingConventions callingConvention, int genericParamCount)
{
this.returnType = returnType;
this.returnTypeOptionalCustomModifiers = returnTypeOptionalCustomModifiers;
this.returnTypeRequiredCustomModifiers = returnTypeRequiredCustomModifiers;
this.parameterTypes = parameterTypes;
this.parameterOptionalCustomModifiers = parameterOptionalCustomModifiers;
this.parameterRequiredCustomModifiers = parameterRequiredCustomModifiers;
this.modifiers = modifiers;
this.callingConvention = callingConvention;
this.genericParamCount = genericParamCount;
}
@ -63,22 +54,16 @@ namespace IKVM.Reflection
&& other.callingConvention == callingConvention
&& other.genericParamCount == genericParamCount
&& other.returnType.Equals(returnType)
&& Util.ArrayEquals(other.returnTypeOptionalCustomModifiers, returnTypeOptionalCustomModifiers)
&& Util.ArrayEquals(other.returnTypeRequiredCustomModifiers, returnTypeRequiredCustomModifiers)
&& Util.ArrayEquals(other.parameterTypes, parameterTypes)
&& Util.ArrayEquals(other.parameterOptionalCustomModifiers, parameterOptionalCustomModifiers)
&& Util.ArrayEquals(other.parameterRequiredCustomModifiers, parameterRequiredCustomModifiers);
&& Util.ArrayEquals(other.modifiers, modifiers);
}
public override int GetHashCode()
{
return genericParamCount ^ 77 * (int)callingConvention
^ 3 * returnType.GetHashCode()
^ Util.GetHashCode(returnTypeOptionalCustomModifiers) * 33
^ Util.GetHashCode(returnTypeRequiredCustomModifiers) * 55
^ Util.GetHashCode(parameterTypes) * 5
^ Util.GetHashCode(parameterOptionalCustomModifiers)
^ Util.GetHashCode(parameterRequiredCustomModifiers);
^ Util.GetHashCode(modifiers) * 55;
}
private sealed class UnboundGenericMethodContext : IGenericContext
@ -106,11 +91,7 @@ namespace IKVM.Reflection
CallingConventions callingConvention;
int genericParamCount;
Type returnType;
Type[] returnTypeOptionalCustomModifiers;
Type[] returnTypeRequiredCustomModifiers;
Type[] parameterTypes;
Type[][] parameterOptionalCustomModifiers;
Type[][] parameterRequiredCustomModifiers;
byte flags = br.ReadByte();
switch (flags & 7)
{
@ -138,39 +119,31 @@ namespace IKVM.Reflection
context = new UnboundGenericMethodContext(context);
}
int paramCount = br.ReadCompressedInt();
ReadCustomModifiers(module, br, context, out returnTypeRequiredCustomModifiers, out returnTypeOptionalCustomModifiers);
Type[][][] modifiers = null;
Type[] optionalCustomModifiers;
Type[] requiredCustomModifiers;
ReadCustomModifiers(module, br, context, out requiredCustomModifiers, out optionalCustomModifiers);
returnType = ReadRetType(module, br, context);
parameterTypes = new Type[paramCount];
parameterOptionalCustomModifiers = null;
parameterRequiredCustomModifiers = null;
PackedCustomModifiers.SetModifiers(ref modifiers, 0, 0, optionalCustomModifiers, paramCount + 1);
PackedCustomModifiers.SetModifiers(ref modifiers, 0, 1, requiredCustomModifiers, paramCount + 1);
for (int i = 0; i < parameterTypes.Length; i++)
{
if ((callingConvention & CallingConventions.VarArgs) != 0 && br.PeekByte() == SENTINEL)
{
Array.Resize(ref parameterTypes, i);
if (parameterOptionalCustomModifiers != null)
if (modifiers != null)
{
Array.Resize(ref parameterOptionalCustomModifiers, i);
}
if (parameterRequiredCustomModifiers != null)
{
Array.Resize(ref parameterRequiredCustomModifiers, i);
Array.Resize(ref modifiers, i + 1);
}
break;
}
if (IsCustomModifier(br.PeekByte()))
{
if (parameterOptionalCustomModifiers == null)
{
parameterOptionalCustomModifiers = new Type[parameterTypes.Length][];
parameterRequiredCustomModifiers = new Type[parameterTypes.Length][];
}
ReadCustomModifiers(module, br, context, out parameterRequiredCustomModifiers[i], out parameterOptionalCustomModifiers[i]);
}
ReadCustomModifiers(module, br, context, out requiredCustomModifiers, out optionalCustomModifiers);
PackedCustomModifiers.SetModifiers(ref modifiers, i + 1, 0, optionalCustomModifiers, paramCount + 1);
PackedCustomModifiers.SetModifiers(ref modifiers, i + 1, 1, requiredCustomModifiers, paramCount + 1);
parameterTypes[i] = ReadParam(module, br, context);
}
return new MethodSignature(returnType, returnTypeOptionalCustomModifiers, returnTypeRequiredCustomModifiers,
parameterTypes, parameterOptionalCustomModifiers, parameterRequiredCustomModifiers, callingConvention, genericParamCount);
return new MethodSignature(returnType, parameterTypes, modifiers, callingConvention, genericParamCount);
}
internal static __StandAloneMethodSig ReadStandAloneMethodSig(ModuleReader module, ByteReader br, IGenericContext context)
@ -256,12 +229,12 @@ namespace IKVM.Reflection
internal Type[] GetReturnTypeOptionalCustomModifiers(IGenericBinder binder)
{
return BindTypeParameters(binder, returnTypeOptionalCustomModifiers);
return BindTypeParameters(binder, modifiers, 0, 0);
}
internal Type[] GetReturnTypeRequiredCustomModifiers(IGenericBinder binder)
{
return BindTypeParameters(binder, returnTypeRequiredCustomModifiers);
return BindTypeParameters(binder, modifiers, 0, 1);
}
internal Type GetParameterType(IGenericBinder binder, int index)
@ -271,20 +244,12 @@ namespace IKVM.Reflection
internal Type[] GetParameterOptionalCustomModifiers(IGenericBinder binder, int index)
{
if (parameterOptionalCustomModifiers == null)
{
return null;
}
return BindTypeParameters(binder, parameterOptionalCustomModifiers[index]);
return BindTypeParameters(binder, modifiers, index + 1, 0);
}
internal Type[] GetParameterRequiredCustomModifiers(IGenericBinder binder, int index)
{
if (parameterRequiredCustomModifiers == null)
{
return null;
}
return BindTypeParameters(binder, parameterRequiredCustomModifiers[index]);
return BindTypeParameters(binder, modifiers, index + 1, 1);
}
internal CallingConventions CallingConvention
@ -322,16 +287,19 @@ namespace IKVM.Reflection
{
Binder binder = new Binder(type, methodArgs);
return new MethodSignature(returnType.BindTypeParameters(binder),
BindTypeParameters(binder, returnTypeOptionalCustomModifiers),
BindTypeParameters(binder, returnTypeRequiredCustomModifiers),
BindTypeParameters(binder, parameterTypes),
BindTypeParameters(binder, parameterOptionalCustomModifiers),
BindTypeParameters(binder, parameterRequiredCustomModifiers),
BindTypeParameters(binder, modifiers),
callingConvention, genericParamCount);
}
private sealed class Unbinder : IGenericBinder
{
internal static readonly Unbinder Instance = new Unbinder();
private Unbinder()
{
}
public Type BindTypeParameter(Type type)
{
return type;
@ -343,47 +311,15 @@ namespace IKVM.Reflection
}
}
internal static MethodSignature MakeFromBuilder(Type returnType, Type[] parameterTypes,
Type[][] optionalCustomModifiers, Type[][] requiredCustomModifiers, CallingConventions callingConvention, int genericParamCount)
internal static MethodSignature MakeFromBuilder(Type returnType, Type[] parameterTypes, Type[][][] modifiers, CallingConventions callingConvention, int genericParamCount)
{
Type[] returnTypeOptionalCustomModifiers = UnpackReturnTypeModifiers(optionalCustomModifiers);
Type[] returnTypeRequiredCustomModifiers = UnpackReturnTypeModifiers(requiredCustomModifiers);
Type[][] parameterOptionalCustomModifiers = UnpackParameterModifiers(optionalCustomModifiers);
Type[][] parameterRequiredCustomModifiers = UnpackParameterModifiers(requiredCustomModifiers);
if (genericParamCount > 0)
{
Unbinder unbinder = new Unbinder();
returnType = returnType.BindTypeParameters(unbinder);
Type.InplaceBindTypeParameters(unbinder, returnTypeOptionalCustomModifiers);
Type.InplaceBindTypeParameters(unbinder, returnTypeRequiredCustomModifiers);
parameterTypes = BindTypeParameters(unbinder, parameterTypes);
parameterOptionalCustomModifiers = BindTypeParameters(unbinder, parameterOptionalCustomModifiers);
parameterRequiredCustomModifiers = BindTypeParameters(unbinder, parameterRequiredCustomModifiers);
returnType = returnType.BindTypeParameters(Unbinder.Instance);
parameterTypes = BindTypeParameters(Unbinder.Instance, parameterTypes);
modifiers = BindTypeParameters(Unbinder.Instance, modifiers);
}
return new MethodSignature(returnType, returnTypeOptionalCustomModifiers, returnTypeRequiredCustomModifiers,
parameterTypes, parameterOptionalCustomModifiers, parameterRequiredCustomModifiers, callingConvention, genericParamCount);
}
private static Type[] UnpackReturnTypeModifiers(Type[][] types)
{
if (types == null)
{
return Type.EmptyTypes;
}
return types[types.Length - 1];
}
private static Type[][] UnpackParameterModifiers(Type[][] types)
{
if (types == null)
{
return null;
}
Type[][] unpacked = new Type[types.Length - 1][];
Array.Copy(types, unpacked, unpacked.Length);
return unpacked;
return new MethodSignature(returnType, parameterTypes, modifiers, callingConvention, genericParamCount);
}
internal bool MatchParameterTypes(Type[] types)
@ -463,22 +399,94 @@ namespace IKVM.Reflection
}
bb.WriteCompressedInt(parameterCount);
// RetType
WriteCustomModifiers(module, bb, ELEMENT_TYPE_CMOD_OPT, returnTypeOptionalCustomModifiers);
WriteCustomModifiers(module, bb, ELEMENT_TYPE_CMOD_REQD, returnTypeRequiredCustomModifiers);
WriteType(module, bb, returnType ?? module.universe.System_Void);
if (modifiers != null && modifiers[0] != null)
{
WriteCustomModifiers(module, bb, ELEMENT_TYPE_CMOD_OPT, modifiers[0][0]);
WriteCustomModifiers(module, bb, ELEMENT_TYPE_CMOD_REQD, modifiers[0][1]);
}
WriteType(module, bb, returnType);
// Param
for (int i = 0; i < parameterTypes.Length; i++)
{
if (parameterOptionalCustomModifiers != null)
if (modifiers != null && modifiers[i + 1] != null)
{
WriteCustomModifiers(module, bb, ELEMENT_TYPE_CMOD_OPT, parameterOptionalCustomModifiers[i]);
}
if (parameterRequiredCustomModifiers != null)
{
WriteCustomModifiers(module, bb, ELEMENT_TYPE_CMOD_REQD, parameterRequiredCustomModifiers[i]);
WriteCustomModifiers(module, bb, ELEMENT_TYPE_CMOD_OPT, modifiers[i + 1][0]);
WriteCustomModifiers(module, bb, ELEMENT_TYPE_CMOD_REQD, modifiers[i + 1][1]);
}
WriteType(module, bb, parameterTypes[i]);
}
}
}
static class PackedCustomModifiers
{
// modifiers are packed in a very specific way (and required to be so, otherwise equality checks will fail)
// For modifiers[x][y][z]:
// x = parameter index, 0 = return type, 1 = first parameters, ...
// y = 0 = optional custom modifiers, 1 = required custom modifiers
// z = the custom modifiers
// At any level the reference can be null (and *must* be null, if there are no modifiers below that level).
// Empty arrays are not allowed at any level.
// this can be used to "add" elements to the modifiers array (and the elements are assumed to already be in normalized form)
internal static void SetModifiers(ref Type[][][] modifiers, int index, int optOrReq, Type[] add, int count)
{
if (add != null)
{
if (modifiers == null)
{
modifiers = new Type[count][][];
}
if (modifiers[index] == null)
{
modifiers[index] = new Type[2][];
}
modifiers[index][optOrReq] = add;
}
}
// this method make a copy of the incoming arrays (where necessary) and returns a normalized modifiers array
internal static Type[][][] CreateFromExternal(Type[] returnOptional, Type[] returnRequired, Type[][] parameterOptional, Type[][] parameterRequired, int parameterCount)
{
Type[][][] modifiers = null;
SetModifiers(ref modifiers, 0, 0, NormalizeAndCopy(returnOptional), parameterCount + 1);
SetModifiers(ref modifiers, 0, 1, NormalizeAndCopy(returnRequired), parameterCount + 1);
for (int i = 0; i < parameterCount; i++)
{
SetModifiers(ref modifiers, i + 1, 0, NormalizeAndCopy(parameterOptional, i), parameterCount + 1);
SetModifiers(ref modifiers, i + 1, 1, NormalizeAndCopy(parameterRequired, i), parameterCount + 1);
}
return modifiers;
}
private static Type[] NormalizeAndCopy(Type[] array)
{
if (array == null || array.Length == 0)
{
return null;
}
Type[] copy = null;
for (int i = 0; i < array.Length; i++)
{
if (array[i] != null)
{
if (copy == null)
{
copy = new Type[array.Length];
}
copy[i] = array[i];
}
}
return copy;
}
private static Type[] NormalizeAndCopy(Type[][] array, int index)
{
if (array == null || array.Length == 0)
{
return null;
}
return NormalizeAndCopy(array[index]);
}
}
}

Просмотреть файл

@ -786,5 +786,28 @@ namespace IKVM.Reflection
}
return expanded;
}
protected static Type[][][] BindTypeParameters(IGenericBinder binder, Type[][][] types)
{
if (types == null)
{
return null;
}
Type[][][] expanded = new Type[types.Length][][];
for (int i = 0; i < types.Length; i++)
{
expanded[i] = BindTypeParameters(binder, types[i]);
}
return expanded;
}
protected static Type[] BindTypeParameters(IGenericBinder binder, Type[][][] types, int index, int optOrReq)
{
if (types == null || types[index] == null)
{
return null;
}
return BindTypeParameters(binder, types[index][optOrReq]);
}
}
}

Просмотреть файл

@ -129,6 +129,34 @@ namespace IKVM.Reflection
return false;
}
internal static bool ArrayEquals(Type[][][] t1, Type[][][] t2)
{
if (t1 == t2)
{
return true;
}
if (t1 == null)
{
return t2.Length == 0;
}
else if (t2 == null)
{
return t1.Length == 0;
}
if (t1.Length == t2.Length)
{
for (int i = 0; i < t1.Length; i++)
{
if (!ArrayEquals(t1[i], t2[i]))
{
return false;
}
}
return true;
}
return false;
}
internal static bool TypeEquals(Type t1, Type t2)
{
if (t1 == t2)
@ -172,5 +200,18 @@ namespace IKVM.Reflection
}
return h;
}
internal static int GetHashCode(Type[][][] types)
{
int h = 0;
if (types != null)
{
foreach (Type[][] array in types)
{
h ^= GetHashCode(array);
}
}
return h;
}
}
}