зеркало из https://github.com/mono/ikvm-fork.git
Implemented type annotation reflection for statically compiled classes.
This commit is contained in:
Родитель
3828b7df57
Коммит
ff3cadecc8
|
@ -931,6 +931,10 @@ namespace IKVM.Internal
|
|||
AttributeHelper.SetEnclosingMethodAttribute(typeBuilder, classFile.EnclosingMethod[0], classFile.EnclosingMethod[1], classFile.EnclosingMethod[2]);
|
||||
}
|
||||
}
|
||||
if (classFile.RuntimeVisibleTypeAnnotations != null)
|
||||
{
|
||||
AttributeHelper.SetRuntimeVisibleTypeAnnotationsAttribute(typeBuilder, classFile.RuntimeVisibleTypeAnnotations);
|
||||
}
|
||||
if (wrapper.classLoader.EmitStackTraceInfo)
|
||||
{
|
||||
if (f.SourceFileAttribute != null)
|
||||
|
@ -1637,6 +1641,10 @@ namespace IKVM.Internal
|
|||
{
|
||||
AttributeHelper.SetSignatureAttribute(field, fld.GenericSignature);
|
||||
}
|
||||
if (fld.RuntimeVisibleTypeAnnotations != null)
|
||||
{
|
||||
AttributeHelper.SetRuntimeVisibleTypeAnnotationsAttribute(field, fld.RuntimeVisibleTypeAnnotations);
|
||||
}
|
||||
}
|
||||
#endif // STATIC_COMPILER
|
||||
return field;
|
||||
|
@ -2974,6 +2982,10 @@ namespace IKVM.Internal
|
|||
}
|
||||
AttributeHelper.SetMethodParametersAttribute(method, modifiers);
|
||||
}
|
||||
if (m.RuntimeVisibleTypeAnnotations != null)
|
||||
{
|
||||
AttributeHelper.SetRuntimeVisibleTypeAnnotationsAttribute(method, m.RuntimeVisibleTypeAnnotations);
|
||||
}
|
||||
#else // STATIC_COMPILER
|
||||
if (setModifiers)
|
||||
{
|
||||
|
@ -4517,6 +4529,8 @@ namespace IKVM.Internal
|
|||
{
|
||||
AddAccessStubs();
|
||||
}
|
||||
|
||||
AddConstantPoolAttributeIfNecessary(classFile, typeBuilder);
|
||||
#endif // STATIC_COMPILER
|
||||
|
||||
for (int i = 0; i < classFile.Methods.Length; i++)
|
||||
|
@ -4633,6 +4647,147 @@ namespace IKVM.Internal
|
|||
}
|
||||
|
||||
#if STATIC_COMPILER
|
||||
private static void AddConstantPoolAttributeIfNecessary(ClassFile classFile, TypeBuilder typeBuilder)
|
||||
{
|
||||
object[] constantPool = null;
|
||||
bool[] inUse = null;
|
||||
MarkConstantPoolUsage(classFile, classFile.RuntimeVisibleTypeAnnotations, ref constantPool, ref inUse);
|
||||
foreach (ClassFile.Method method in classFile.Methods)
|
||||
{
|
||||
MarkConstantPoolUsage(classFile, method.RuntimeVisibleTypeAnnotations, ref constantPool, ref inUse);
|
||||
}
|
||||
foreach (ClassFile.Field field in classFile.Fields)
|
||||
{
|
||||
MarkConstantPoolUsage(classFile, field.RuntimeVisibleTypeAnnotations, ref constantPool, ref inUse);
|
||||
}
|
||||
if (constantPool != null)
|
||||
{
|
||||
// to save space, we clear out the items that aren't used by the RuntimeVisibleTypeAnnotations and
|
||||
// use an RLE for the empty slots
|
||||
AttributeHelper.SetConstantPoolAttribute(typeBuilder, ConstantPoolAttribute.Compress(constantPool, inUse));
|
||||
}
|
||||
}
|
||||
|
||||
private static void MarkConstantPoolUsage(ClassFile classFile, byte[] runtimeVisibleTypeAnnotations, ref object[] constantPool, ref bool[] inUse)
|
||||
{
|
||||
if (runtimeVisibleTypeAnnotations != null)
|
||||
{
|
||||
if (constantPool == null)
|
||||
{
|
||||
constantPool = classFile.GetConstantPool();
|
||||
inUse = new bool[constantPool.Length];
|
||||
}
|
||||
try
|
||||
{
|
||||
BigEndianBinaryReader br = new BigEndianBinaryReader(runtimeVisibleTypeAnnotations, 0, runtimeVisibleTypeAnnotations.Length);
|
||||
ushort num_annotations = br.ReadUInt16();
|
||||
for (int i = 0; i < num_annotations; i++)
|
||||
{
|
||||
MarkConstantPoolUsageForTypeAnnotation(br, inUse);
|
||||
}
|
||||
return;
|
||||
}
|
||||
catch (ClassFormatError)
|
||||
{
|
||||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
}
|
||||
// if we fail to parse the annotations (e.g. due to a malformed attribute), we simply keep all the constant pool entries
|
||||
for (int i = 0; i < inUse.Length; i++)
|
||||
{
|
||||
inUse[i] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void MarkConstantPoolUsageForTypeAnnotation(BigEndianBinaryReader br, bool[] inUse)
|
||||
{
|
||||
switch (br.ReadByte()) // target_type
|
||||
{
|
||||
case 0x00:
|
||||
case 0x01:
|
||||
br.ReadByte(); // type_parameter_index
|
||||
break;
|
||||
case 0x10:
|
||||
br.ReadUInt16(); // supertype_index
|
||||
break;
|
||||
case 0x11:
|
||||
case 0x12:
|
||||
br.ReadByte(); // type_parameter_index
|
||||
br.ReadByte(); // bound_index
|
||||
break;
|
||||
case 0x13:
|
||||
case 0x14:
|
||||
case 0x15:
|
||||
// empty_target
|
||||
break;
|
||||
case 0x16:
|
||||
br.ReadByte(); // formal_parameter_index
|
||||
break;
|
||||
case 0x17:
|
||||
br.ReadUInt16(); // throws_type_index
|
||||
break;
|
||||
default:
|
||||
throw new ClassFormatError("");
|
||||
}
|
||||
byte path_length = br.ReadByte();
|
||||
for (int i = 0; i < path_length; i++)
|
||||
{
|
||||
br.ReadByte(); // type_path_kind
|
||||
br.ReadByte(); // type_argument_index
|
||||
}
|
||||
MarkConstantPoolUsageForAnnotation(br, inUse);
|
||||
}
|
||||
|
||||
private static void MarkConstantPoolUsageForAnnotation(BigEndianBinaryReader br, bool[] inUse)
|
||||
{
|
||||
ushort type_index = br.ReadUInt16();
|
||||
inUse[type_index] = true;
|
||||
ushort num_components = br.ReadUInt16();
|
||||
for (int i = 0; i < num_components; i++)
|
||||
{
|
||||
ushort component_name_index = br.ReadUInt16();
|
||||
inUse[component_name_index] = true;
|
||||
MarkConstantPoolUsageForAnnotationComponentValue(br, inUse);
|
||||
}
|
||||
}
|
||||
|
||||
private static void MarkConstantPoolUsageForAnnotationComponentValue(BigEndianBinaryReader br, bool[] inUse)
|
||||
{
|
||||
switch ((char)br.ReadByte()) // tag
|
||||
{
|
||||
case 'B':
|
||||
case 'C':
|
||||
case 'D':
|
||||
case 'F':
|
||||
case 'I':
|
||||
case 'J':
|
||||
case 'S':
|
||||
case 'Z':
|
||||
case 's':
|
||||
case 'c':
|
||||
inUse[br.ReadUInt16()] = true;
|
||||
break;
|
||||
case 'e':
|
||||
inUse[br.ReadUInt16()] = true;
|
||||
inUse[br.ReadUInt16()] = true;
|
||||
break;
|
||||
case '@':
|
||||
MarkConstantPoolUsageForAnnotation(br, inUse);
|
||||
break;
|
||||
case '[':
|
||||
ushort num_values = br.ReadUInt16();
|
||||
for (int i = 0; i < num_values; i++)
|
||||
{
|
||||
MarkConstantPoolUsageForAnnotationComponentValue(br, inUse);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new ClassFormatError("");
|
||||
}
|
||||
}
|
||||
|
||||
private bool EmitInterlockedCompareAndSet(MethodWrapper method, string fieldName, CodeEmitter ilGenerator)
|
||||
{
|
||||
TypeWrapper[] parameters = method.GetParameters();
|
||||
|
|
|
@ -80,6 +80,8 @@ namespace IKVM.Internal
|
|||
private static ConstructorInfo enclosingMethodAttribute;
|
||||
private static ConstructorInfo signatureAttribute;
|
||||
private static ConstructorInfo methodParametersAttribute;
|
||||
private static ConstructorInfo runtimeVisibleTypeAnnotationsAttribute;
|
||||
private static ConstructorInfo constantPoolAttribute;
|
||||
private static CustomAttributeBuilder paramArrayAttribute;
|
||||
private static ConstructorInfo nonNestedInnerClassAttribute;
|
||||
private static ConstructorInfo nonNestedOuterClassAttribute;
|
||||
|
@ -107,6 +109,8 @@ namespace IKVM.Internal
|
|||
private static readonly Type typeofNonNestedOuterClassAttribute = JVM.LoadType(typeof(NonNestedOuterClassAttribute));
|
||||
private static readonly Type typeofEnclosingMethodAttribute = JVM.LoadType(typeof(EnclosingMethodAttribute));
|
||||
private static readonly Type typeofMethodParametersAttribute = JVM.LoadType(typeof(MethodParametersAttribute));
|
||||
private static readonly Type typeofRuntimeVisibleTypeAnnotationsAttribute = JVM.LoadType(typeof(RuntimeVisibleTypeAnnotationsAttribute));
|
||||
private static readonly Type typeofConstantPoolAttribute = JVM.LoadType(typeof(ConstantPoolAttribute));
|
||||
private static readonly CustomAttributeBuilder hideFromJavaAttribute = new CustomAttributeBuilder(typeofHideFromJavaAttribute.GetConstructor(Type.EmptyTypes), new object[0]);
|
||||
private static readonly CustomAttributeBuilder hideFromReflection = new CustomAttributeBuilder(typeofHideFromJavaAttribute.GetConstructor(new Type[] { typeofHideFromJavaFlags }), new object[] { HideFromJavaFlags.Reflection | HideFromJavaFlags.StackTrace | HideFromJavaFlags.StackWalk });
|
||||
|
||||
|
@ -874,6 +878,42 @@ namespace IKVM.Internal
|
|||
mb.SetCustomAttribute(new CustomAttributeBuilder(methodParametersAttribute, new object[] { modifiers }));
|
||||
}
|
||||
|
||||
internal static void SetRuntimeVisibleTypeAnnotationsAttribute(TypeBuilder tb, byte[] data)
|
||||
{
|
||||
if(runtimeVisibleTypeAnnotationsAttribute == null)
|
||||
{
|
||||
runtimeVisibleTypeAnnotationsAttribute = typeofRuntimeVisibleTypeAnnotationsAttribute.GetConstructor(new Type[] { Types.Byte.MakeArrayType() });
|
||||
}
|
||||
tb.SetCustomAttribute(new CustomAttributeBuilder(runtimeVisibleTypeAnnotationsAttribute, new object[] { data }));
|
||||
}
|
||||
|
||||
internal static void SetRuntimeVisibleTypeAnnotationsAttribute(FieldBuilder fb, byte[] data)
|
||||
{
|
||||
if(runtimeVisibleTypeAnnotationsAttribute == null)
|
||||
{
|
||||
runtimeVisibleTypeAnnotationsAttribute = typeofRuntimeVisibleTypeAnnotationsAttribute.GetConstructor(new Type[] { Types.Byte.MakeArrayType() });
|
||||
}
|
||||
fb.SetCustomAttribute(new CustomAttributeBuilder(runtimeVisibleTypeAnnotationsAttribute, new object[] { data }));
|
||||
}
|
||||
|
||||
internal static void SetRuntimeVisibleTypeAnnotationsAttribute(MethodBuilder mb, byte[] data)
|
||||
{
|
||||
if(runtimeVisibleTypeAnnotationsAttribute == null)
|
||||
{
|
||||
runtimeVisibleTypeAnnotationsAttribute = typeofRuntimeVisibleTypeAnnotationsAttribute.GetConstructor(new Type[] { Types.Byte.MakeArrayType() });
|
||||
}
|
||||
mb.SetCustomAttribute(new CustomAttributeBuilder(runtimeVisibleTypeAnnotationsAttribute, new object[] { data }));
|
||||
}
|
||||
|
||||
internal static void SetConstantPoolAttribute(TypeBuilder tb, object[] constantPool)
|
||||
{
|
||||
if(constantPoolAttribute == null)
|
||||
{
|
||||
constantPoolAttribute = typeofConstantPoolAttribute.GetConstructor(new Type[] { Types.Object.MakeArrayType() });
|
||||
}
|
||||
tb.SetCustomAttribute(new CustomAttributeBuilder(constantPoolAttribute, new object[] { constantPool }));
|
||||
}
|
||||
|
||||
internal static void SetParamArrayAttribute(ParameterBuilder pb)
|
||||
{
|
||||
if(paramArrayAttribute == null)
|
||||
|
@ -1017,6 +1057,34 @@ namespace IKVM.Internal
|
|||
#endif
|
||||
}
|
||||
|
||||
internal static object[] GetConstantPool(Type type)
|
||||
{
|
||||
#if !STATIC_COMPILER && !STUB_GENERATOR
|
||||
object[] attribs = type.GetCustomAttributes(typeof(ConstantPoolAttribute), false);
|
||||
return attribs.Length == 1 ? ((ConstantPoolAttribute)attribs[0]).constantPool : null;
|
||||
#else
|
||||
foreach(CustomAttributeData cad in CustomAttributeData.__GetCustomAttributes(type, typeofConstantPoolAttribute, false))
|
||||
{
|
||||
return DecodeArray<object>(cad.ConstructorArguments[0]);
|
||||
}
|
||||
return null;
|
||||
#endif
|
||||
}
|
||||
|
||||
internal static byte[] GetRuntimeVisibleTypeAnnotations(MemberInfo member)
|
||||
{
|
||||
#if !STATIC_COMPILER && !STUB_GENERATOR
|
||||
object[] attribs = member.GetCustomAttributes(typeof(RuntimeVisibleTypeAnnotationsAttribute), false);
|
||||
return attribs.Length == 1 ? ((RuntimeVisibleTypeAnnotationsAttribute)attribs[0]).data : null;
|
||||
#else
|
||||
foreach(CustomAttributeData cad in CustomAttributeData.__GetCustomAttributes(member, typeofRuntimeVisibleTypeAnnotationsAttribute, false))
|
||||
{
|
||||
return DecodeArray<byte>(cad.ConstructorArguments[0]);
|
||||
}
|
||||
return null;
|
||||
#endif
|
||||
}
|
||||
|
||||
internal static InnerClassAttribute GetInnerClass(Type type)
|
||||
{
|
||||
#if !STATIC_COMPILER && !STUB_GENERATOR
|
||||
|
@ -5164,6 +5232,28 @@ namespace IKVM.Internal
|
|||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
internal override object[] GetConstantPool()
|
||||
{
|
||||
return AttributeHelper.GetConstantPool(type);
|
||||
}
|
||||
|
||||
internal override byte[] GetRawTypeAnnotations()
|
||||
{
|
||||
return AttributeHelper.GetRuntimeVisibleTypeAnnotations(type);
|
||||
}
|
||||
|
||||
internal override byte[] GetMethodRawTypeAnnotations(MethodWrapper mw)
|
||||
{
|
||||
MethodBase mb = mw.GetMethod();
|
||||
return mb == null ? null : AttributeHelper.GetRuntimeVisibleTypeAnnotations(mb);
|
||||
}
|
||||
|
||||
internal override byte[] GetFieldRawTypeAnnotations(FieldWrapper fw)
|
||||
{
|
||||
FieldInfo fi = fw.GetField();
|
||||
return fi == null ? null : AttributeHelper.GetRuntimeVisibleTypeAnnotations(fi);
|
||||
}
|
||||
}
|
||||
|
||||
sealed class ArrayTypeWrapper : TypeWrapper
|
||||
|
|
|
@ -881,6 +881,79 @@ namespace IKVM.Attributes
|
|||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface)]
|
||||
public sealed class ConstantPoolAttribute : Attribute
|
||||
{
|
||||
internal readonly object[] constantPool;
|
||||
|
||||
public ConstantPoolAttribute(object[] constantPool)
|
||||
{
|
||||
this.constantPool = Decompress(constantPool);
|
||||
}
|
||||
|
||||
private static object[] Decompress(object[] constantPool)
|
||||
{
|
||||
List<object> list = new List<object>();
|
||||
foreach (object obj in constantPool)
|
||||
{
|
||||
int emptySlots = obj as byte? ?? obj as ushort? ?? 0;
|
||||
if (emptySlots == 0)
|
||||
{
|
||||
list.Add(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < emptySlots; i++)
|
||||
{
|
||||
list.Add(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
return list.ToArray();
|
||||
}
|
||||
|
||||
internal static object[] Compress(object[] constantPool, bool[] inUse)
|
||||
{
|
||||
int length = constantPool.Length;
|
||||
while (!inUse[length - 1])
|
||||
{
|
||||
length--;
|
||||
}
|
||||
int write = 0;
|
||||
for (int read = 0; read < length; read++)
|
||||
{
|
||||
int start = read;
|
||||
while (!inUse[read])
|
||||
{
|
||||
read++;
|
||||
}
|
||||
int emptySlots = read - start;
|
||||
if (emptySlots > 255)
|
||||
{
|
||||
constantPool[write++] = (ushort)emptySlots;
|
||||
}
|
||||
else if (emptySlots > 0)
|
||||
{
|
||||
constantPool[write++] = (byte)emptySlots;
|
||||
}
|
||||
constantPool[write++] = constantPool[read];
|
||||
}
|
||||
Array.Resize(ref constantPool, write);
|
||||
return constantPool;
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Field)]
|
||||
public sealed class RuntimeVisibleTypeAnnotationsAttribute : Attribute
|
||||
{
|
||||
internal readonly byte[] data;
|
||||
|
||||
public RuntimeVisibleTypeAnnotationsAttribute(byte[] data)
|
||||
{
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
|
||||
// used in custom modifier for access stubs
|
||||
public static class AccessStub { }
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче