25using System.Collections.Generic;
30using IKVM.ByteCode.Decoding;
36 sealed partial class ClassFile : IDisposable
48 throw new ArgumentNullException(nameof(name));
53 for (
int i = 0; i < name.Length; i++)
54 if (
".;[/<>".Contains(name[i]))
71 for (
int i = 0; i < name.Length; i++)
72 if (
".;[/<>".Contains(name[i]))
87 throw new ArgumentNullException(nameof(name));
98 public static bool IsValidFieldName(ReadOnlySpan<char> name, ClassFormatVersion version)
100 if (name.Length == 0)
103 for (
int i = 0; i < name.Length; i++)
104 if (
".;[/".Contains(name[i]))
118 throw new ArgumentNullException(nameof(name));
120 if (!
char.IsLetter(name[0]) &&
"$_".Contains(name[0]) ==
false)
123 for (
int i = 1; i < name.Length; i++)
124 if (!
char.IsLetterOrDigit(name[i]) &&
"$_".Contains(name[i]) ==
false)
137 if (!
char.IsLetter(name[0]) &&
"$_".Contains(name[0]) ==
false)
140 for (
int i = 1; i < name.Length; i++)
141 if (!
char.IsLetterOrDigit(name[i]) &&
"$_".Contains(name[i]) ==
false)
154 if (descriptor is
null)
155 throw new ArgumentNullException(nameof(descriptor));
167 if (descriptor is
null)
168 throw new ArgumentNullException(nameof(descriptor));
180 if (descriptor.IsEmpty)
183 switch (descriptor[0])
187 descriptor = descriptor.Slice(1);
188 return descriptor.Length >= 2 && descriptor.IndexOf(
';') == descriptor.Length - 1;
191 while (descriptor[0] ==
'[')
193 descriptor = descriptor.Slice(1);
194 if (descriptor.IsEmpty)
208 descriptor = descriptor.Slice(1);
209 return descriptor.IsEmpty;
222 if (descriptor is
null)
223 throw new ArgumentNullException(nameof(descriptor));
235 if (descriptor.Length < 3 || descriptor[0] !=
'(')
238 int end = descriptor.IndexOf(
')');
245 for (
int i = 1; i < end; i++)
247 switch (descriptor[i])
259 var p = descriptor.Slice(i).IndexOf(
';');
260 i = p == -1 ? -1 : p + i;
263 while (descriptor[i] ==
'[')
266 if (
"BZCSIJFDL".Contains(descriptor[i]) ==
false)
269 if (descriptor[i] ==
'L')
271 var o = descriptor.Slice(i).IndexOf(
';');
272 i = o == -1 ? -1 : o + i;
280 if (i == -1 || i >= end)
287 const ushort FLAG_MASK_DEPRECATED = 0x100;
288 const ushort FLAG_MASK_INTERNAL = 0x200;
289 const ushort FLAG_CALLERSENSITIVE = 0x400;
290 const ushort FLAG_LAMBDAFORM_COMPILED = 0x800;
291 const ushort FLAG_LAMBDAFORM_HIDDEN = 0x1000;
292 const ushort FLAG_FORCEINLINE = 0x2000;
293 const ushort FLAG_HAS_ASSERTIONS = 0x4000;
294 const ushort FLAG_MODULE_INITIALIZER = 0x8000;
298 readonly IKVM.ByteCode.Decoding.ClassFile clazz;
300 readonly ConstantPoolItem[] constantpool;
301 readonly
string[] utf8_cp;
305 readonly ConstantPoolItemClass[] interfaces;
306 readonly Field[] fields;
307 readonly Method[] methods;
308 readonly
string sourceFile;
312 readonly
string ikvmAssembly;
313 readonly InnerClass[] innerClasses;
314 readonly
object[] annotations;
315 readonly
string signature;
316 readonly
string[] enclosingMethod;
317 readonly BootstrapMethod[] bootstrapMethods;
318 readonly TypeAnnotationTable runtimeVisibleTypeAnnotations = TypeAnnotationTable.Empty;
330 internal static string GetClassName(
byte[] bytes,
int offset,
int length, out
bool isstub)
334 using var clazz =
IKVM.ByteCode.Decoding.ClassFile.Read(bytes.AsMemory(offset, length));
335 return GetClassName(clazz, out isstub);
337 catch (UnsupportedClassVersionException e)
339 throw new UnsupportedClassVersionError(e.Message);
341 catch (ByteCodeException e)
355 static string GetClassName(
IKVM.ByteCode.Decoding.ClassFile reader, out
bool isstub)
357 if (reader.Version <
new ClassFormatVersion(45, 3) || reader.Version >
new ClassFormatVersion((ushort)SupportedVersions.Maximum, 0))
358 throw new UnsupportedClassVersionError(reader.Version);
361 isstub = reader.Constants.Any(i => i.Kind == ConstantKind.Utf8 && reader.Constants.Get((Utf8ConstantHandle)i).Value ==
"IKVM.NET.Assembly");
362 return string.Intern(reader.Constants.Get(reader.This).Name.Replace(
'/',
'.'));
380 this.context = context ??
throw new ArgumentNullException(nameof(context));
381 this.diagnostics = diagnostics ??
throw new ArgumentNullException(nameof(diagnostics));
382 this.clazz = clazz ??
throw new ArgumentNullException(nameof(clazz));
386 if (clazz.Version <
new ClassFormatVersion(45, 3) || clazz.Version >
new ClassFormatVersion((ushort)SupportedVersions.Maximum, 0))
387 throw new UnsupportedClassVersionError(clazz.Version);
390 constantpool =
new ConstantPoolItem[clazz.Constants.SlotCount];
391 utf8_cp =
new string[clazz.Constants.SlotCount];
392 for (ushort i = 1; i < clazz.Constants.SlotCount; i++)
394 switch (clazz.Constants.GetKind(
new ConstantHandle(ConstantKind.Unknown, i)))
396 case ConstantKind.Unknown:
399 case ConstantKind.Class:
400 constantpool[i] =
new ConstantPoolItemClass(context, clazz.Constants.Read(
new ClassConstantHandle(i)));
402 case ConstantKind.Double:
403 constantpool[i] =
new ConstantPoolItemDouble(context, clazz.Constants.Read(
new DoubleConstantHandle(i)));
405 case ConstantKind.Fieldref:
406 constantpool[i] =
new ConstantPoolItemFieldref(context, clazz.Constants.Read(
new FieldrefConstantHandle(i)));
408 case ConstantKind.Float:
409 constantpool[i] =
new ConstantPoolItemFloat(context, clazz.Constants.Read(
new FloatConstantHandle(i)));
411 case ConstantKind.Integer:
412 constantpool[i] =
new ConstantPoolItemInteger(context, clazz.Constants.Read(
new IntegerConstantHandle(i)));
414 case ConstantKind.InterfaceMethodref:
415 constantpool[i] =
new ConstantPoolItemInterfaceMethodref(context, clazz.Constants.Read(
new InterfaceMethodrefConstantHandle(i)));
417 case ConstantKind.Long:
418 constantpool[i] =
new ConstantPoolItemLong(context, clazz.Constants.Read(
new LongConstantHandle(i)));
420 case ConstantKind.Methodref:
421 constantpool[i] =
new ConstantPoolItemMethodref(context, clazz.Constants.Read(
new MethodrefConstantHandle(i)));
423 case ConstantKind.NameAndType:
424 constantpool[i] =
new ConstantPoolItemNameAndType(context, clazz.Constants.Read(
new NameAndTypeConstantHandle(i)));
426 case ConstantKind.MethodHandle:
427 if (clazz.Version < 51)
429 constantpool[i] =
new ConstantPoolItemMethodHandle(context, clazz.Constants.Read(
new MethodHandleConstantHandle(i)));
431 case ConstantKind.MethodType:
432 if (clazz.Version < 51)
434 constantpool[i] =
new ConstantPoolItemMethodType(context, clazz.Constants.Read(
new MethodTypeConstantHandle(i)));
436 case ConstantKind.InvokeDynamic:
437 if (clazz.Version < 51)
439 constantpool[i] =
new ConstantPoolItemInvokeDynamic(context, clazz.Constants.Read(
new InvokeDynamicConstantHandle(i)));
441 case ConstantKind.String:
442 constantpool[i] =
new ConstantPoolItemString(context, clazz.Constants.Read(
new StringConstantHandle(i)));
444 case ConstantKind.Utf8:
445 utf8_cp[i] = clazz.Constants.Read(
new Utf8ConstantHandle(i)).Value;
452 if (constantPoolPatches !=
null)
453 PatchConstantPool(constantPoolPatches, utf8_cp, inputClassName);
455 for (
int i = 1; i < clazz.Constants.SlotCount; i++)
457 if (constantpool[i] !=
null)
461 constantpool[i].Resolve(
this, utf8_cp, options);
469 catch (IndexOutOfRangeException)
471 throw new ClassFormatError(
"{0} (Invalid constant pool item #{1})", inputClassName, i);
473 catch (InvalidCastException)
475 throw new ClassFormatError(
"{0} (Invalid constant pool item #{1})", inputClassName, i);
480 access_flags = (
Modifiers)clazz.AccessFlags;
488 throw new ClassFormatError(
"{0} (Illegal class modifiers 0x{1:X})", inputClassName, access_flags);
490 ValidateConstantPoolItemClass(inputClassName, clazz.This);
491 ValidateConstantPoolItemClass(inputClassName, clazz.Super);
493 if (
IsInterface && (clazz.Super.IsNil || SuperClass.Name !=
"java.lang.Object"))
501 interfaces =
new ConstantPoolItemClass[clazz.Interfaces.Count];
502 for (
int i = 0; i < interfaces.Length; i++)
504 var handle = clazz.Interfaces[i].Class;
505 if (handle.IsNil || handle.Slot >= constantpool.Length)
508 var cpi = constantpool[handle.Slot] as ConstantPoolItemClass;
515 CheckDuplicates(interfaces,
"Repetitive interface name");
517 fields =
new Field[clazz.Fields.Count];
518 for (
int i = 0; i < clazz.Fields.Count; i++)
520 fields[i] =
new Field(
this, utf8_cp, clazz.Fields[i]);
521 var name = fields[i].Name;
527 CheckDuplicates<FieldOrMethod>(fields,
"Repetitive field name/signature");
529 methods =
new Method[clazz.Methods.Count];
530 for (
int i = 0; i < clazz.Methods.Count; i++)
532 methods[i] =
new Method(
this, utf8_cp, options, clazz.Methods[i]);
533 var name = methods[i].Name;
534 var sig = methods[i].Signature;
537 if (!ReferenceEquals(name, StringConstants.INIT) && !ReferenceEquals(name, StringConstants.CLINIT))
539 if (!sig.EndsWith(
"V"))
540 throw new ClassFormatError(
"{0} (Method \"{1}\" has illegal signature \"{2}\")",
Name, name, sig);
542 RemoveAssertionInit(methods[i]);
546 CheckDuplicates<FieldOrMethod>(methods,
"Repetitive method name/signature");
548 for (
int i = 0; i < clazz.Attributes.Count; i++)
550 var attribute = clazz.Attributes[i];
552 switch (GetConstantPoolUtf8String(utf8_cp, attribute.Name))
554 case AttributeName.Deprecated:
555 var deprecatedAttribute = (DeprecatedAttribute)attribute;
556 flags |= FLAG_MASK_DEPRECATED;
558 case AttributeName.SourceFile:
559 var sourceFileAttribute = (
IKVM.ByteCode.Decoding.SourceFileAttribute)attribute;
560 sourceFile = GetConstantPoolUtf8String(utf8_cp, sourceFileAttribute.SourceFile);
562 case AttributeName.InnerClasses:
566 var innerClassesAttribute = (InnerClassesAttribute)attribute;
567 innerClasses =
new InnerClass[innerClassesAttribute.Table.Count];
568 for (
int j = 0; j < innerClasses.Length; j++)
570 var item = innerClassesAttribute.Table[j];
572 innerClasses[j].innerClass = item.Inner;
573 innerClasses[j].outerClass = item.Outer;
574 innerClasses[j].name = item.InnerName;
575 innerClasses[j].accessFlags = (
Modifiers)item.InnerAccessFlags;
577 if (innerClasses[j].innerClass.IsNotNil && !(GetConstantPoolItem(innerClasses[j].innerClass) is ConstantPoolItemClass))
578 throw new ClassFormatError(
"{0} (inner_class_info_index has bad constant pool index)", this.
Name);
580 if (innerClasses[j].outerClass.IsNotNil && !(GetConstantPoolItem(innerClasses[j].outerClass) is ConstantPoolItemClass))
581 throw new ClassFormatError(
"{0} (outer_class_info_index has bad constant pool index)", this.
Name);
583 if (innerClasses[j].name.IsNotNil && utf8_cp[innerClasses[j].name.Slot] ==
null)
586 if (innerClasses[j].innerClass == innerClasses[j].outerClass)
589 if (innerClasses[j].innerClass.IsNotNil && innerClasses[j].outerClass.IsNotNil)
591 MarkLinkRequiredConstantPoolItem(innerClasses[j].innerClass);
592 MarkLinkRequiredConstantPoolItem(innerClasses[j].outerClass);
597 case AttributeName.Signature:
598 if (clazz.Version < 49)
601 var signatureAttribute = (
IKVM.ByteCode.Decoding.SignatureAttribute)attribute;
602 signature = GetConstantPoolUtf8String(utf8_cp, signatureAttribute.Signature);
604 case AttributeName.EnclosingMethod:
605 if (clazz.Version < 49)
608 var enclosingMethodAttribute = (
IKVM.ByteCode.Decoding.EnclosingMethodAttribute)attribute;
609 var classHandle = enclosingMethodAttribute.Class;
610 var methodHandle = enclosingMethodAttribute.Method;
611 ValidateConstantPoolItemClass(inputClassName, classHandle);
613 if (methodHandle.IsNil)
617 GetConstantPoolClass(classHandle),
624 if (GetConstantPoolItem(methodHandle) is not ConstantPoolItemNameAndType m)
625 throw new ClassFormatError(
"{0} (Bad constant pool index #{1})", inputClassName, methodHandle);
627 enclosingMethod =
new string[]
629 GetConstantPoolClass(classHandle),
630 GetConstantPoolUtf8String(utf8_cp, m.NameHandle),
631 GetConstantPoolUtf8String(utf8_cp, m.DescriptorHandle).Replace(
'/',
'.')
636 case AttributeName.RuntimeVisibleAnnotations:
637 if (clazz.Version < 49)
640 var runtimeVisibleAnnotationsAttribute = (RuntimeVisibleAnnotationsAttribute)attribute;
641 annotations = ReadAnnotations(runtimeVisibleAnnotationsAttribute.Annotations,
this, utf8_cp);
644 case AttributeName.RuntimeInvisibleAnnotations:
645 if (clazz.Version < 49)
648 var runtimeInvisibleAnnotationsAttribute = (RuntimeInvisibleAnnotationsAttribute)attribute;
649 foreach (var annot
in ReadAnnotations(runtimeInvisibleAnnotationsAttribute.Annotations,
this, utf8_cp))
651 if (annot[1].Equals(
"Likvm/lang/Internal;"))
654 flags |= FLAG_MASK_INTERNAL;
660 case AttributeName.BootstrapMethods:
661 if (clazz.Version < 51)
664 var bootstrapMethodsAttribute = (BootstrapMethodsAttribute)attribute;
665 bootstrapMethods = ReadBootstrapMethods(bootstrapMethodsAttribute.Methods,
this);
667 case AttributeName.RuntimeVisibleTypeAnnotations:
668 if (clazz.Version < 52)
671 var _runtimeVisibleTypeAnnotations = (
IKVM.ByteCode.Decoding.RuntimeVisibleTypeAnnotationsAttribute)attribute;
672 CreateUtf8ConstantPoolItems(utf8_cp);
673 runtimeVisibleTypeAnnotations = _runtimeVisibleTypeAnnotations.TypeAnnotations;
675 case "IKVM.NET.Assembly":
676 if (attribute.Data.Length != 2)
677 throw new ClassFormatError(
"IKVM.NET.Assembly attribute has incorrect length");
679 var r =
new ClassFormatReader(attribute.Data);
680 if (r.TryReadU2(out var index) ==
false)
681 throw new ClassFormatError(
"IKVM.NET.Assembly attribute has incorrect length");
683 ikvmAssembly = GetConstantPoolUtf8String(utf8_cp,
new(index));
691 for (
int i = 1; i < constantpool.Length; i++)
692 if (constantpool[i] !=
null && constantpool[i] is ConstantPoolItemInvokeDynamic cpi)
693 if (bootstrapMethods ==
null || cpi.BootstrapMethod >= bootstrapMethods.Length)
694 throw new ClassFormatError(
"Short length on BootstrapMethods in class file");
696 catch (OverflowException)
700 catch (IndexOutOfRangeException)
704 catch (ByteCodeException)
710 void CreateUtf8ConstantPoolItems(
string[] utf8_cp)
712 for (
int i = 0; i < constantpool.Length; i++)
713 if (constantpool[i] ==
null && utf8_cp[i] !=
null)
714 constantpool[i] =
new ConstantPoolItemUtf8(context, utf8_cp[i]);
717 void CheckDuplicates<T>(T[] members,
string msg)
718 where T : IEquatable<T>
720 if (members.Length < 100)
722 for (
int i = 0; i < members.Length; i++)
723 for (
int j = 0; j < i; j++)
724 if (members[i].Equals(members[j]))
729 var hs =
new HashSet<T>();
730 for (
int i = 0; i < members.Length; i++)
731 if (hs.Add(members[i]) ==
false)
736 void PatchConstantPool(
object[] constantPoolPatches,
string[] utf8_cp,
string inputClassName)
738#if !IMPORTER && !FIRST_PASS
739 for (
int i = 0; i < constantPoolPatches.Length; i++)
741 if (constantPoolPatches[i] !=
null)
743 if (utf8_cp[i] !=
null)
745 if (!(constantPoolPatches[i] is
string))
746 throw new ClassFormatError(
"Illegal utf8 patch at {0} in class file {1}", i, inputClassName);
748 utf8_cp[i] = (string)constantPoolPatches[i];
750 else if (constantpool[i] !=
null)
752 switch (constantpool[i].GetConstantType())
754 case ConstantType.String:
755 constantpool[i] =
new ConstantPoolItemLiveObject(context, constantPoolPatches[i]);
757 case ConstantType.Class:
758 java.lang.Class clazz;
760 if ((clazz = constantPoolPatches[i] as
java.
lang.Class) !=
null)
762 var tw = RuntimeJavaType.FromClass(clazz);
763 constantpool[i] =
new ConstantPoolItemClass(context, tw.Name, tw);
765 else if ((name = constantPoolPatches[i] as
string) !=
null)
767 constantpool[i] =
new ConstantPoolItemClass(context,
string.Intern(name.Replace(
'/',
'.')),
null);
771 throw new ClassFormatError(
"Illegal class patch at {0} in class file {1}", i, inputClassName);
774 case ConstantType.Integer:
775 ((ConstantPoolItemInteger)constantpool[i])._value = ((
java.
lang.Integer)constantPoolPatches[i]).intValue();
777 case ConstantType.Long:
778 ((ConstantPoolItemLong)constantpool[i])._value = ((
java.
lang.Long)constantPoolPatches[i]).longValue();
780 case ConstantType.Float:
781 ((ConstantPoolItemFloat)constantpool[i])._value = ((
java.
lang.Float)constantPoolPatches[i]).floatValue();
783 case ConstantType.Double:
784 ((ConstantPoolItemDouble)constantpool[i])._value = ((
java.
lang.Double)constantPoolPatches[i]).doubleValue();
787 throw new NotImplementedException(
"ConstantPoolPatch: " + constantPoolPatches[i]);
795 void MarkLinkRequiredConstantPoolItem(ConstantHandle handle)
797 if (handle.Slot > 0 && handle.Slot < constantpool.Length && constantpool[handle.Slot] !=
null)
798 constantpool[handle.Slot].MarkLinkRequired();
801 void MarkLinkRequiredConstantPoolItem(
int index)
803 MarkLinkRequiredConstantPoolItem(
new ConstantHandle(ConstantKind.Unknown, checked((ushort)index)));
806 static BootstrapMethod[] ReadBootstrapMethods(BootstrapMethodTable methods, ClassFile classFile)
808 var bsm =
new BootstrapMethod[methods.Count];
809 for (
int i = 0; i < methods.Count; i++)
811 var method = methods[i];
813 var bsm_index = method.Method;
814 if (bsm_index.Slot >= classFile.constantpool.Length || classFile.constantpool[bsm_index.Slot] is not ConstantPoolItemMethodHandle)
815 throw new ClassFormatError(
"bootstrap_method_index {0} has bad constant type in class file {1}", bsm_index, classFile.Name);
817 classFile.MarkLinkRequiredConstantPoolItem(bsm_index);
819 var argument_count = method.Arguments.Count;
820 var args =
new ConstantHandle[argument_count];
821 for (
int j = 0; j < args.Length; j++)
823 var argument_index = method.Arguments[j];
824 if (classFile.IsValidConstant(argument_index) ==
false)
825 throw new ClassFormatError(
"argument_index {0} has bad constant type in class file {1}", argument_index, classFile.Name);
827 classFile.MarkLinkRequiredConstantPoolItem(argument_index);
828 args[j] = argument_index;
831 bsm[i] =
new BootstrapMethod(bsm_index, args);
837 bool IsValidConstant(ConstantHandle handle)
839 if (handle.Slot < constantpool.Length && constantpool[handle.Slot] !=
null)
843 constantpool[handle.Slot].GetConstantType();
846 catch (InvalidOperationException)
855 static object[][] ReadAnnotations(AnnotationTable reader, ClassFile classFile,
string[] utf8_cp)
857 var annotations =
new object[reader.Count][];
859 for (
int i = 0; i < annotations.Length; i++)
860 annotations[i] = ReadAnnotation(reader[i], classFile, utf8_cp);
865 static object[] ReadAnnotation(
IKVM.ByteCode.Decoding.Annotation annotation, ClassFile classFile,
string[] utf8_cp)
867 var l =
new object[2 + annotation.Elements.Count * 2];
869 l[1] = classFile.GetConstantPoolUtf8String(utf8_cp, annotation.Type);
870 for (
int i = 0; i < annotation.Elements.Count; i++)
872 l[2 + i * 2 + 0] = classFile.GetConstantPoolUtf8String(utf8_cp, annotation.Elements[i].Name);
873 l[2 + i * 2 + 1] = ReadAnnotationElementValue(annotation.Elements[i].Value, classFile, utf8_cp);
879 static object ReadAnnotationElementValue(in ElementValue reader, ClassFile classFile,
string[] utf8_cp)
885 case ElementValueKind.Boolean:
886 return classFile.GetConstantPoolConstantInteger((IntegerConstantHandle)((ConstantElementValue)reader).Handle) != 0;
887 case ElementValueKind.Byte:
888 return (
byte)classFile.GetConstantPoolConstantInteger((IntegerConstantHandle)((ConstantElementValue)reader).Handle);
889 case ElementValueKind.Char:
890 return (
char)classFile.GetConstantPoolConstantInteger((IntegerConstantHandle)((ConstantElementValue)reader).Handle);
891 case ElementValueKind.Short:
892 return (
short)classFile.GetConstantPoolConstantInteger((IntegerConstantHandle)((ConstantElementValue)reader).Handle);
893 case ElementValueKind.Integer:
894 return classFile.GetConstantPoolConstantInteger((IntegerConstantHandle)((ConstantElementValue)reader).Handle);
895 case ElementValueKind.Float:
896 return classFile.GetConstantPoolConstantFloat((FloatConstantHandle)((ConstantElementValue)reader).Handle);
897 case ElementValueKind.Long:
898 return classFile.GetConstantPoolConstantLong((LongConstantHandle)((ConstantElementValue)reader).Handle);
899 case ElementValueKind.Double:
900 return classFile.GetConstantPoolConstantDouble((DoubleConstantHandle)((ConstantElementValue)reader).Handle);
901 case ElementValueKind.String:
902 return classFile.GetConstantPoolUtf8String(utf8_cp, (Utf8ConstantHandle)((ConstantElementValue)reader).Handle);
903 case ElementValueKind.Enum:
904 var _enum = (EnumElementValue)reader;
905 return new object[] {
907 classFile.GetConstantPoolUtf8String(utf8_cp, _enum.TypeName),
908 classFile.GetConstantPoolUtf8String(utf8_cp, _enum.ConstantName)
910 case ElementValueKind.Class:
911 var _class = (ClassElementValue)reader;
912 return new object[] {
914 classFile.GetConstantPoolUtf8String(utf8_cp, _class.Class)
916 case ElementValueKind.Annotation:
917 return ReadAnnotation(((AnnotationElementValue)reader).
Annotation, classFile, utf8_cp);
918 case ElementValueKind.Array:
919 var _array = (ArrayElementValue)reader;
921 var array =
new object[_array.Count + 1];
923 for (
int i = 0; i < _array.Count; i++)
924 array[i + 1] = ReadAnnotationElementValue(_array[i], classFile, utf8_cp);
928 throw new ClassFormatError(
"Invalid tag {0} in annotation element_value", reader.Kind);
931 catch (NullReferenceException)
935 catch (InvalidCastException)
939 catch (IndexOutOfRangeException)
943 catch (ByteCodeException)
951 void ValidateConstantPoolItemClass(
string classFile, ClassConstantHandle handle)
953 if (handle.Slot >= constantpool.Length || constantpool[handle.Slot] is not ConstantPoolItemClass)
954 throw new ClassFormatError(
"{0} (Bad constant pool index #{1})", classFile, handle);
970 ((ConstantPoolItemClass)constantpool[clazz.This.Slot]).LinkSelf(thisType);
972 for (
int i = 1; i < constantpool.Length; i++)
973 if (constantpool[i] !=
null)
974 constantpool[i].Link(thisType, mode);
1022 internal bool IsReferenced(Field fld) => constantpool.OfType<ConstantPoolItemFieldref>().Any(i => i.Class ==
Name && i.Name == fld.Name && i.Signature == fld.Signature);
1029 internal ConstantPoolItemFieldref GetFieldref(FieldrefConstantHandle handle)
1031 return (ConstantPoolItemFieldref)constantpool[handle.Slot];
1039 internal ConstantPoolItemFieldref GetFieldref(
int slot)
1041 return GetFieldref(
new FieldrefConstantHandle(checked((ushort)slot)));
1049 internal ConstantPoolItemFieldref SafeGetFieldref(ConstantHandle handle)
1051 if (handle.IsNotNil && handle.Slot < constantpool.Length)
1052 return constantpool[handle.Slot] as ConstantPoolItemFieldref;
1062 internal ConstantPoolItemFieldref SafeGetFieldref(
int index)
1064 if (index > ushort.MaxValue || index < ushort.MinValue)
1067 return SafeGetFieldref(
new ConstantHandle(ConstantKind.Unknown, (ushort)index));
1070 internal ConstantPoolItemMI GetMethodref(MethodrefConstantHandle handle)
1072 return (ConstantPoolItemMI)constantpool[handle.Slot];
1076 internal ConstantPoolItemMI GetMethodref(
int handle)
1078 return GetMethodref(
new MethodrefConstantHandle(checked((ushort)handle)));
1086 internal ConstantPoolItemMI SafeGetMethodref(ConstantHandle handle)
1088 if (handle.IsNotNil && handle.Slot < constantpool.Length)
1089 return constantpool[handle.Slot] as ConstantPoolItemMI;
1099 internal ConstantPoolItemMI SafeGetMethodref(
int slot)
1101 if (slot > ushort.MaxValue || slot < ushort.MinValue)
1104 return SafeGetMethodref(
new ConstantHandle(ConstantKind.Unknown, (ushort)slot));
1107 internal ConstantPoolItemInvokeDynamic GetInvokeDynamic(InvokeDynamicConstantHandle handle)
1109 return (ConstantPoolItemInvokeDynamic)constantpool[handle.Slot];
1112 private ConstantPoolItem GetConstantPoolItem(ConstantHandle handle)
1114 return constantpool[handle.Slot];
1117 internal string GetConstantPoolClass(ClassConstantHandle handle)
1119 return ((ConstantPoolItemClass)constantpool[handle.Slot]).Name;
1122 private bool SafeIsConstantPoolClass(ClassConstantHandle handle)
1124 if (handle.Slot > 0 && handle.Slot < constantpool.Length)
1125 return constantpool[handle.Slot] as ConstantPoolItemClass !=
null;
1130 internal RuntimeJavaType GetConstantPoolClassType(ClassConstantHandle handle)
1132 return ((ConstantPoolItemClass)constantpool[handle.Slot]).GetClassType();
1135 internal RuntimeJavaType GetConstantPoolClassType(
int slot)
1137 return GetConstantPoolClassType(
new ClassConstantHandle(checked((ushort)slot)));
1139 string GetConstantPoolUtf8String(
string[] utf8_cp, Utf8ConstantHandle handle)
1141 var s = utf8_cp[handle.Slot];
1144 if (clazz.This.IsNil)
1153 internal ConstantType GetConstantPoolConstantType(ConstantHandle handle)
1155 return constantpool[handle.Slot].GetConstantType();
1158 internal ConstantType GetConstantPoolConstantType(
int slot)
1160 return GetConstantPoolConstantType(
new ConstantHandle(ConstantKind.Unknown, checked((ushort)slot)));
1163 internal double GetConstantPoolConstantDouble(DoubleConstantHandle handle)
1165 return ((ConstantPoolItemDouble)constantpool[handle.Slot]).Value;
1168 internal float GetConstantPoolConstantFloat(FloatConstantHandle handle)
1170 return ((ConstantPoolItemFloat)constantpool[handle.Slot]).Value;
1173 internal int GetConstantPoolConstantInteger(IntegerConstantHandle handle)
1175 return ((ConstantPoolItemInteger)constantpool[handle.Slot]).Value;
1178 internal long GetConstantPoolConstantLong(LongConstantHandle handle)
1180 return ((ConstantPoolItemLong)constantpool[handle.Slot]).Value;
1183 internal string GetConstantPoolConstantString(StringConstantHandle handle)
1185 return ((ConstantPoolItemString)constantpool[handle.Slot]).Value;
1188 internal string GetConstantPoolConstantString(
int slot)
1190 return GetConstantPoolConstantString(
new StringConstantHandle(checked((ushort)slot)));
1193 internal ConstantPoolItemMethodHandle GetConstantPoolConstantMethodHandle(MethodHandleConstantHandle handle)
1195 return (ConstantPoolItemMethodHandle)constantpool[handle.Slot];
1198 internal ConstantPoolItemMethodHandle GetConstantPoolConstantMethodHandle(
int slot)
1200 return GetConstantPoolConstantMethodHandle(
new MethodHandleConstantHandle(checked((ushort)slot)));
1203 internal ConstantPoolItemMethodType GetConstantPoolConstantMethodType(MethodTypeConstantHandle handle)
1205 return (ConstantPoolItemMethodType)constantpool[handle.Slot];
1208 internal ConstantPoolItemMethodType GetConstantPoolConstantMethodType(
int slot)
1210 return GetConstantPoolConstantMethodType(
new MethodTypeConstantHandle(checked((ushort)slot)));
1213 internal object GetConstantPoolConstantLiveObject(
int slot)
1215 return ((ConstantPoolItemLiveObject)constantpool[slot]).Value;
1221 internal string Name => GetConstantPoolClass(clazz.This);
1226 internal ConstantPoolItemClass SuperClass => (ConstantPoolItemClass)constantpool[clazz.Super.Slot];
1231 internal Field[] Fields => fields;
1236 internal Method[] Methods => methods;
1241 internal ConstantPoolItemClass[] Interfaces => interfaces;
1245 internal string SourcePath
1248 get {
return sourcePath; }
1249 set { sourcePath = value; }
1251 get {
return sourceFile; }
1255 internal object[] Annotations => annotations;
1257 internal string GenericSignature => signature;
1259 internal string[] EnclosingMethod => enclosingMethod;
1261 internal ref readonly TypeAnnotationTable RuntimeVisibleTypeAnnotations =>
ref runtimeVisibleTypeAnnotations;
1263 internal object[] GetConstantPool()
1265 var cp =
new object[constantpool.Length];
1266 for (
int i = 1; i < cp.Length; i++)
1267 if (constantpool[i] !=
null)
1268 cp[i] = constantpool[i].GetRuntimeValue();
1273 internal string IKVMAssemblyAttribute => ikvmAssembly;
1275 internal bool DeprecatedAttribute => (flags & FLAG_MASK_DEPRECATED) != 0;
1280 internal bool IsInternal => (flags & FLAG_MASK_INTERNAL) != 0;
1283 internal void SetInternal()
1286 flags |= FLAG_MASK_INTERNAL;
1289 internal bool HasAssertions => (flags & FLAG_HAS_ASSERTIONS) != 0;
1291 internal bool HasInitializedFields
1295 foreach (Field f
in fields)
1296 if (f.IsStatic && !f.IsFinal && f.ConstantValue !=
null)
1303 internal BootstrapMethod GetBootstrapMethod(
int index)
1305 return bootstrapMethods[index];
1308 internal InnerClass[] InnerClasses => innerClasses;
1310 internal Field GetField(
string name,
string sig)
1312 for (
int i = 0; i < fields.Length; i++)
1313 if (fields[i].
Name == name && fields[i].Signature == sig)
1323 void RemoveAssertionInit(Method method)
1334 ConstantPoolItemFieldref fieldref;
1336 if (method.Instructions is [
1337 { NormalizedOpCode: NormalizedByteCode.__ldc },
1338 { NormalizedOpCode: NormalizedByteCode.__invokevirtual },
1339 { NormalizedOpCode: NormalizedByteCode.__ifne },
1340 { NormalizedOpCode: NormalizedByteCode.__iconst },
1341 { NormalizedOpCode: NormalizedByteCode.__goto },
1342 { NormalizedOpCode: NormalizedByteCode.__iconst },
1343 { NormalizedOpCode: NormalizedByteCode.__putstatic },
1345 method.Instructions[0].NormalizedOpCode ==
NormalizedByteCode.__ldc && SafeIsConstantPoolClass(
new ClassConstantHandle(checked((ushort)method.Instructions[0].Arg1))) &&
1346 method.Instructions[1].NormalizedOpCode ==
NormalizedByteCode.__invokevirtual && IsDesiredAssertionStatusMethodref(method.Instructions[1].Arg1) &&
1347 method.Instructions[2].NormalizedOpCode ==
NormalizedByteCode.__ifne && method.Instructions[2].TargetIndex == 5 &&
1348 method.Instructions[3].NormalizedOpCode ==
NormalizedByteCode.__iconst && method.Instructions[3].Arg1 == 1 &&
1349 method.Instructions[4].NormalizedOpCode ==
NormalizedByteCode.__goto && method.Instructions[4].TargetIndex == 6 &&
1350 method.Instructions[5].NormalizedOpCode ==
NormalizedByteCode.__iconst && method.Instructions[5].Arg1 == 0 &&
1351 method.Instructions[6].NormalizedOpCode ==
NormalizedByteCode.__putstatic && (fieldref = SafeGetFieldref(method.Instructions[6].Arg1)) !=
null &&
1352 fieldref.Class ==
Name && fieldref.Signature ==
"Z" &&
1353 (field = GetField(fieldref.Name, fieldref.Signature)) !=
null &&
1354 field.IsStatic && field.IsFinal &&
1355 !HasBranchIntoRegion(method.Instructions, 7, method.Instructions.Length, 0, 7) &&
1356 !HasStaticFieldWrite(method.Instructions, 7, method.Instructions.Length, field) &&
1357 !HasExceptionHandlerInRegion(method.ExceptionTable, 0, 7))
1359 field.PatchConstantValue(
true);
1361 flags |= FLAG_HAS_ASSERTIONS;
1365 bool IsDesiredAssertionStatusMethodref(
int cpi)
1367 return SafeGetMethodref(cpi) is ConstantPoolItemMethodref {
Class:
"java.lang.Class",
Name:
"desiredAssertionStatus", Signature:
"()Z" };
1370 private static bool HasBranchIntoRegion(Method.Instruction[] instructions,
int checkStart,
int checkEnd,
int regionStart,
int regionEnd)
1372 for (
int i = checkStart; i < checkEnd; i++)
1374 switch (instructions[i].NormalizedOpCode)
1394 if (instructions[i].TargetIndex > regionStart && instructions[i].TargetIndex < regionEnd)
1401 if (instructions[i].DefaultTarget > regionStart && instructions[i].DefaultTarget < regionEnd)
1405 for (
int j = 0; j < instructions[i].SwitchEntryCount; j++)
1407 if (instructions[i].GetSwitchTargetIndex(j) > regionStart && instructions[i].GetSwitchTargetIndex(j) < regionEnd)
1418 private bool HasStaticFieldWrite(Method.Instruction[] instructions,
int checkStart,
int checkEnd, Field field)
1420 for (
int i = checkStart; i < checkEnd; i++)
1424 ConstantPoolItemFieldref fieldref = SafeGetFieldref(instructions[i].Arg1);
1425 if (fieldref !=
null && fieldref.Class ==
Name && fieldref.Name == field.Name && fieldref.Signature == field.Signature)
1434 private static bool HasExceptionHandlerInRegion(Method.ExceptionTableEntry[] entries,
int regionStart,
int regionEnd)
1436 for (
int i = 0; i < entries.Length; i++)
1438 if (entries[i].handlerIndex > regionStart && entries[i].handlerIndex < regionEnd)
global::java.lang.Class Class
global::java.lang.invoke.LambdaForm.Name Name
const byte TAG_ANNOTATION
bool IsFinal
Gets whether this class file represents a final class.
static bool IsValidFieldName(ReadOnlySpan< char > name, ClassFormatVersion version)
Returns true if the given string is a valid field name given the specified class format version.
static bool IsValidMethodDescriptor(string descriptor)
Returns true if the specified descriptor is a valid method descriptor.
static bool IsValidPre49Identifier(string name)
Returns true if the given string is a valid identifier for pre-49 class files.
static bool IsValidMethodName(ReadOnlySpan< char > name, ClassFormatVersion version)
Returns true if the given string is a valid method name given the specified class format version.
static bool IsValidFieldDescriptor(string descriptor, int start, int end)
Returns true if the specified descriptor is a valid field descriptor.
bool IsAbstract
Gets whether this class file represents an abstract class.
bool IsAnnotation
Gets whether this class file represents an annotation.
bool IsInterface
Gets whether this class file represents an interface.
static bool IsValidFieldName(string name, ClassFormatVersion version)
Returns true if the given string is a valid field name given the specified class format version.
void Link(RuntimeJavaType thisType, LoadMode mode)
Initiates linkage of this class file to the specified java type instance.
static bool IsValidPre49Identifier(ReadOnlySpan< char > name)
Returns true if the given string is a valid identifier for pre-49 class files.
bool IsSuper
Gets whether this class file is a super.
bool IsEnum
Gets whether this class file represents an enum.
bool IsPublic
Gets whether this class file represents a public class.
int MajorVersion
Gets the major version of the class.
static bool IsValidMethodName(string name, ClassFormatVersion version)
Returns true if the given string is a valid method name given the specified class format version.
static bool IsValidMethodDescriptor(ReadOnlySpan< char > descriptor)
Returns true if the specified descriptor is a valid method descriptor.
static bool IsValidFieldDescriptor(string descriptor)
Returns true if the specified descriptor is a valid field descriptor.
Modifiers Modifiers
Gets the modifiers of the class.
static bool IsValidFieldDescriptor(ReadOnlySpan< char > descriptor)
Returns true if the specified descriptor is a valid field descriptor.
Maintains services relevant to an instane of the IKVM runtime.
Exposes methods to accept diagnostic invocations.