diff options
Diffstat (limited to 'runtime/ClassFile.cs')
-rw-r--r-- | runtime/ClassFile.cs | 3910 |
1 files changed, 0 insertions, 3910 deletions
diff --git a/runtime/ClassFile.cs b/runtime/ClassFile.cs deleted file mode 100644 index bdb51002..00000000 --- a/runtime/ClassFile.cs +++ /dev/null @@ -1,3910 +0,0 @@ -/* - Copyright (C) 2002-2014 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 - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ -using System; -using System.IO; -using System.Collections.Generic; -using IKVM.Attributes; - -namespace IKVM.Internal -{ - enum HardError : short - { - NoClassDefFoundError, - IllegalAccessError, - InstantiationError, - IncompatibleClassChangeError, - NoSuchFieldError, - AbstractMethodError, - NoSuchMethodError, - LinkageError, - // "exceptions" that are wrapped in an IncompatibleClassChangeError - IllegalAccessException, - // if an error is added here, it must also be added to MethodAnalyzer.SetHardError() - } - - [Flags] - enum ClassFileParseOptions - { - None = 0, - LocalVariableTable = 1, - LineNumberTable = 2, - RelaxedClassNameValidation = 4, - TrustedAnnotations = 8, - } - - sealed class ClassFile - { - private ConstantPoolItem[] constantpool; - // Modifiers is a ushort, so the next four fields combine into two 32 bit slots - private Modifiers access_flags; - private ushort this_class; - private ushort super_class; - private ushort flags; - private const ushort FLAG_MASK_MAJORVERSION = 0xFF; - private const ushort FLAG_MASK_DEPRECATED = 0x100; - private const ushort FLAG_MASK_INTERNAL = 0x200; - private const ushort FLAG_CALLERSENSITIVE = 0x400; - private const ushort FLAG_LAMBDAFORM_COMPILED = 0x800; - private const ushort FLAG_LAMBDAFORM_HIDDEN = 0x1000; - private const ushort FLAG_FORCEINLINE = 0x2000; - private ConstantPoolItemClass[] interfaces; - private Field[] fields; - private Method[] methods; - private string sourceFile; -#if STATIC_COMPILER - private string sourcePath; -#endif - private string ikvmAssembly; - private InnerClass[] innerClasses; - private object[] annotations; - private string signature; - private string[] enclosingMethod; - private BootstrapMethod[] bootstrapMethods; - private byte[] runtimeVisibleTypeAnnotations; - - private static class SupportedVersions - { - internal static readonly int Minimum = 45; - internal static readonly int Maximum = Experimental.JDK_9 ? 53 : 52; - } - -#if STATIC_COMPILER - // This method parses just enough of the class file to obtain its name and - // determine if the class is a possible ikvmstub generated stub, it doesn't - // validate the class file structure, but it may throw a ClassFormatError if it - // encounters bogus data - internal static string GetClassName(byte[] buf, int offset, int length, out bool isstub) - { - isstub = false; - BigEndianBinaryReader br = new BigEndianBinaryReader(buf, offset, length); - if(br.ReadUInt32() != 0xCAFEBABE) - { - throw new ClassFormatError("Bad magic number"); - } - int minorVersion = br.ReadUInt16(); - int majorVersion = br.ReadUInt16(); - if((majorVersion & FLAG_MASK_MAJORVERSION) != majorVersion - || majorVersion < SupportedVersions.Minimum - || majorVersion > SupportedVersions.Maximum - || (majorVersion == SupportedVersions.Minimum && minorVersion < 3) - || (majorVersion == SupportedVersions.Maximum && minorVersion != 0)) - { - throw new UnsupportedClassVersionError(majorVersion + "." + minorVersion); - } - int constantpoolcount = br.ReadUInt16(); - int[] cpclass = new int[constantpoolcount]; - string[] utf8_cp = new string[constantpoolcount]; - for(int i = 1; i < constantpoolcount; i++) - { - Constant tag = (Constant)br.ReadByte(); - switch(tag) - { - case Constant.Class: - cpclass[i] = br.ReadUInt16(); - break; - case Constant.Double: - case Constant.Long: - br.Skip(8); - i++; - break; - case Constant.Fieldref: - case Constant.InterfaceMethodref: - case Constant.Methodref: - case Constant.InvokeDynamic: - case Constant.NameAndType: - case Constant.Float: - case Constant.Integer: - br.Skip(4); - break; - case Constant.MethodHandle: - br.Skip(3); - break; - case Constant.String: - case Constant.MethodType: - br.Skip(2); - break; - case Constant.Utf8: - isstub |= (utf8_cp[i] = br.ReadString("<unknown>")) == "IKVM.NET.Assembly"; - break; - default: - throw new ClassFormatError("Illegal constant pool type 0x{0:X}", tag); - } - } - br.ReadUInt16(); // access_flags - try - { - return String.Intern(utf8_cp[cpclass[br.ReadUInt16()]].Replace('/', '.')); - } - catch(Exception x) - { - throw new ClassFormatError("{0}: {1}", x.GetType().Name, x.Message); - } - } -#endif // STATIC_COMPILER - - internal ClassFile(byte[] buf, int offset, int length, string inputClassName, ClassFileParseOptions options, object[] constantPoolPatches) - { - try - { - BigEndianBinaryReader br = new BigEndianBinaryReader(buf, offset, length); - if(br.ReadUInt32() != 0xCAFEBABE) - { - throw new ClassFormatError("{0} (Bad magic number)", inputClassName); - } - ushort minorVersion = br.ReadUInt16(); - ushort majorVersion = br.ReadUInt16(); - if((majorVersion & FLAG_MASK_MAJORVERSION) != majorVersion - || majorVersion < SupportedVersions.Minimum - || majorVersion > SupportedVersions.Maximum - || (majorVersion == SupportedVersions.Minimum && minorVersion < 3) - || (majorVersion == SupportedVersions.Maximum && minorVersion != 0)) - { - throw new UnsupportedClassVersionError(inputClassName + " (" + majorVersion + "." + minorVersion + ")"); - } - flags = majorVersion; - int constantpoolcount = br.ReadUInt16(); - constantpool = new ConstantPoolItem[constantpoolcount]; - string[] utf8_cp = new string[constantpoolcount]; - for(int i = 1; i < constantpoolcount; i++) - { - Constant tag = (Constant)br.ReadByte(); - switch(tag) - { - case Constant.Class: - constantpool[i] = new ConstantPoolItemClass(br); - break; - case Constant.Double: - constantpool[i] = new ConstantPoolItemDouble(br); - i++; - break; - case Constant.Fieldref: - constantpool[i] = new ConstantPoolItemFieldref(br); - break; - case Constant.Float: - constantpool[i] = new ConstantPoolItemFloat(br); - break; - case Constant.Integer: - constantpool[i] = new ConstantPoolItemInteger(br); - break; - case Constant.InterfaceMethodref: - constantpool[i] = new ConstantPoolItemInterfaceMethodref(br); - break; - case Constant.Long: - constantpool[i] = new ConstantPoolItemLong(br); - i++; - break; - case Constant.Methodref: - constantpool[i] = new ConstantPoolItemMethodref(br); - break; - case Constant.NameAndType: - constantpool[i] = new ConstantPoolItemNameAndType(br); - break; - case Constant.MethodHandle: - if (majorVersion < 51) - goto default; - constantpool[i] = new ConstantPoolItemMethodHandle(br); - break; - case Constant.MethodType: - if (majorVersion < 51) - goto default; - constantpool[i] = new ConstantPoolItemMethodType(br); - break; - case Constant.InvokeDynamic: - if (majorVersion < 51) - goto default; - constantpool[i] = new ConstantPoolItemInvokeDynamic(br); - break; - case Constant.String: - constantpool[i] = new ConstantPoolItemString(br); - break; - case Constant.Utf8: - utf8_cp[i] = br.ReadString(inputClassName); - break; - default: - throw new ClassFormatError("{0} (Illegal constant pool type 0x{1:X})", inputClassName, tag); - } - } - if (constantPoolPatches != null) - { - PatchConstantPool(constantPoolPatches, utf8_cp, inputClassName); - } - for(int i = 1; i < constantpoolcount; i++) - { - if(constantpool[i] != null) - { - try - { - constantpool[i].Resolve(this, utf8_cp, options); - } - catch(ClassFormatError x) - { - // HACK at this point we don't yet have the class name, so any exceptions throw - // are missing the class name - throw new ClassFormatError("{0} ({1})", inputClassName, x.Message); - } - catch(IndexOutOfRangeException) - { - throw new ClassFormatError("{0} (Invalid constant pool item #{1})", inputClassName, i); - } - catch(InvalidCastException) - { - throw new ClassFormatError("{0} (Invalid constant pool item #{1})", inputClassName, i); - } - } - } - access_flags = (Modifiers)br.ReadUInt16(); - // NOTE although the vmspec says (in 4.1) that interfaces must be marked abstract, earlier versions of - // javac (JDK 1.1) didn't do this, so the VM doesn't enforce this rule for older class files. - // NOTE although the vmspec implies (in 4.1) that ACC_SUPER is illegal on interfaces, it doesn't enforce this - // for older class files. - // (See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6320322) - if((IsInterface && IsFinal) - || (IsAbstract && IsFinal) - || (majorVersion >= 49 && IsAnnotation && !IsInterface) - || (majorVersion >= 49 && IsInterface && (!IsAbstract || IsSuper || IsEnum))) - { - throw new ClassFormatError("{0} (Illegal class modifiers 0x{1:X})", inputClassName, access_flags); - } - this_class = br.ReadUInt16(); - ValidateConstantPoolItemClass(inputClassName, this_class); - super_class = br.ReadUInt16(); - ValidateConstantPoolItemClass(inputClassName, super_class); - if(IsInterface && (super_class == 0 || this.SuperClass.Name != "java.lang.Object")) - { - throw new ClassFormatError("{0} (Interfaces must have java.lang.Object as superclass)", Name); - } - // most checks are already done by ConstantPoolItemClass.Resolve, but since it allows - // array types, we do need to check for that - if(this.Name[0] == '[') - { - throw new ClassFormatError("Bad name"); - } - int interfaces_count = br.ReadUInt16(); - interfaces = new ConstantPoolItemClass[interfaces_count]; - for(int i = 0; i < interfaces.Length; i++) - { - int index = br.ReadUInt16(); - if(index == 0 || index >= constantpool.Length) - { - throw new ClassFormatError("{0} (Illegal constant pool index)", Name); - } - ConstantPoolItemClass cpi = constantpool[index] as ConstantPoolItemClass; - if(cpi == null) - { - throw new ClassFormatError("{0} (Interface name has bad constant type)", Name); - } - interfaces[i] = cpi; - } - CheckDuplicates(interfaces, "Repetitive interface name"); - int fields_count = br.ReadUInt16(); - fields = new Field[fields_count]; - for(int i = 0; i < fields_count; i++) - { - fields[i] = new Field(this, utf8_cp, br); - string name = fields[i].Name; - if(!IsValidFieldName(name, majorVersion)) - { - throw new ClassFormatError("{0} (Illegal field name \"{1}\")", Name, name); - } - } - CheckDuplicates<FieldOrMethod>(fields, "Repetitive field name/signature"); - int methods_count = br.ReadUInt16(); - methods = new Method[methods_count]; - for(int i = 0; i < methods_count; i++) - { - methods[i] = new Method(this, utf8_cp, options, br); - string name = methods[i].Name; - string sig = methods[i].Signature; - if(!IsValidMethodName(name, majorVersion)) - { - if(!ReferenceEquals(name, StringConstants.INIT) && !ReferenceEquals(name, StringConstants.CLINIT)) - { - throw new ClassFormatError("{0} (Illegal method name \"{1}\")", Name, name); - } - if(!sig.EndsWith("V")) - { - throw new ClassFormatError("{0} (Method \"{1}\" has illegal signature \"{2}\")", Name, name, sig); - } - } - } - CheckDuplicates<FieldOrMethod>(methods, "Repetitive method name/signature"); - int attributes_count = br.ReadUInt16(); - for(int i = 0; i < attributes_count; i++) - { - switch(GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16())) - { - case "Deprecated": - if(br.ReadUInt32() != 0) - { - throw new ClassFormatError("Invalid Deprecated attribute length"); - } - flags |= FLAG_MASK_DEPRECATED; - break; - case "SourceFile": - if(br.ReadUInt32() != 2) - { - throw new ClassFormatError("SourceFile attribute has incorrect length"); - } - sourceFile = GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16()); - break; - case "InnerClasses": - { - BigEndianBinaryReader rdr = br; - uint attribute_length = br.ReadUInt32(); - ushort count = rdr.ReadUInt16(); - if(this.MajorVersion >= 49 && attribute_length != 2 + count * (2 + 2 + 2 + 2)) - { - throw new ClassFormatError("{0} (InnerClasses attribute has incorrect length)", this.Name); - } - innerClasses = new InnerClass[count]; - for(int j = 0; j < innerClasses.Length; j++) - { - innerClasses[j].innerClass = rdr.ReadUInt16(); - innerClasses[j].outerClass = rdr.ReadUInt16(); - innerClasses[j].name = rdr.ReadUInt16(); - innerClasses[j].accessFlags = (Modifiers)rdr.ReadUInt16(); - if(innerClasses[j].innerClass != 0 && !(GetConstantPoolItem(innerClasses[j].innerClass) is ConstantPoolItemClass)) - { - throw new ClassFormatError("{0} (inner_class_info_index has bad constant pool index)", this.Name); - } - if(innerClasses[j].outerClass != 0 && !(GetConstantPoolItem(innerClasses[j].outerClass) is ConstantPoolItemClass)) - { - throw new ClassFormatError("{0} (outer_class_info_index has bad constant pool index)", this.Name); - } - if(innerClasses[j].name != 0 && utf8_cp[innerClasses[j].name] == null) - { - throw new ClassFormatError("{0} (inner class name has bad constant pool index)", this.Name); - } - if(innerClasses[j].innerClass == innerClasses[j].outerClass) - { - throw new ClassFormatError("{0} (Class is both inner and outer class)", this.Name); - } - if(innerClasses[j].innerClass != 0 && innerClasses[j].outerClass != 0) - { - MarkLinkRequiredConstantPoolItem(innerClasses[j].innerClass); - MarkLinkRequiredConstantPoolItem(innerClasses[j].outerClass); - } - } - break; - } - case "Signature": - if(majorVersion < 49) - { - goto default; - } - if(br.ReadUInt32() != 2) - { - throw new ClassFormatError("Signature attribute has incorrect length"); - } - signature = GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16()); - break; - case "EnclosingMethod": - if(majorVersion < 49) - { - goto default; - } - if(br.ReadUInt32() != 4) - { - throw new ClassFormatError("EnclosingMethod attribute has incorrect length"); - } - else - { - ushort class_index = br.ReadUInt16(); - ushort method_index = br.ReadUInt16(); - ValidateConstantPoolItemClass(inputClassName, class_index); - if(method_index == 0) - { - enclosingMethod = new string[] { - GetConstantPoolClass(class_index), - null, - null - }; - } - else - { - ConstantPoolItemNameAndType m = GetConstantPoolItem(method_index) as ConstantPoolItemNameAndType; - if(m == null) - { - throw new ClassFormatError("{0} (Bad constant pool index #{1})", inputClassName, method_index); - } - enclosingMethod = new string[] { - GetConstantPoolClass(class_index), - GetConstantPoolUtf8String(utf8_cp, m.name_index), - GetConstantPoolUtf8String(utf8_cp, m.descriptor_index).Replace('/', '.') - }; - } - } - break; - case "RuntimeVisibleAnnotations": - if(majorVersion < 49) - { - goto default; - } - annotations = ReadAnnotations(br, this, utf8_cp); - break; -#if STATIC_COMPILER - case "RuntimeInvisibleAnnotations": - if(majorVersion < 49) - { - goto default; - } - foreach(object[] annot in ReadAnnotations(br, this, utf8_cp)) - { - if(annot[1].Equals("Likvm/lang/Internal;")) - { - this.access_flags &= ~Modifiers.AccessMask; - flags |= FLAG_MASK_INTERNAL; - } - } - break; -#endif - case "BootstrapMethods": - if(majorVersion < 51) - { - goto default; - } - bootstrapMethods = ReadBootstrapMethods(br, this); - break; - case "RuntimeVisibleTypeAnnotations": - if(majorVersion < 52) - { - goto default; - } - CreateUtf8ConstantPoolItems(utf8_cp); - runtimeVisibleTypeAnnotations = br.Section(br.ReadUInt32()).ToArray(); - break; - case "IKVM.NET.Assembly": - if(br.ReadUInt32() != 2) - { - throw new ClassFormatError("IKVM.NET.Assembly attribute has incorrect length"); - } - ikvmAssembly = GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16()); - break; - default: - br.Skip(br.ReadUInt32()); - break; - } - } - // validate the invokedynamic entries to point into the bootstrapMethods array - for(int i = 1; i < constantpoolcount; i++) - { - ConstantPoolItemInvokeDynamic cpi; - if(constantpool[i] != null - && (cpi = constantpool[i] as ConstantPoolItemInvokeDynamic) != null) - { - if(bootstrapMethods == null || cpi.BootstrapMethod >= bootstrapMethods.Length) - { - throw new ClassFormatError("Short length on BootstrapMethods in class file"); - } - } - } - if(br.Position != offset + length) - { - throw new ClassFormatError("Extra bytes at the end of the class file"); - } - } - catch(OverflowException) - { - throw new ClassFormatError("Truncated class file (or section)"); - } - catch(IndexOutOfRangeException) - { - // TODO we should throw more specific errors - throw new ClassFormatError("Unspecified class file format error"); - } - // catch(Exception x) - // { - // Console.WriteLine(x); - // FileStream fs = File.Create(inputClassName + ".broken"); - // fs.Write(buf, offset, length); - // fs.Close(); - // throw; - // } - } - - private void CreateUtf8ConstantPoolItems(string[] utf8_cp) - { - for (int i = 0; i < constantpool.Length; i++) - { - if (constantpool[i] == null && utf8_cp[i] != null) - { - constantpool[i] = new ConstantPoolItemUtf8(utf8_cp[i]); - } - } - } - - private void CheckDuplicates<T>(T[] members, string msg) - where T : IEquatable<T> - { - if (members.Length < 100) - { - for (int i = 0; i < members.Length; i++) - { - for (int j = 0; j < i; j++) - { - if (members[i].Equals(members[j])) - { - throw new ClassFormatError("{0} ({1})", Name, msg); - } - } - } - } - else - { - Dictionary<T, object> dict = new Dictionary<T, object>(); - for (int i = 0; i < members.Length; i++) - { - if (dict.ContainsKey(members[i])) - { - throw new ClassFormatError("{0} ({1})", Name, msg); - } - dict.Add(members[i], null); - } - } - } - - private void PatchConstantPool(object[] constantPoolPatches, string[] utf8_cp, string inputClassName) - { -#if !STATIC_COMPILER && !FIRST_PASS - for (int i = 0; i < constantPoolPatches.Length; i++) - { - if (constantPoolPatches[i] != null) - { - if (utf8_cp[i] != null) - { - if (!(constantPoolPatches[i] is string)) - { - throw new ClassFormatError("Illegal utf8 patch at {0} in class file {1}", i, inputClassName); - } - utf8_cp[i] = (string)constantPoolPatches[i]; - } - else if (constantpool[i] != null) - { - switch (constantpool[i].GetConstantType()) - { - case ConstantType.String: - constantpool[i] = new ConstantPoolItemLiveObject(constantPoolPatches[i]); - break; - case ConstantType.Class: - java.lang.Class clazz; - string name; - if ((clazz = constantPoolPatches[i] as java.lang.Class) != null) - { - TypeWrapper tw = TypeWrapper.FromClass(clazz); - constantpool[i] = new ConstantPoolItemClass(tw.Name, tw); - } - else if ((name = constantPoolPatches[i] as string) != null) - { - constantpool[i] = new ConstantPoolItemClass(String.Intern(name.Replace('/', '.')), null); - } - else - { - throw new ClassFormatError("Illegal class patch at {0} in class file {1}", i, inputClassName); - } - break; - case ConstantType.Integer: - ((ConstantPoolItemInteger)constantpool[i]).v = ((java.lang.Integer)constantPoolPatches[i]).intValue(); - break; - case ConstantType.Long: - ((ConstantPoolItemLong)constantpool[i]).l = ((java.lang.Long)constantPoolPatches[i]).longValue(); - break; - case ConstantType.Float: - ((ConstantPoolItemFloat)constantpool[i]).v = ((java.lang.Float)constantPoolPatches[i]).floatValue(); - break; - case ConstantType.Double: - ((ConstantPoolItemDouble)constantpool[i]).d = ((java.lang.Double)constantPoolPatches[i]).doubleValue(); - break; - default: - throw new NotImplementedException("ConstantPoolPatch: " + constantPoolPatches[i]); - } - } - } - } -#endif - } - - private void MarkLinkRequiredConstantPoolItem(int index) - { - if (index > 0 && index < constantpool.Length && constantpool[index] != null) - { - constantpool[index].MarkLinkRequired(); - } - } - - private static BootstrapMethod[] ReadBootstrapMethods(BigEndianBinaryReader br, ClassFile classFile) - { - BigEndianBinaryReader rdr = br.Section(br.ReadUInt32()); - ushort count = rdr.ReadUInt16(); - BootstrapMethod[] bsm = new BootstrapMethod[count]; - for(int i = 0; i < bsm.Length; i++) - { - ushort bsm_index = rdr.ReadUInt16(); - if(bsm_index >= classFile.constantpool.Length || !(classFile.constantpool[bsm_index] is ConstantPoolItemMethodHandle)) - { - throw new ClassFormatError("bootstrap_method_index {0} has bad constant type in class file {1}", bsm_index, classFile.Name); - } - classFile.MarkLinkRequiredConstantPoolItem(bsm_index); - ushort argument_count = rdr.ReadUInt16(); - ushort[] args = new ushort[argument_count]; - for(int j = 0; j < args.Length; j++) - { - ushort argument_index = rdr.ReadUInt16(); - if(!classFile.IsValidConstant(argument_index)) - { - throw new ClassFormatError("argument_index {0} has bad constant type in class file {1}", argument_index, classFile.Name); - } - classFile.MarkLinkRequiredConstantPoolItem(argument_index); - args[j] = argument_index; - } - bsm[i] = new BootstrapMethod(bsm_index, args); - } - if(!rdr.IsAtEnd) - { - throw new ClassFormatError("Bad length on BootstrapMethods in class file {0}", classFile.Name); - } - return bsm; - } - - private bool IsValidConstant(ushort index) - { - if(index < constantpool.Length && constantpool[index] != null) - { - try - { - constantpool[index].GetConstantType(); - return true; - } - catch (InvalidOperationException) { } - } - return false; - } - - private static object[] ReadAnnotations(BigEndianBinaryReader br, ClassFile classFile, string[] utf8_cp) - { - BigEndianBinaryReader rdr = br.Section(br.ReadUInt32()); - ushort num_annotations = rdr.ReadUInt16(); - object[] annotations = new object[num_annotations]; - for(int i = 0; i < annotations.Length; i++) - { - annotations[i] = ReadAnnotation(rdr, classFile, utf8_cp); - } - if(!rdr.IsAtEnd) - { - throw new ClassFormatError("{0} (RuntimeVisibleAnnotations attribute has wrong length)", classFile.Name); - } - return annotations; - } - - private static object ReadAnnotation(BigEndianBinaryReader rdr, ClassFile classFile, string[] utf8_cp) - { - string type = classFile.GetConstantPoolUtf8String(utf8_cp, rdr.ReadUInt16()); - ushort num_element_value_pairs = rdr.ReadUInt16(); - object[] annot = new object[2 + num_element_value_pairs * 2]; - annot[0] = AnnotationDefaultAttribute.TAG_ANNOTATION; - annot[1] = type; - for(int i = 0; i < num_element_value_pairs; i++) - { - annot[2 + i * 2 + 0] = classFile.GetConstantPoolUtf8String(utf8_cp, rdr.ReadUInt16()); - annot[2 + i * 2 + 1] = ReadAnnotationElementValue(rdr, classFile, utf8_cp); - } - return annot; - } - - private static object ReadAnnotationElementValue(BigEndianBinaryReader rdr, ClassFile classFile, string[] utf8_cp) - { - try - { - byte tag = rdr.ReadByte(); - switch (tag) - { - case (byte)'Z': - return classFile.GetConstantPoolConstantInteger(rdr.ReadUInt16()) != 0; - case (byte)'B': - return (byte)classFile.GetConstantPoolConstantInteger(rdr.ReadUInt16()); - case (byte)'C': - return (char)classFile.GetConstantPoolConstantInteger(rdr.ReadUInt16()); - case (byte)'S': - return (short)classFile.GetConstantPoolConstantInteger(rdr.ReadUInt16()); - case (byte)'I': - return classFile.GetConstantPoolConstantInteger(rdr.ReadUInt16()); - case (byte)'F': - return classFile.GetConstantPoolConstantFloat(rdr.ReadUInt16()); - case (byte)'J': - return classFile.GetConstantPoolConstantLong(rdr.ReadUInt16()); - case (byte)'D': - return classFile.GetConstantPoolConstantDouble(rdr.ReadUInt16()); - case (byte)'s': - return classFile.GetConstantPoolUtf8String(utf8_cp, rdr.ReadUInt16()); - case (byte)'e': - { - ushort type_name_index = rdr.ReadUInt16(); - ushort const_name_index = rdr.ReadUInt16(); - return new object[] { - AnnotationDefaultAttribute.TAG_ENUM, - classFile.GetConstantPoolUtf8String(utf8_cp, type_name_index), - classFile.GetConstantPoolUtf8String(utf8_cp, const_name_index) - }; - } - case (byte)'c': - return new object[] { - AnnotationDefaultAttribute.TAG_CLASS, - classFile.GetConstantPoolUtf8String(utf8_cp, rdr.ReadUInt16()) - }; - case (byte)'@': - return ReadAnnotation(rdr, classFile, utf8_cp); - case (byte)'[': - { - ushort num_values = rdr.ReadUInt16(); - object[] array = new object[num_values + 1]; - array[0] = AnnotationDefaultAttribute.TAG_ARRAY; - for (int i = 0; i < num_values; i++) - { - array[i + 1] = ReadAnnotationElementValue(rdr, classFile, utf8_cp); - } - return array; - } - default: - throw new ClassFormatError("Invalid tag {0} in annotation element_value", tag); - } - } - catch (NullReferenceException) - { - } - catch (InvalidCastException) - { - } - catch (IndexOutOfRangeException) - { - } - return new object[] { AnnotationDefaultAttribute.TAG_ERROR, "java.lang.IllegalArgumentException", "Wrong type at constant pool index" }; - } - - private void ValidateConstantPoolItemClass(string classFile, ushort index) - { - if(index >= constantpool.Length || !(constantpool[index] is ConstantPoolItemClass)) - { - throw new ClassFormatError("{0} (Bad constant pool index #{1})", classFile, index); - } - } - - private static bool IsValidMethodName(string name, int majorVersion) - { - if(name.Length == 0) - { - return false; - } - for(int i = 0; i < name.Length; i++) - { - if(".;[/<>".IndexOf(name[i]) != -1) - { - return false; - } - } - return majorVersion >= 49 || IsValidPre49Identifier(name); - } - - private static bool IsValidFieldName(string name, int majorVersion) - { - if(name.Length == 0) - { - return false; - } - for(int i = 0; i < name.Length; i++) - { - if(".;[/".IndexOf(name[i]) != -1) - { - return false; - } - } - return majorVersion >= 49 || IsValidPre49Identifier(name); - } - - private static bool IsValidPre49Identifier(string name) - { - if(!Char.IsLetter(name[0]) && "$_".IndexOf(name[0]) == -1) - { - return false; - } - for(int i = 1; i < name.Length; i++) - { - if(!Char.IsLetterOrDigit(name[i]) && "$_".IndexOf(name[i]) == -1) - { - return false; - } - } - return true; - } - - internal static bool IsValidFieldSig(string sig) - { - return IsValidFieldSigImpl(sig, 0, sig.Length); - } - - private static bool IsValidFieldSigImpl(string sig, int start, int end) - { - if(start >= end) - { - return false; - } - switch(sig[start]) - { - case 'L': - return sig.IndexOf(';', start + 1) == end - 1; - case '[': - while(sig[start] == '[') - { - start++; - if(start == end) - { - return false; - } - } - return IsValidFieldSigImpl(sig, start, end); - case 'B': - case 'Z': - case 'C': - case 'S': - case 'I': - case 'J': - case 'F': - case 'D': - return start == end - 1; - default: - return false; - } - } - - internal static bool IsValidMethodSig(string sig) - { - if(sig.Length < 3 || sig[0] != '(') - { - return false; - } - int end = sig.IndexOf(')'); - if(end == -1) - { - return false; - } - if(!sig.EndsWith(")V") && !IsValidFieldSigImpl(sig, end + 1, sig.Length)) - { - return false; - } - for(int i = 1; i < end; i++) - { - switch(sig[i]) - { - case 'B': - case 'Z': - case 'C': - case 'S': - case 'I': - case 'J': - case 'F': - case 'D': - break; - case 'L': - i = sig.IndexOf(';', i); - break; - case '[': - while(sig[i] == '[') - { - i++; - } - if("BZCSIJFDL".IndexOf(sig[i]) == -1) - { - return false; - } - if(sig[i] == 'L') - { - i = sig.IndexOf(';', i); - } - break; - default: - return false; - } - if(i == -1 || i >= end) - { - return false; - } - } - return true; - } - - internal int MajorVersion - { - get - { - return flags & FLAG_MASK_MAJORVERSION; - } - } - - internal void Link(TypeWrapper thisType) - { - // this is not just an optimization, it's required for anonymous classes to be able to refer to themselves - ((ConstantPoolItemClass)constantpool[this_class]).LinkSelf(thisType); - for(int i = 1; i < constantpool.Length; i++) - { - if(constantpool[i] != null) - { - constantpool[i].Link(thisType); - } - } - } - - internal Modifiers Modifiers - { - get - { - return access_flags; - } - } - - internal bool IsAbstract - { - get - { - // interfaces are implicitly abstract - return (access_flags & (Modifiers.Abstract | Modifiers.Interface)) != 0; - } - } - - internal bool IsFinal - { - get - { - return (access_flags & Modifiers.Final) != 0; - } - } - - internal bool IsPublic - { - get - { - return (access_flags & Modifiers.Public) != 0; - } - } - - internal bool IsInterface - { - get - { - return (access_flags & Modifiers.Interface) != 0; - } - } - - internal bool IsEnum - { - get - { - return (access_flags & Modifiers.Enum) != 0; - } - } - - internal bool IsAnnotation - { - get - { - return (access_flags & Modifiers.Annotation) != 0; - } - } - - internal bool IsSuper - { - get - { - return (access_flags & Modifiers.Super) != 0; - } - } - - internal void RemoveUnusedFields() - { - List<Field> list = new List<Field>(); - foreach(Field f in fields) - { - if(f.IsPrivate && f.IsStatic && f.Name != "serialVersionUID" && !IsReferenced(f)) - { - // unused, so we skip it - Tracer.Info(Tracer.Compiler, "Unused field {0}::{1}", this.Name, f.Name); - } - else - { - list.Add(f); - } - } - fields = list.ToArray(); - } - - private bool IsReferenced(Field fld) - { - foreach(ConstantPoolItem cpi in constantpool) - { - ConstantPoolItemFieldref fieldref = cpi as ConstantPoolItemFieldref; - if(fieldref != null && - fieldref.Class == this.Name && - fieldref.Name == fld.Name && - fieldref.Signature == fld.Signature) - { - return true; - } - } - return false; - } - - internal ConstantPoolItemFieldref GetFieldref(int index) - { - return (ConstantPoolItemFieldref)constantpool[index]; - } - - // this won't throw an exception if index is invalid - // (used by IsSideEffectFreeStaticInitializer) - internal ConstantPoolItemFieldref SafeGetFieldref(int index) - { - if(index > 0 && index < constantpool.Length) - { - return constantpool[index] as ConstantPoolItemFieldref; - } - return null; - } - - // NOTE this returns an MI, because it used for both normal methods and interface methods - internal ConstantPoolItemMI GetMethodref(int index) - { - return (ConstantPoolItemMI)constantpool[index]; - } - - // this won't throw an exception if index is invalid - // (used by IsAccessBridge) - internal ConstantPoolItemMI SafeGetMethodref(int index) - { - if (index > 0 && index < constantpool.Length) - { - return constantpool[index] as ConstantPoolItemMI; - } - return null; - } - - internal ConstantPoolItemInvokeDynamic GetInvokeDynamic(int index) - { - return (ConstantPoolItemInvokeDynamic)constantpool[index]; - } - - private ConstantPoolItem GetConstantPoolItem(int index) - { - return constantpool[index]; - } - - internal string GetConstantPoolClass(int index) - { - return ((ConstantPoolItemClass)constantpool[index]).Name; - } - - private bool SafeIsConstantPoolClass(int index) - { - if(index > 0 && index < constantpool.Length) - { - return constantpool[index] as ConstantPoolItemClass != null; - } - return false; - } - - internal TypeWrapper GetConstantPoolClassType(int index) - { - return ((ConstantPoolItemClass)constantpool[index]).GetClassType(); - } - - private string GetConstantPoolUtf8String(string[] utf8_cp, int index) - { - string s = utf8_cp[index]; - if(s == null) - { - if(this_class == 0) - { - throw new ClassFormatError("Bad constant pool index #{0}", index); - } - else - { - throw new ClassFormatError("{0} (Bad constant pool index #{1})", this.Name, index); - } - } - return s; - } - - internal ConstantType GetConstantPoolConstantType(int index) - { - return constantpool[index].GetConstantType(); - } - - internal double GetConstantPoolConstantDouble(int index) - { - return ((ConstantPoolItemDouble)constantpool[index]).Value; - } - - internal float GetConstantPoolConstantFloat(int index) - { - return ((ConstantPoolItemFloat)constantpool[index]).Value; - } - - internal int GetConstantPoolConstantInteger(int index) - { - return ((ConstantPoolItemInteger)constantpool[index]).Value; - } - - internal long GetConstantPoolConstantLong(int index) - { - return ((ConstantPoolItemLong)constantpool[index]).Value; - } - - internal string GetConstantPoolConstantString(int index) - { - return ((ConstantPoolItemString)constantpool[index]).Value; - } - - internal ConstantPoolItemMethodHandle GetConstantPoolConstantMethodHandle(int index) - { - return (ConstantPoolItemMethodHandle)constantpool[index]; - } - - internal ConstantPoolItemMethodType GetConstantPoolConstantMethodType(int index) - { - return (ConstantPoolItemMethodType)constantpool[index]; - } - - internal object GetConstantPoolConstantLiveObject(int index) - { - return ((ConstantPoolItemLiveObject)constantpool[index]).Value; - } - - internal string Name - { - get - { - return GetConstantPoolClass(this_class); - } - } - - internal ConstantPoolItemClass SuperClass - { - get - { - return (ConstantPoolItemClass)constantpool[super_class]; - } - } - - internal Field[] Fields - { - get - { - return fields; - } - } - - internal Method[] Methods - { - get - { - return methods; - } - } - - internal ConstantPoolItemClass[] Interfaces - { - get - { - return interfaces; - } - } - - internal string SourceFileAttribute - { - get - { - return sourceFile; - } - } - - internal string SourcePath - { -#if STATIC_COMPILER - get { return sourcePath; } - set { sourcePath = value; } -#else - get { return sourceFile; } -#endif - } - - internal object[] Annotations - { - get - { - return annotations; - } - } - - internal string GenericSignature - { - get - { - return signature; - } - } - - internal string[] EnclosingMethod - { - get - { - return enclosingMethod; - } - } - - internal byte[] RuntimeVisibleTypeAnnotations - { - get - { - return runtimeVisibleTypeAnnotations; - } - } - - internal object[] GetConstantPool() - { - object[] cp = new object[constantpool.Length]; - for (int i = 1; i < cp.Length; i++) - { - if (constantpool[i] != null) - { - cp[i] = constantpool[i].GetRuntimeValue(); - } - } - return cp; - } - - internal string IKVMAssemblyAttribute - { - get - { - return ikvmAssembly; - } - } - - internal bool DeprecatedAttribute - { - get - { - return (flags & FLAG_MASK_DEPRECATED) != 0; - } - } - - internal bool IsInternal - { - get - { - return (flags & FLAG_MASK_INTERNAL) != 0; - } - } - - // for use by ikvmc (to implement the -privatepackage option) - internal void SetInternal() - { - access_flags &= ~Modifiers.AccessMask; - flags |= FLAG_MASK_INTERNAL; - } - - internal bool HasInitializedFields - { - get - { - foreach (Field f in fields) - { - if (f.IsStatic && !f.IsFinal && f.ConstantValue != null) - { - return true; - } - } - return false; - } - } - - internal BootstrapMethod GetBootstrapMethod(int index) - { - return bootstrapMethods[index]; - } - - internal struct BootstrapMethod - { - private ushort bsm_index; - private ushort[] args; - - internal BootstrapMethod(ushort bsm_index, ushort[] args) - { - this.bsm_index = bsm_index; - this.args = args; - } - - internal int BootstrapMethodIndex - { - get { return bsm_index; } - } - - internal int ArgumentCount - { - get { return args.Length; } - } - - internal int GetArgument(int index) - { - return args[index]; - } - } - - internal struct InnerClass - { - internal ushort innerClass; // ConstantPoolItemClass - internal ushort outerClass; // ConstantPoolItemClass - internal ushort name; // ConstantPoolItemUtf8 - internal Modifiers accessFlags; - } - - internal InnerClass[] InnerClasses - { - get - { - return innerClasses; - } - } - - internal enum RefKind - { - getField = 1, - getStatic = 2, - putField = 3, - putStatic = 4, - invokeVirtual = 5, - invokeStatic = 6, - invokeSpecial = 7, - newInvokeSpecial = 8, - invokeInterface = 9 - } - - internal enum ConstantType - { - Integer, - Long, - Float, - Double, - String, - Class, - MethodHandle, - MethodType, - LiveObject, // used by anonymous class constant pool patching - } - - internal abstract class ConstantPoolItem - { - internal virtual void Resolve(ClassFile classFile, string[] utf8_cp, ClassFileParseOptions options) - { - } - - internal virtual void Link(TypeWrapper thisType) - { - } - - internal virtual ConstantType GetConstantType() - { - throw new InvalidOperationException(); - } - - internal virtual void MarkLinkRequired() - { - } - - // this is used for sun.reflect.ConstantPool - // it returns a boxed System.Int32, System.Int64, System.Float, System.Double or a string - internal virtual object GetRuntimeValue() - { - return null; - } - } - - internal sealed class ConstantPoolItemClass : ConstantPoolItem, IEquatable<ConstantPoolItemClass> - { - private ushort name_index; - private string name; - private TypeWrapper typeWrapper; - private static char[] invalidJava15Characters = { '.', ';', '[', ']' }; - - internal ConstantPoolItemClass(BigEndianBinaryReader br) - { - name_index = br.ReadUInt16(); - } - - internal ConstantPoolItemClass(string name, TypeWrapper typeWrapper) - { - this.name = name; - this.typeWrapper = typeWrapper; - } - - internal override void Resolve(ClassFile classFile, string[] utf8_cp, ClassFileParseOptions options) - { - // if the item was patched, we already have a name - if(name != null) - { - return; - } - name = classFile.GetConstantPoolUtf8String(utf8_cp, name_index); - if(name.Length > 0) - { - // We don't enforce the strict class name rules in the static compiler, since HotSpot doesn't enforce *any* rules on - // class names for the system (and boot) class loader. We still need to enforce the 1.5 restrictions, because we - // rely on those invariants. -#if !STATIC_COMPILER - if(classFile.MajorVersion < 49 && (options & ClassFileParseOptions.RelaxedClassNameValidation) == 0) - { - char prev = name[0]; - if(Char.IsLetter(prev) || prev == '$' || prev == '_' || prev == '[' || prev == '/') - { - int skip = 1; - int end = name.Length; - if(prev == '[') - { - if(!IsValidFieldSig(name)) - { - goto barf; - } - while(name[skip] == '[') - { - skip++; - } - if(name.EndsWith(";")) - { - end--; - } - } - for(int i = skip; i < end; i++) - { - char c = name[i]; - if(!Char.IsLetterOrDigit(c) && c != '$' && c != '_' && (c != '/' || prev == '/')) - { - goto barf; - } - prev = c; - } - name = String.Intern(name.Replace('/', '.')); - return; - } - } - else -#endif - { - // since 1.5 the restrictions on class names have been greatly reduced - int start = 0; - int end = name.Length; - if(name[0] == '[') - { - if(!IsValidFieldSig(name)) - { - goto barf; - } - // the semicolon is only allowed at the end and IsValidFieldSig enforces this, - // but since invalidJava15Characters contains the semicolon, we decrement end - // to make the following check against invalidJava15Characters ignore the - // trailing semicolon. - if(name[end - 1] == ';') - { - end--; - } - while(name[start] == '[') - { - start++; - } - } - if(name.IndexOfAny(invalidJava15Characters, start, end - start) >= 0) - { - goto barf; - } - name = String.Intern(name.Replace('/', '.')); - return; - } - } - barf: - throw new ClassFormatError("Invalid class name \"{0}\"", name); - } - - internal override void MarkLinkRequired() - { - if(typeWrapper == null) - { - typeWrapper = VerifierTypeWrapper.Null; - } - } - - internal void LinkSelf(TypeWrapper thisType) - { - this.typeWrapper = thisType; - } - - internal override void Link(TypeWrapper thisType) - { - if(typeWrapper == VerifierTypeWrapper.Null) - { - TypeWrapper tw = ClassLoaderWrapper.LoadClassNoThrow(thisType.GetClassLoader(), name, true); -#if !STATIC_COMPILER && !FIRST_PASS - if(!tw.IsUnloadable) - { - try - { - thisType.GetClassLoader().CheckPackageAccess(tw, thisType.ClassObject.pd); - } - catch(java.lang.SecurityException) - { - tw = new UnloadableTypeWrapper(name); - } - } -#endif - typeWrapper = tw; - } - } - - internal string Name - { - get - { - return name; - } - } - - internal TypeWrapper GetClassType() - { - return typeWrapper; - } - - internal override ConstantType GetConstantType() - { - return ConstantType.Class; - } - - public sealed override int GetHashCode() - { - return name.GetHashCode(); - } - - public bool Equals(ConstantPoolItemClass other) - { - return ReferenceEquals(name, other.name); - } - } - - private sealed class ConstantPoolItemDouble : ConstantPoolItem - { - internal double d; - - internal ConstantPoolItemDouble(BigEndianBinaryReader br) - { - d = br.ReadDouble(); - } - - internal override ConstantType GetConstantType() - { - return ConstantType.Double; - } - - internal double Value - { - get - { - return d; - } - } - - internal override object GetRuntimeValue() - { - return d; - } - } - - internal abstract class ConstantPoolItemFMI : ConstantPoolItem - { - private ushort class_index; - private ushort name_and_type_index; - private ConstantPoolItemClass clazz; - private string name; - private string descriptor; - - internal ConstantPoolItemFMI(BigEndianBinaryReader br) - { - class_index = br.ReadUInt16(); - name_and_type_index = br.ReadUInt16(); - } - - internal override void Resolve(ClassFile classFile, string[] utf8_cp, ClassFileParseOptions options) - { - ConstantPoolItemNameAndType name_and_type = (ConstantPoolItemNameAndType)classFile.GetConstantPoolItem(name_and_type_index); - clazz = (ConstantPoolItemClass)classFile.GetConstantPoolItem(class_index); - // if the constant pool items referred to were strings, GetConstantPoolItem returns null - if(name_and_type == null || clazz == null) - { - throw new ClassFormatError("Bad index in constant pool"); - } - name = String.Intern(classFile.GetConstantPoolUtf8String(utf8_cp, name_and_type.name_index)); - descriptor = classFile.GetConstantPoolUtf8String(utf8_cp, name_and_type.descriptor_index); - Validate(name, descriptor, classFile.MajorVersion); - descriptor = String.Intern(descriptor.Replace('/', '.')); - } - - protected abstract void Validate(string name, string descriptor, int majorVersion); - - internal override void MarkLinkRequired() - { - clazz.MarkLinkRequired(); - } - - internal override void Link(TypeWrapper thisType) - { - clazz.Link(thisType); - } - - internal string Name - { - get - { - return name; - } - } - - internal string Signature - { - get - { - return descriptor; - } - } - - internal string Class - { - get - { - return clazz.Name; - } - } - - internal TypeWrapper GetClassType() - { - return clazz.GetClassType(); - } - - internal abstract MemberWrapper GetMember(); - } - - internal sealed class ConstantPoolItemFieldref : ConstantPoolItemFMI - { - private FieldWrapper field; - private TypeWrapper fieldTypeWrapper; - - internal ConstantPoolItemFieldref(BigEndianBinaryReader br) : base(br) - { - } - - protected override void Validate(string name, string descriptor, int majorVersion) - { - if(!IsValidFieldSig(descriptor)) - { - throw new ClassFormatError("Invalid field signature \"{0}\"", descriptor); - } - if(!IsValidFieldName(name, majorVersion)) - { - throw new ClassFormatError("Invalid field name \"{0}\"", name); - } - } - - internal TypeWrapper GetFieldType() - { - return fieldTypeWrapper; - } - - internal override void Link(TypeWrapper thisType) - { - base.Link(thisType); - lock(this) - { - if(fieldTypeWrapper != null) - { - return; - } - } - FieldWrapper fw = null; - TypeWrapper wrapper = GetClassType(); - if(wrapper == null) - { - return; - } - if(!wrapper.IsUnloadable) - { - fw = wrapper.GetFieldWrapper(Name, Signature); - if(fw != null) - { - fw.Link(); - } - } - ClassLoaderWrapper classLoader = thisType.GetClassLoader(); - TypeWrapper fld = classLoader.FieldTypeWrapperFromSigNoThrow(this.Signature); - lock(this) - { - if(fieldTypeWrapper == null) - { - fieldTypeWrapper = fld; - field = fw; - } - } - } - - internal FieldWrapper GetField() - { - return field; - } - - internal override MemberWrapper GetMember() - { - return field; - } - } - - internal class ConstantPoolItemMI : ConstantPoolItemFMI - { - private TypeWrapper[] argTypeWrappers; - private TypeWrapper retTypeWrapper; - protected MethodWrapper method; - protected MethodWrapper invokespecialMethod; - - internal ConstantPoolItemMI(BigEndianBinaryReader br) : base(br) - { - } - - protected override void Validate(string name, string descriptor, int majorVersion) - { - if(!IsValidMethodSig(descriptor)) - { - throw new ClassFormatError("Method {0} has invalid signature {1}", name, descriptor); - } - if(!IsValidMethodName(name, majorVersion)) - { - if(!ReferenceEquals(name, StringConstants.INIT)) - { - throw new ClassFormatError("Invalid method name \"{0}\"", name); - } - if(!descriptor.EndsWith("V")) - { - throw new ClassFormatError("Method {0} has invalid signature {1}", name, descriptor); - } - } - } - - internal override void Link(TypeWrapper thisType) - { - base.Link(thisType); - lock(this) - { - if(argTypeWrappers != null) - { - return; - } - } - ClassLoaderWrapper classLoader = thisType.GetClassLoader(); - TypeWrapper[] args = classLoader.ArgTypeWrapperListFromSigNoThrow(this.Signature); - TypeWrapper ret = classLoader.RetTypeWrapperFromSigNoThrow(this.Signature); - lock(this) - { - if(argTypeWrappers == null) - { - argTypeWrappers = args; - retTypeWrapper = ret; - } - } - } - - internal TypeWrapper[] GetArgTypes() - { - return argTypeWrappers; - } - - internal TypeWrapper GetRetType() - { - return retTypeWrapper; - } - - internal MethodWrapper GetMethod() - { - return method; - } - - internal MethodWrapper GetMethodForInvokespecial() - { - return invokespecialMethod != null ? invokespecialMethod : method; - } - - internal override MemberWrapper GetMember() - { - return method; - } - } - - internal sealed class ConstantPoolItemMethodref : ConstantPoolItemMI - { - internal ConstantPoolItemMethodref(BigEndianBinaryReader br) : base(br) - { - } - - internal override void Link(TypeWrapper thisType) - { - base.Link(thisType); - TypeWrapper wrapper = GetClassType(); - if(wrapper != null && !wrapper.IsUnloadable) - { - method = wrapper.GetMethodWrapper(Name, Signature, !ReferenceEquals(Name, StringConstants.INIT)); - if(method != null) - { - method.Link(); - } - if(Name != StringConstants.INIT - && !thisType.IsInterface - && (!JVM.AllowNonVirtualCalls || (thisType.Modifiers & Modifiers.Super) == Modifiers.Super) - && thisType != wrapper - && thisType.IsSubTypeOf(wrapper)) - { - invokespecialMethod = thisType.BaseTypeWrapper.GetMethodWrapper(Name, Signature, true); - if(invokespecialMethod != null) - { - invokespecialMethod.Link(); - } - } - } - } - } - - internal sealed class ConstantPoolItemInterfaceMethodref : ConstantPoolItemMI - { - internal ConstantPoolItemInterfaceMethodref(BigEndianBinaryReader br) : base(br) - { - } - - private static MethodWrapper GetInterfaceMethod(TypeWrapper wrapper, string name, string sig) - { - if(wrapper.IsUnloadable) - { - return null; - } - MethodWrapper method = wrapper.GetMethodWrapper(name, sig, false); - if(method != null) - { - return method; - } - TypeWrapper[] interfaces = wrapper.Interfaces; - for(int i = 0; i < interfaces.Length; i++) - { - method = GetInterfaceMethod(interfaces[i], name, sig); - if(method != null) - { - return method; - } - } - return null; - } - - internal override void Link(TypeWrapper thisType) - { - base.Link(thisType); - TypeWrapper wrapper = GetClassType(); - if(wrapper != null) - { - method = GetInterfaceMethod(wrapper, Name, Signature); - if(method == null) - { - // NOTE vmspec 5.4.3.4 clearly states that an interfacemethod may also refer to a method in Object - method = CoreClasses.java.lang.Object.Wrapper.GetMethodWrapper(Name, Signature, false); - } - if(method != null) - { - method.Link(); - } - } - } - } - - private sealed class ConstantPoolItemFloat : ConstantPoolItem - { - internal float v; - - internal ConstantPoolItemFloat(BigEndianBinaryReader br) - { - v = br.ReadSingle(); - } - - internal override ConstantType GetConstantType() - { - return ConstantType.Float; - } - - internal float Value - { - get - { - return v; - } - } - - internal override object GetRuntimeValue() - { - return v; - } - } - - private sealed class ConstantPoolItemInteger : ConstantPoolItem - { - internal int v; - - internal ConstantPoolItemInteger(BigEndianBinaryReader br) - { - v = br.ReadInt32(); - } - - internal override ConstantType GetConstantType() - { - return ConstantType.Integer; - } - - internal int Value - { - get - { - return v; - } - } - - internal override object GetRuntimeValue() - { - return v; - } - } - - private sealed class ConstantPoolItemLong : ConstantPoolItem - { - internal long l; - - internal ConstantPoolItemLong(BigEndianBinaryReader br) - { - l = br.ReadInt64(); - } - - internal override ConstantType GetConstantType() - { - return ConstantType.Long; - } - - internal long Value - { - get - { - return l; - } - } - - internal override object GetRuntimeValue() - { - return l; - } - } - - private sealed class ConstantPoolItemNameAndType : ConstantPoolItem - { - internal ushort name_index; - internal ushort descriptor_index; - - internal ConstantPoolItemNameAndType(BigEndianBinaryReader br) - { - name_index = br.ReadUInt16(); - descriptor_index = br.ReadUInt16(); - } - - internal override void Resolve(ClassFile classFile, string[] utf8_cp, ClassFileParseOptions options) - { - if(classFile.GetConstantPoolUtf8String(utf8_cp, name_index) == null - || classFile.GetConstantPoolUtf8String(utf8_cp, descriptor_index) == null) - { - throw new ClassFormatError("Illegal constant pool index"); - } - } - } - - internal sealed class ConstantPoolItemMethodHandle : ConstantPoolItem - { - private byte ref_kind; - private ushort method_index; - private ConstantPoolItemFMI cpi; - - internal ConstantPoolItemMethodHandle(BigEndianBinaryReader br) - { - ref_kind = br.ReadByte(); - method_index = br.ReadUInt16(); - } - - internal override void Resolve(ClassFile classFile, string[] utf8_cp, ClassFileParseOptions options) - { - switch ((RefKind)ref_kind) - { - case RefKind.getField: - case RefKind.getStatic: - case RefKind.putField: - case RefKind.putStatic: - cpi = classFile.GetConstantPoolItem(method_index) as ConstantPoolItemFieldref; - break; - case RefKind.invokeSpecial: - case RefKind.invokeVirtual: - case RefKind.invokeStatic: - case RefKind.newInvokeSpecial: - cpi = classFile.GetConstantPoolItem(method_index) as ConstantPoolItemMethodref; - if (cpi == null && classFile.MajorVersion >= 52 && ((RefKind)ref_kind == RefKind.invokeStatic || (RefKind)ref_kind == RefKind.invokeSpecial)) - goto case RefKind.invokeInterface; - break; - case RefKind.invokeInterface: - cpi = classFile.GetConstantPoolItem(method_index) as ConstantPoolItemInterfaceMethodref; - break; - } - if (cpi == null) - { - throw new ClassFormatError("Invalid constant pool item MethodHandle"); - } - if (ReferenceEquals(cpi.Name, StringConstants.INIT) && Kind != RefKind.newInvokeSpecial) - { - throw new ClassFormatError("Bad method name"); - } - } - - internal override void MarkLinkRequired() - { - cpi.MarkLinkRequired(); - } - - internal string Class - { - get { return cpi.Class; } - } - - internal string Name - { - get { return cpi.Name; } - } - - internal string Signature - { - get { return cpi.Signature; } - } - - internal ConstantPoolItemFMI MemberConstantPoolItem - { - get { return cpi; } - } - - internal RefKind Kind - { - get { return (RefKind)ref_kind; } - } - - internal MemberWrapper Member - { - get { return cpi.GetMember(); } - } - - internal TypeWrapper GetClassType() - { - return cpi.GetClassType(); - } - - internal override void Link(TypeWrapper thisType) - { - cpi.Link(thisType); - } - - internal override ConstantType GetConstantType() - { - return ConstantType.MethodHandle; - } - } - - internal sealed class ConstantPoolItemMethodType : ConstantPoolItem - { - private ushort signature_index; - private string descriptor; - private TypeWrapper[] argTypeWrappers; - private TypeWrapper retTypeWrapper; - - internal ConstantPoolItemMethodType(BigEndianBinaryReader br) - { - signature_index = br.ReadUInt16(); - } - - internal override void Resolve(ClassFile classFile, string[] utf8_cp, ClassFileParseOptions options) - { - string descriptor = classFile.GetConstantPoolUtf8String(utf8_cp, signature_index); - if (descriptor == null || !IsValidMethodSig(descriptor)) - { - throw new ClassFormatError("Invalid MethodType signature"); - } - this.descriptor = String.Intern(descriptor.Replace('/', '.')); - } - - internal override void Link(TypeWrapper thisType) - { - lock (this) - { - if (argTypeWrappers != null) - { - return; - } - } - ClassLoaderWrapper classLoader = thisType.GetClassLoader(); - TypeWrapper[] args = classLoader.ArgTypeWrapperListFromSigNoThrow(descriptor); - TypeWrapper ret = classLoader.RetTypeWrapperFromSigNoThrow(descriptor); - lock (this) - { - if (argTypeWrappers == null) - { - argTypeWrappers = args; - retTypeWrapper = ret; - } - } - } - - internal string Signature - { - get { return descriptor; } - } - - internal TypeWrapper[] GetArgTypes() - { - return argTypeWrappers; - } - - internal TypeWrapper GetRetType() - { - return retTypeWrapper; - } - - internal override ConstantType GetConstantType() - { - return ConstantType.MethodType; - } - } - - internal sealed class ConstantPoolItemInvokeDynamic : ConstantPoolItem - { - private ushort bootstrap_specifier_index; - private ushort name_and_type_index; - private string name; - private string descriptor; - private TypeWrapper[] argTypeWrappers; - private TypeWrapper retTypeWrapper; - - internal ConstantPoolItemInvokeDynamic(BigEndianBinaryReader br) - { - bootstrap_specifier_index = br.ReadUInt16(); - name_and_type_index = br.ReadUInt16(); - } - - internal override void Resolve(ClassFile classFile, string[] utf8_cp, ClassFileParseOptions options) - { - ConstantPoolItemNameAndType name_and_type = (ConstantPoolItemNameAndType)classFile.GetConstantPoolItem(name_and_type_index); - // if the constant pool items referred to were strings, GetConstantPoolItem returns null - if (name_and_type == null) - { - throw new ClassFormatError("Bad index in constant pool"); - } - name = String.Intern(classFile.GetConstantPoolUtf8String(utf8_cp, name_and_type.name_index)); - descriptor = String.Intern(classFile.GetConstantPoolUtf8String(utf8_cp, name_and_type.descriptor_index).Replace('/', '.')); - } - - internal override void Link(TypeWrapper thisType) - { - lock (this) - { - if (argTypeWrappers != null) - { - return; - } - } - ClassLoaderWrapper classLoader = thisType.GetClassLoader(); - TypeWrapper[] args = classLoader.ArgTypeWrapperListFromSigNoThrow(descriptor); - TypeWrapper ret = classLoader.RetTypeWrapperFromSigNoThrow(descriptor); - lock (this) - { - if (argTypeWrappers == null) - { - argTypeWrappers = args; - retTypeWrapper = ret; - } - } - } - - internal TypeWrapper[] GetArgTypes() - { - return argTypeWrappers; - } - - internal TypeWrapper GetRetType() - { - return retTypeWrapper; - } - - internal string Name - { - get { return name; } - } - - internal ushort BootstrapMethod - { - get { return bootstrap_specifier_index; } - } - } - - private sealed class ConstantPoolItemString : ConstantPoolItem - { - private ushort string_index; - private string s; - - internal ConstantPoolItemString(BigEndianBinaryReader br) - { - string_index = br.ReadUInt16(); - } - - internal override void Resolve(ClassFile classFile, string[] utf8_cp, ClassFileParseOptions options) - { - s = classFile.GetConstantPoolUtf8String(utf8_cp, string_index); - } - - internal override ConstantType GetConstantType() - { - return ConstantType.String; - } - - internal string Value - { - get - { - return s; - } - } - } - - // this is only used to copy strings into "constantpool" when we see a RuntimeVisibleTypeAnnotations attribute, - // because we need a consistent way of exposing constant pool items to the runtime and that case - private sealed class ConstantPoolItemUtf8 : ConstantPoolItem - { - private readonly string str; - - internal ConstantPoolItemUtf8(string str) - { - this.str = str; - } - - internal override object GetRuntimeValue() - { - return str; - } - } - - private sealed class ConstantPoolItemLiveObject : ConstantPoolItem - { - internal readonly object Value; - - internal ConstantPoolItemLiveObject(object value) - { - this.Value = value; - } - - internal override ConstantType GetConstantType() - { - return ConstantType.LiveObject; - } - } - - internal enum Constant - { - Utf8 = 1, - Integer = 3, - Float = 4, - Long = 5, - Double = 6, - Class = 7, - String = 8, - Fieldref = 9, - Methodref = 10, - InterfaceMethodref = 11, - NameAndType = 12, - MethodHandle = 15, - MethodType = 16, - InvokeDynamic = 18, - } - - internal abstract class FieldOrMethod : IEquatable<FieldOrMethod> - { - // Note that Modifiers is a ushort, so it combines nicely with the following ushort field - protected Modifiers access_flags; - protected ushort flags; - private string name; - private string descriptor; - protected string signature; - protected object[] annotations; - protected byte[] runtimeVisibleTypeAnnotations; - - internal FieldOrMethod(ClassFile classFile, string[] utf8_cp, BigEndianBinaryReader br) - { - access_flags = (Modifiers)br.ReadUInt16(); - name = String.Intern(classFile.GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16())); - descriptor = classFile.GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16()); - ValidateSig(classFile, descriptor); - descriptor = String.Intern(descriptor.Replace('/', '.')); - } - - protected abstract void ValidateSig(ClassFile classFile, string descriptor); - - internal string Name - { - get - { - return name; - } - } - - internal string Signature - { - get - { - return descriptor; - } - } - - internal object[] Annotations - { - get - { - return annotations; - } - } - - internal string GenericSignature - { - get - { - return signature; - } - } - - internal Modifiers Modifiers - { - get - { - return (Modifiers)access_flags; - } - } - - internal bool IsAbstract - { - get - { - return (access_flags & Modifiers.Abstract) != 0; - } - } - - internal bool IsFinal - { - get - { - return (access_flags & Modifiers.Final) != 0; - } - } - - internal bool IsPublic - { - get - { - return (access_flags & Modifiers.Public) != 0; - } - } - - internal bool IsPrivate - { - get - { - return (access_flags & Modifiers.Private) != 0; - } - } - - internal bool IsProtected - { - get - { - return (access_flags & Modifiers.Protected) != 0; - } - } - - internal bool IsStatic - { - get - { - return (access_flags & Modifiers.Static) != 0; - } - } - - internal bool IsSynchronized - { - get - { - return (access_flags & Modifiers.Synchronized) != 0; - } - } - - internal bool IsVolatile - { - get - { - return (access_flags & Modifiers.Volatile) != 0; - } - } - - internal bool IsTransient - { - get - { - return (access_flags & Modifiers.Transient) != 0; - } - } - - internal bool IsNative - { - get - { - return (access_flags & Modifiers.Native) != 0; - } - } - - internal bool IsEnum - { - get - { - return (access_flags & Modifiers.Enum) != 0; - } - } - - internal bool DeprecatedAttribute - { - get - { - return (flags & FLAG_MASK_DEPRECATED) != 0; - } - } - - internal bool IsInternal - { - get - { - return (flags & FLAG_MASK_INTERNAL) != 0; - } - } - - internal byte[] RuntimeVisibleTypeAnnotations - { - get - { - return runtimeVisibleTypeAnnotations; - } - } - - public sealed override int GetHashCode() - { - return name.GetHashCode() ^ descriptor.GetHashCode(); - } - - public bool Equals(FieldOrMethod other) - { - return ReferenceEquals(name, other.name) && ReferenceEquals(descriptor, other.descriptor); - } - } - - internal sealed class Field : FieldOrMethod - { - private object constantValue; - private string[] propertyGetterSetter; - - internal Field(ClassFile classFile, string[] utf8_cp, BigEndianBinaryReader br) : base(classFile, utf8_cp, br) - { - if((IsPrivate && IsPublic) || (IsPrivate && IsProtected) || (IsPublic && IsProtected) - || (IsFinal && IsVolatile) - || (classFile.IsInterface && (!IsPublic || !IsStatic || !IsFinal || IsTransient))) - { - throw new ClassFormatError("{0} (Illegal field modifiers: 0x{1:X})", classFile.Name, access_flags); - } - int attributes_count = br.ReadUInt16(); - for(int i = 0; i < attributes_count; i++) - { - switch(classFile.GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16())) - { - case "Deprecated": - if(br.ReadUInt32() != 0) - { - throw new ClassFormatError("Invalid Deprecated attribute length"); - } - flags |= FLAG_MASK_DEPRECATED; - break; - case "ConstantValue": - { - if(br.ReadUInt32() != 2) - { - throw new ClassFormatError("Invalid ConstantValue attribute length"); - } - ushort index = br.ReadUInt16(); - try - { - switch(Signature) - { - case "I": - constantValue = classFile.GetConstantPoolConstantInteger(index); - break; - case "S": - constantValue = (short)classFile.GetConstantPoolConstantInteger(index); - break; - case "B": - constantValue = (byte)classFile.GetConstantPoolConstantInteger(index); - break; - case "C": - constantValue = (char)classFile.GetConstantPoolConstantInteger(index); - break; - case "Z": - constantValue = classFile.GetConstantPoolConstantInteger(index) != 0; - break; - case "J": - constantValue = classFile.GetConstantPoolConstantLong(index); - break; - case "F": - constantValue = classFile.GetConstantPoolConstantFloat(index); - break; - case "D": - constantValue = classFile.GetConstantPoolConstantDouble(index); - break; - case "Ljava.lang.String;": - constantValue = classFile.GetConstantPoolConstantString(index); - break; - default: - throw new ClassFormatError("{0} (Invalid signature for constant)", classFile.Name); - } - } - catch(InvalidCastException) - { - throw new ClassFormatError("{0} (Bad index into constant pool)", classFile.Name); - } - catch(IndexOutOfRangeException) - { - throw new ClassFormatError("{0} (Bad index into constant pool)", classFile.Name); - } - catch(InvalidOperationException) - { - throw new ClassFormatError("{0} (Bad index into constant pool)", classFile.Name); - } - catch(NullReferenceException) - { - throw new ClassFormatError("{0} (Bad index into constant pool)", classFile.Name); - } - break; - } - case "Signature": - if(classFile.MajorVersion < 49) - { - goto default; - } - if(br.ReadUInt32() != 2) - { - throw new ClassFormatError("Signature attribute has incorrect length"); - } - signature = classFile.GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16()); - break; - case "RuntimeVisibleAnnotations": - if(classFile.MajorVersion < 49) - { - goto default; - } - annotations = ReadAnnotations(br, classFile, utf8_cp); - break; - case "RuntimeInvisibleAnnotations": - if(classFile.MajorVersion < 49) - { - goto default; - } - foreach(object[] annot in ReadAnnotations(br, classFile, utf8_cp)) - { - if(annot[1].Equals("Likvm/lang/Property;")) - { - DecodePropertyAnnotation(classFile, annot); - } -#if STATIC_COMPILER - else if(annot[1].Equals("Likvm/lang/Internal;")) - { - this.access_flags &= ~Modifiers.AccessMask; - flags |= FLAG_MASK_INTERNAL; - } -#endif - } - break; - case "RuntimeVisibleTypeAnnotations": - if (classFile.MajorVersion < 52) - { - goto default; - } - classFile.CreateUtf8ConstantPoolItems(utf8_cp); - runtimeVisibleTypeAnnotations = br.Section(br.ReadUInt32()).ToArray(); - break; - default: - br.Skip(br.ReadUInt32()); - break; - } - } - } - - private void DecodePropertyAnnotation(ClassFile classFile, object[] annot) - { - if(propertyGetterSetter != null) - { - Tracer.Error(Tracer.ClassLoading, "Ignoring duplicate ikvm.lang.Property annotation on {0}.{1}", classFile.Name, this.Name); - return; - } - propertyGetterSetter = new string[2]; - for(int i = 2; i < annot.Length - 1; i += 2) - { - string value = annot[i + 1] as string; - if(value == null) - { - propertyGetterSetter = null; - break; - } - if(annot[i].Equals("get") && propertyGetterSetter[0] == null) - { - propertyGetterSetter[0] = value; - } - else if(annot[i].Equals("set") && propertyGetterSetter[1] == null) - { - propertyGetterSetter[1] = value; - } - else - { - propertyGetterSetter = null; - break; - } - } - if(propertyGetterSetter == null || propertyGetterSetter[0] == null) - { - propertyGetterSetter = null; - Tracer.Error(Tracer.ClassLoading, "Ignoring malformed ikvm.lang.Property annotation on {0}.{1}", classFile.Name, this.Name); - return; - } - } - - protected override void ValidateSig(ClassFile classFile, string descriptor) - { - if(!IsValidFieldSig(descriptor)) - { - throw new ClassFormatError("{0} (Field \"{1}\" has invalid signature \"{2}\")", classFile.Name, this.Name, descriptor); - } - } - - internal object ConstantValue - { - get - { - return constantValue; - } - } - - internal bool IsStaticFinalConstant - { - get { return (access_flags & (Modifiers.Final | Modifiers.Static)) == (Modifiers.Final | Modifiers.Static) && constantValue != null; } - } - - internal bool IsProperty - { - get - { - return propertyGetterSetter != null; - } - } - - internal string PropertyGetter - { - get - { - return propertyGetterSetter[0]; - } - } - - internal string PropertySetter - { - get - { - return propertyGetterSetter[1]; - } - } - } - - internal sealed class Method : FieldOrMethod - { - private Code code; - private string[] exceptions; - private LowFreqData low; - private MethodParametersEntry[] parameters; - - sealed class LowFreqData - { - internal object annotationDefault; - internal object[][] parameterAnnotations; -#if STATIC_COMPILER - internal string DllExportName; - internal int DllExportOrdinal; - internal string InterlockedCompareAndSetField; -#endif - } - - internal Method(ClassFile classFile, string[] utf8_cp, ClassFileParseOptions options, BigEndianBinaryReader br) : base(classFile, utf8_cp, br) - { - // vmspec 4.6 says that all flags, except ACC_STRICT are ignored on <clinit> - // however, since Java 7 it does need to be marked static - if(ReferenceEquals(Name, StringConstants.CLINIT) && ReferenceEquals(Signature, StringConstants.SIG_VOID) && (classFile.MajorVersion < 51 || IsStatic)) - { - access_flags &= Modifiers.Strictfp; - access_flags |= (Modifiers.Static | Modifiers.Private); - } - else - { - // LAMESPEC: vmspec 4.6 says that abstract methods can not be strictfp (and this makes sense), but - // javac (pre 1.5) is broken and marks abstract methods as strictfp (if you put the strictfp on the class) - if((ReferenceEquals(Name, StringConstants.INIT) && (IsStatic || IsSynchronized || IsFinal || IsAbstract || IsNative)) - || (IsPrivate && IsPublic) || (IsPrivate && IsProtected) || (IsPublic && IsProtected) - || (IsAbstract && (IsFinal || IsNative || IsPrivate || IsStatic || IsSynchronized)) - || (classFile.IsInterface && classFile.MajorVersion <= 51 && (!IsPublic || IsFinal || IsNative || IsSynchronized || !IsAbstract)) - || (classFile.IsInterface && classFile.MajorVersion >= 52 && (!(IsPublic || IsPrivate) || IsFinal || IsNative || IsSynchronized))) - { - throw new ClassFormatError("Method {0} in class {1} has illegal modifiers: 0x{2:X}", Name, classFile.Name, (int)access_flags); - } - } - int attributes_count = br.ReadUInt16(); - for(int i = 0; i < attributes_count; i++) - { - switch(classFile.GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16())) - { - case "Deprecated": - if(br.ReadUInt32() != 0) - { - throw new ClassFormatError("Invalid Deprecated attribute length"); - } - flags |= FLAG_MASK_DEPRECATED; - break; - case "Code": - { - if(!code.IsEmpty) - { - throw new ClassFormatError("{0} (Duplicate Code attribute)", classFile.Name); - } - BigEndianBinaryReader rdr = br.Section(br.ReadUInt32()); - code.Read(classFile, utf8_cp, this, rdr, options); - if(!rdr.IsAtEnd) - { - throw new ClassFormatError("{0} (Code attribute has wrong length)", classFile.Name); - } - break; - } - case "Exceptions": - { - if(exceptions != null) - { - throw new ClassFormatError("{0} (Duplicate Exceptions attribute)", classFile.Name); - } - BigEndianBinaryReader rdr = br.Section(br.ReadUInt32()); - ushort count = rdr.ReadUInt16(); - exceptions = new string[count]; - for(int j = 0; j < count; j++) - { - exceptions[j] = classFile.GetConstantPoolClass(rdr.ReadUInt16()); - } - if(!rdr.IsAtEnd) - { - throw new ClassFormatError("{0} (Exceptions attribute has wrong length)", classFile.Name); - } - break; - } - case "Signature": - if(classFile.MajorVersion < 49) - { - goto default; - } - if(br.ReadUInt32() != 2) - { - throw new ClassFormatError("Signature attribute has incorrect length"); - } - signature = classFile.GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16()); - break; - case "RuntimeVisibleAnnotations": - if(classFile.MajorVersion < 49) - { - goto default; - } - annotations = ReadAnnotations(br, classFile, utf8_cp); - if ((options & ClassFileParseOptions.TrustedAnnotations) != 0) - { - foreach(object[] annot in annotations) - { - switch((string)annot[1]) - { -#if STATIC_COMPILER - case "Lsun/reflect/CallerSensitive;": - flags |= FLAG_CALLERSENSITIVE; - break; -#endif - case "Ljava/lang/invoke/LambdaForm$Compiled;": - flags |= FLAG_LAMBDAFORM_COMPILED; - break; - case "Ljava/lang/invoke/LambdaForm$Hidden;": - flags |= FLAG_LAMBDAFORM_HIDDEN; - break; - case "Ljava/lang/invoke/ForceInline;": - flags |= FLAG_FORCEINLINE; - break; - } - } - } - break; - case "RuntimeVisibleParameterAnnotations": - { - if(classFile.MajorVersion < 49) - { - goto default; - } - if(low == null) - { - low = new LowFreqData(); - } - BigEndianBinaryReader rdr = br.Section(br.ReadUInt32()); - byte num_parameters = rdr.ReadByte(); - low.parameterAnnotations = new object[num_parameters][]; - for(int j = 0; j < num_parameters; j++) - { - ushort num_annotations = rdr.ReadUInt16(); - low.parameterAnnotations[j] = new object[num_annotations]; - for(int k = 0; k < num_annotations; k++) - { - low.parameterAnnotations[j][k] = ReadAnnotation(rdr, classFile, utf8_cp); - } - } - if(!rdr.IsAtEnd) - { - throw new ClassFormatError("{0} (RuntimeVisibleParameterAnnotations attribute has wrong length)", classFile.Name); - } - break; - } - case "AnnotationDefault": - { - if(classFile.MajorVersion < 49) - { - goto default; - } - if(low == null) - { - low = new LowFreqData(); - } - BigEndianBinaryReader rdr = br.Section(br.ReadUInt32()); - low.annotationDefault = ReadAnnotationElementValue(rdr, classFile, utf8_cp); - if(!rdr.IsAtEnd) - { - throw new ClassFormatError("{0} (AnnotationDefault attribute has wrong length)", classFile.Name); - } - break; - } -#if STATIC_COMPILER - case "RuntimeInvisibleAnnotations": - if(classFile.MajorVersion < 49) - { - goto default; - } - foreach(object[] annot in ReadAnnotations(br, classFile, utf8_cp)) - { - if(annot[1].Equals("Likvm/lang/Internal;")) - { - if (classFile.IsInterface) - { - StaticCompiler.IssueMessage(Message.InterfaceMethodCantBeInternal, classFile.Name, this.Name, this.Signature); - } - else - { - this.access_flags &= ~Modifiers.AccessMask; - flags |= FLAG_MASK_INTERNAL; - } - } - if(annot[1].Equals("Likvm/lang/DllExport;")) - { - string name = null; - int? ordinal = null; - for (int j = 2; j < annot.Length; j += 2) - { - if (annot[j].Equals("name") && annot[j + 1] is string) - { - name = (string)annot[j + 1]; - } - else if (annot[j].Equals("ordinal") && annot[j + 1] is int) - { - ordinal = (int)annot[j + 1]; - } - } - if (name != null && ordinal != null) - { - if (!IsStatic) - { - StaticCompiler.IssueMessage(Message.DllExportMustBeStaticMethod, classFile.Name, this.Name, this.Signature); - } - else - { - if (low == null) - { - low = new LowFreqData(); - } - low.DllExportName = name; - low.DllExportOrdinal = ordinal.Value; - } - } - } - if(annot[1].Equals("Likvm/internal/InterlockedCompareAndSet;")) - { - string field = null; - for (int j = 2; j < annot.Length; j += 2) - { - if (annot[j].Equals("value") && annot[j + 1] is string) - { - field = (string)annot[j + 1]; - } - } - if (field != null) - { - if (low == null) - { - low = new LowFreqData(); - } - low.InterlockedCompareAndSetField = field; - } - } - } - break; -#endif - case "MethodParameters": - { - if(classFile.MajorVersion < 52) - { - goto default; - } - if(parameters != null) - { - throw new ClassFormatError("{0} (Duplicate MethodParameters attribute)", classFile.Name); - } - parameters = ReadMethodParameters(br, utf8_cp); - break; - } - case "RuntimeVisibleTypeAnnotations": - if (classFile.MajorVersion < 52) - { - goto default; - } - classFile.CreateUtf8ConstantPoolItems(utf8_cp); - runtimeVisibleTypeAnnotations = br.Section(br.ReadUInt32()).ToArray(); - break; - default: - br.Skip(br.ReadUInt32()); - break; - } - } - if(IsAbstract || IsNative) - { - if(!code.IsEmpty) - { - throw new ClassFormatError("Code attribute in native or abstract methods in class file " + classFile.Name); - } - } - else - { - if(code.IsEmpty) - { - if(ReferenceEquals(this.Name, StringConstants.CLINIT)) - { - code.verifyError = string.Format("Class {0}, method {1} signature {2}: No Code attribute", classFile.Name, this.Name, this.Signature); - return; - } - throw new ClassFormatError("Absent Code attribute in method that is not native or abstract in class file " + classFile.Name); - } - } - } - - private static MethodParametersEntry[] ReadMethodParameters(BigEndianBinaryReader br, string[] utf8_cp) - { - uint length = br.ReadUInt32(); - if(length > 0) - { - BigEndianBinaryReader rdr = br.Section(length); - byte parameters_count = rdr.ReadByte(); - if(length == 1 + parameters_count * 4) - { - MethodParametersEntry[] parameters = new MethodParametersEntry[parameters_count]; - for(int j = 0; j < parameters_count; j++) - { - ushort name = rdr.ReadUInt16(); - if(name >= utf8_cp.Length || (name != 0 && utf8_cp[name] == null)) - { - return MethodParametersEntry.Malformed; - } - parameters[j].name = utf8_cp[name]; - parameters[j].flags = rdr.ReadUInt16(); - } - return parameters; - } - } - throw new ClassFormatError("Invalid MethodParameters method attribute length " + length + " in class file"); - } - - protected override void ValidateSig(ClassFile classFile, string descriptor) - { - if(!IsValidMethodSig(descriptor)) - { - throw new ClassFormatError("{0} (Method \"{1}\" has invalid signature \"{2}\")", classFile.Name, this.Name, descriptor); - } - } - - internal bool IsStrictfp - { - get - { - return (access_flags & Modifiers.Strictfp) != 0; - } - } - - internal bool IsVirtual - { - get - { - return (access_flags & (Modifiers.Static | Modifiers.Private)) == 0 - && !IsConstructor; - } - } - - // Is this the <clinit>()V method? - internal bool IsClassInitializer - { - get - { - return ReferenceEquals(Name, StringConstants.CLINIT) && ReferenceEquals(Signature, StringConstants.SIG_VOID) && IsStatic; - } - } - - internal bool IsConstructor - { - get - { - return ReferenceEquals(Name, StringConstants.INIT); - } - } - -#if STATIC_COMPILER - internal bool IsCallerSensitive - { - get - { - return (flags & FLAG_CALLERSENSITIVE) != 0; - } - } -#endif - - internal bool IsLambdaFormCompiled - { - get - { - return (flags & FLAG_LAMBDAFORM_COMPILED) != 0; - } - } - - internal bool IsLambdaFormHidden - { - get - { - return (flags & FLAG_LAMBDAFORM_HIDDEN) != 0; - } - } - - internal bool IsForceInline - { - get - { - return (flags & FLAG_FORCEINLINE) != 0; - } - } - - internal string[] ExceptionsAttribute - { - get - { - return exceptions; - } - } - - internal object[][] ParameterAnnotations - { - get - { - return low == null ? null : low.parameterAnnotations; - } - } - - internal object AnnotationDefault - { - get - { - return low == null ? null : low.annotationDefault; - } - } - -#if STATIC_COMPILER - internal string DllExportName - { - get - { - return low == null ? null : low.DllExportName; - } - } - - internal int DllExportOrdinal - { - get - { - return low == null ? -1 : low.DllExportOrdinal; - } - } - - internal string InterlockedCompareAndSetField - { - get - { - return low == null ? null : low.InterlockedCompareAndSetField; - } - } -#endif - - internal string VerifyError - { - get - { - return code.verifyError; - } - } - - // maps argument 'slot' (as encoded in the xload/xstore instructions) into the ordinal - internal int[] ArgMap - { - get - { - return code.argmap; - } - } - - internal int MaxStack - { - get - { - return code.max_stack; - } - } - - internal int MaxLocals - { - get - { - return code.max_locals; - } - } - - internal Instruction[] Instructions - { - get - { - return code.instructions; - } - set - { - code.instructions = value; - } - } - - internal ExceptionTableEntry[] ExceptionTable - { - get - { - return code.exception_table; - } - set - { - code.exception_table = value; - } - } - - internal LineNumberTableEntry[] LineNumberTableAttribute - { - get - { - return code.lineNumberTable; - } - } - - internal LocalVariableTableEntry[] LocalVariableTableAttribute - { - get - { - return code.localVariableTable; - } - } - - internal MethodParametersEntry[] MethodParameters - { - get - { - return parameters; - } - } - - internal bool MalformedMethodParameters - { - get - { - return parameters == MethodParametersEntry.Malformed; - } - } - - internal bool HasJsr - { - get - { - return code.hasJsr; - } - } - - private struct Code - { - internal bool hasJsr; - internal string verifyError; - internal ushort max_stack; - internal ushort max_locals; - internal Instruction[] instructions; - internal ExceptionTableEntry[] exception_table; - internal int[] argmap; - internal LineNumberTableEntry[] lineNumberTable; - internal LocalVariableTableEntry[] localVariableTable; - - internal void Read(ClassFile classFile, string[] utf8_cp, Method method, BigEndianBinaryReader br, ClassFileParseOptions options) - { - max_stack = br.ReadUInt16(); - max_locals = br.ReadUInt16(); - uint code_length = br.ReadUInt32(); - if(code_length == 0 || code_length > 65535) - { - throw new ClassFormatError("Invalid method Code length {1} in class file {0}", classFile.Name, code_length); - } - Instruction[] instructions = new Instruction[code_length + 1]; - int basePosition = br.Position; - int instructionIndex = 0; - try - { - BigEndianBinaryReader rdr = br.Section(code_length); - while(!rdr.IsAtEnd) - { - instructions[instructionIndex].Read((ushort)(rdr.Position - basePosition), rdr, classFile); - hasJsr |= instructions[instructionIndex].NormalizedOpCode == NormalizedByteCode.__jsr; - instructionIndex++; - } - // we add an additional nop instruction to make it easier for consumers of the code array - instructions[instructionIndex++].SetTermNop((ushort)(rdr.Position - basePosition)); - } - catch(ClassFormatError x) - { - // any class format errors in the code block are actually verify errors - verifyError = x.Message; - } - this.instructions = new Instruction[instructionIndex]; - Array.Copy(instructions, 0, this.instructions, 0, instructionIndex); - // build the pcIndexMap - int[] pcIndexMap = new int[this.instructions[instructionIndex - 1].PC + 1]; - for(int i = 0; i < pcIndexMap.Length; i++) - { - pcIndexMap[i] = -1; - } - for(int i = 0; i < instructionIndex - 1; i++) - { - pcIndexMap[this.instructions[i].PC] = i; - } - // convert branch offsets to indexes - for(int i = 0; i < instructionIndex - 1; i++) - { - switch(this.instructions[i].NormalizedOpCode) - { - case NormalizedByteCode.__ifeq: - case NormalizedByteCode.__ifne: - case NormalizedByteCode.__iflt: - case NormalizedByteCode.__ifge: - case NormalizedByteCode.__ifgt: - case NormalizedByteCode.__ifle: - case NormalizedByteCode.__if_icmpeq: - case NormalizedByteCode.__if_icmpne: - case NormalizedByteCode.__if_icmplt: - case NormalizedByteCode.__if_icmpge: - case NormalizedByteCode.__if_icmpgt: - case NormalizedByteCode.__if_icmple: - case NormalizedByteCode.__if_acmpeq: - case NormalizedByteCode.__if_acmpne: - case NormalizedByteCode.__ifnull: - case NormalizedByteCode.__ifnonnull: - case NormalizedByteCode.__goto: - case NormalizedByteCode.__jsr: - this.instructions[i].SetTargetIndex(pcIndexMap[this.instructions[i].Arg1 + this.instructions[i].PC]); - break; - case NormalizedByteCode.__tableswitch: - case NormalizedByteCode.__lookupswitch: - this.instructions[i].MapSwitchTargets(pcIndexMap); - break; - } - } - // read exception table - ushort exception_table_length = br.ReadUInt16(); - exception_table = new ExceptionTableEntry[exception_table_length]; - for(int i = 0; i < exception_table_length; i++) - { - ushort start_pc = br.ReadUInt16(); - ushort end_pc = br.ReadUInt16(); - ushort handler_pc = br.ReadUInt16(); - ushort catch_type = br.ReadUInt16(); - if(start_pc >= end_pc - || end_pc > code_length - || handler_pc >= code_length - || (catch_type != 0 && !classFile.SafeIsConstantPoolClass(catch_type))) - { - throw new ClassFormatError("Illegal exception table: {0}.{1}{2}", classFile.Name, method.Name, method.Signature); - } - classFile.MarkLinkRequiredConstantPoolItem(catch_type); - // if start_pc, end_pc or handler_pc is invalid (i.e. doesn't point to the start of an instruction), - // the index will be -1 and this will be handled by the verifier - int startIndex = pcIndexMap[start_pc]; - int endIndex; - if (end_pc == code_length) - { - // it is legal for end_pc to point to just after the last instruction, - // but since there isn't an entry in our pcIndexMap for that, we have - // a special case for this - endIndex = instructionIndex - 1; - } - else - { - endIndex = pcIndexMap[end_pc]; - } - int handlerIndex = pcIndexMap[handler_pc]; - exception_table[i] = new ExceptionTableEntry(startIndex, endIndex, handlerIndex, catch_type, i); - } - ushort attributes_count = br.ReadUInt16(); - for(int i = 0; i < attributes_count; i++) - { - switch(classFile.GetConstantPoolUtf8String(utf8_cp, br.ReadUInt16())) - { - case "LineNumberTable": - if((options & ClassFileParseOptions.LineNumberTable) != 0) - { - BigEndianBinaryReader rdr = br.Section(br.ReadUInt32()); - int count = rdr.ReadUInt16(); - lineNumberTable = new LineNumberTableEntry[count]; - for(int j = 0; j < count; j++) - { - lineNumberTable[j].start_pc = rdr.ReadUInt16(); - lineNumberTable[j].line_number = rdr.ReadUInt16(); - if(lineNumberTable[j].start_pc >= code_length) - { - throw new ClassFormatError("{0} (LineNumberTable has invalid pc)", classFile.Name); - } - } - if(!rdr.IsAtEnd) - { - throw new ClassFormatError("{0} (LineNumberTable attribute has wrong length)", classFile.Name); - } - } - else - { - br.Skip(br.ReadUInt32()); - } - break; - case "LocalVariableTable": - if((options & ClassFileParseOptions.LocalVariableTable) != 0) - { - BigEndianBinaryReader rdr = br.Section(br.ReadUInt32()); - int count = rdr.ReadUInt16(); - localVariableTable = new LocalVariableTableEntry[count]; - for(int j = 0; j < count; j++) - { - localVariableTable[j].start_pc = rdr.ReadUInt16(); - localVariableTable[j].length = rdr.ReadUInt16(); - localVariableTable[j].name = classFile.GetConstantPoolUtf8String(utf8_cp, rdr.ReadUInt16()); - localVariableTable[j].descriptor = classFile.GetConstantPoolUtf8String(utf8_cp, rdr.ReadUInt16()).Replace('/', '.'); - localVariableTable[j].index = rdr.ReadUInt16(); - } - // NOTE we're intentionally not checking that we're at the end of the section - // (optional attributes shouldn't cause ClassFormatError) - } - else - { - br.Skip(br.ReadUInt32()); - } - break; - default: - br.Skip(br.ReadUInt32()); - break; - } - } - // build the argmap - string sig = method.Signature; - List<int> args = new List<int>(); - int pos = 0; - if(!method.IsStatic) - { - args.Add(pos++); - } - for(int i = 1; sig[i] != ')'; i++) - { - args.Add(pos++); - switch(sig[i]) - { - case 'L': - i = sig.IndexOf(';', i); - break; - case 'D': - case 'J': - args.Add(-1); - break; - case '[': - { - while(sig[i] == '[') - { - i++; - } - if(sig[i] == 'L') - { - i = sig.IndexOf(';', i); - } - break; - } - } - } - argmap = args.ToArray(); - if(args.Count > max_locals) - { - throw new ClassFormatError("{0} (Arguments can't fit into locals)", classFile.Name); - } - } - - internal bool IsEmpty - { - get - { - return instructions == null; - } - } - } - - internal sealed class ExceptionTableEntry - { - internal readonly int startIndex; - internal readonly int endIndex; - internal readonly int handlerIndex; - internal readonly ushort catch_type; - internal readonly int ordinal; - internal readonly bool isFinally; - - internal ExceptionTableEntry(int startIndex, int endIndex, int handlerIndex, ushort catch_type, int ordinal) - : this(startIndex, endIndex, handlerIndex, catch_type, ordinal, false) - { - } - - internal ExceptionTableEntry(int startIndex, int endIndex, int handlerIndex, ushort catch_type, int ordinal, bool isFinally) - { - this.startIndex = startIndex; - this.endIndex = endIndex; - this.handlerIndex = handlerIndex; - this.catch_type = catch_type; - this.ordinal = ordinal; - this.isFinally = isFinally; - } - } - - [Flags] - internal enum InstructionFlags : byte - { - Reachable = 1, - Processed = 2, - BranchTarget = 4, - } - - internal struct Instruction - { - private ushort pc; - private NormalizedByteCode normopcode; - private int arg1; - private short arg2; - private SwitchEntry[] switch_entries; - - struct SwitchEntry - { - internal int value; - internal int target; - } - - internal void SetHardError(HardError error, int messageId) - { - normopcode = NormalizedByteCode.__static_error; - arg2 = (short)error; - arg1 = messageId; - } - - internal HardError HardError - { - get - { - return (HardError)arg2; - } - } - - internal int HandlerIndex - { - get { return (ushort)arg2; } - } - - internal int HardErrorMessageId - { - get - { - return arg1; - } - } - - internal void PatchOpCode(NormalizedByteCode bc) - { - this.normopcode = bc; - } - - internal void PatchOpCode(NormalizedByteCode bc, int arg1) - { - this.normopcode = bc; - this.arg1 = arg1; - } - - internal void PatchOpCode(NormalizedByteCode bc, int arg1, short arg2) - { - this.normopcode = bc; - this.arg1 = arg1; - this.arg2 = arg2; - } - - internal void SetPC(int pc) - { - this.pc = (ushort)pc; - } - - internal void SetTargetIndex(int targetIndex) - { - this.arg1 = targetIndex; - } - - internal void SetTermNop(ushort pc) - { - // TODO what happens if we already have exactly the maximum number of instructions? - this.pc = pc; - this.normopcode = NormalizedByteCode.__nop; - } - - internal void MapSwitchTargets(int[] pcIndexMap) - { - arg1 = pcIndexMap[arg1 + pc]; - for (int i = 0; i < switch_entries.Length; i++) - { - switch_entries[i].target = pcIndexMap[switch_entries[i].target + pc]; - } - } - - internal void Read(ushort pc, BigEndianBinaryReader br, ClassFile classFile) - { - this.pc = pc; - ByteCode bc = (ByteCode)br.ReadByte(); - switch(ByteCodeMetaData.GetMode(bc)) - { - case ByteCodeMode.Simple: - break; - case ByteCodeMode.Constant_1: - arg1 = br.ReadByte(); - classFile.MarkLinkRequiredConstantPoolItem(arg1); - break; - case ByteCodeMode.Local_1: - arg1 = br.ReadByte(); - break; - case ByteCodeMode.Constant_2: - arg1 = br.ReadUInt16(); - classFile.MarkLinkRequiredConstantPoolItem(arg1); - break; - case ByteCodeMode.Branch_2: - arg1 = br.ReadInt16(); - break; - case ByteCodeMode.Branch_4: - arg1 = br.ReadInt32(); - break; - case ByteCodeMode.Constant_2_1_1: - arg1 = br.ReadUInt16(); - classFile.MarkLinkRequiredConstantPoolItem(arg1); - arg2 = br.ReadByte(); - if(br.ReadByte() != 0) - { - throw new ClassFormatError("invokeinterface filler must be zero"); - } - break; - case ByteCodeMode.Immediate_1: - arg1 = br.ReadSByte(); - break; - case ByteCodeMode.Immediate_2: - arg1 = br.ReadInt16(); - break; - case ByteCodeMode.Local_1_Immediate_1: - arg1 = br.ReadByte(); - arg2 = br.ReadSByte(); - break; - case ByteCodeMode.Constant_2_Immediate_1: - arg1 = br.ReadUInt16(); - classFile.MarkLinkRequiredConstantPoolItem(arg1); - arg2 = br.ReadSByte(); - break; - case ByteCodeMode.Tableswitch: - { - // skip the padding - uint p = pc + 1u; - uint align = ((p + 3) & 0x7ffffffc) - p; - br.Skip(align); - int default_offset = br.ReadInt32(); - this.arg1 = default_offset; - int low = br.ReadInt32(); - int high = br.ReadInt32(); - if(low > high || high > 16384L + low) - { - throw new ClassFormatError("Incorrect tableswitch"); - } - SwitchEntry[] entries = new SwitchEntry[high - low + 1]; - for(int i = low; i < high; i++) - { - entries[i - low].value = i; - entries[i - low].target = br.ReadInt32(); - } - // do the last entry outside the loop, to avoid overflowing "i", if high == int.MaxValue - entries[high - low].value = high; - entries[high - low].target = br.ReadInt32(); - this.switch_entries = entries; - break; - } - case ByteCodeMode.Lookupswitch: - { - // skip the padding - uint p = pc + 1u; - uint align = ((p + 3) & 0x7ffffffc) - p; - br.Skip(align); - int default_offset = br.ReadInt32(); - this.arg1 = default_offset; - int count = br.ReadInt32(); - if(count < 0 || count > 16384) - { - throw new ClassFormatError("Incorrect lookupswitch"); - } - SwitchEntry[] entries = new SwitchEntry[count]; - for(int i = 0; i < count; i++) - { - entries[i].value = br.ReadInt32(); - entries[i].target = br.ReadInt32(); - } - this.switch_entries = entries; - break; - } - case ByteCodeMode.WidePrefix: - bc = (ByteCode)br.ReadByte(); - // NOTE the PC of a wide instruction is actually the PC of the - // wide prefix, not the following instruction (vmspec 4.9.2) - switch(ByteCodeMetaData.GetWideMode(bc)) - { - case ByteCodeModeWide.Local_2: - arg1 = br.ReadUInt16(); - break; - case ByteCodeModeWide.Local_2_Immediate_2: - arg1 = br.ReadUInt16(); - arg2 = br.ReadInt16(); - break; - default: - throw new ClassFormatError("Invalid wide prefix on opcode: {0}", bc); - } - break; - default: - throw new ClassFormatError("Invalid opcode: {0}", bc); - } - this.normopcode = ByteCodeMetaData.GetNormalizedByteCode(bc); - arg1 = ByteCodeMetaData.GetArg(bc, arg1); - } - - internal int PC - { - get - { - return pc; - } - } - - internal NormalizedByteCode NormalizedOpCode - { - get - { - return normopcode; - } - } - - internal int Arg1 - { - get - { - return arg1; - } - } - - internal int TargetIndex - { - get - { - return arg1; - } - set - { - arg1 = value; - } - } - - internal int Arg2 - { - get - { - return arg2; - } - } - - internal int NormalizedArg1 - { - get - { - return arg1; - } - } - - internal int DefaultTarget - { - get - { - return arg1; - } - set - { - arg1 = value; - } - } - - internal int SwitchEntryCount - { - get - { - return switch_entries.Length; - } - } - - internal int GetSwitchValue(int i) - { - return switch_entries[i].value; - } - - internal int GetSwitchTargetIndex(int i) - { - return switch_entries[i].target; - } - - internal void SetSwitchTargets(int[] targets) - { - SwitchEntry[] newEntries = (SwitchEntry[])switch_entries.Clone(); - for (int i = 0; i < newEntries.Length; i++) - { - newEntries[i].target = targets[i]; - } - switch_entries = newEntries; - } - } - - internal struct LineNumberTableEntry - { - internal ushort start_pc; - internal ushort line_number; - } - - internal struct LocalVariableTableEntry - { - internal ushort start_pc; - internal ushort length; - internal string name; - internal string descriptor; - internal ushort index; - } - } - - internal Field GetField(string name, string sig) - { - for (int i = 0; i < fields.Length; i++) - { - if (fields[i].Name == name && fields[i].Signature == sig) - { - return fields[i]; - } - } - return null; - } - - internal bool HasSerialVersionUID - { - get - { - Field field = GetField("serialVersionUID", "J"); - return field != null && field.IsStatic && field.IsFinal; - } - } - } -} |