ikvm-fork/runtime/ClassFile.cs

2628 строки
63 KiB
C#
Исходник Обычный вид История

2002-12-18 19:00:25 +03:00
/*
2005-01-06 12:36:49 +03:00
Copyright (C) 2002, 2003, 2004, 2005 Jeroen Frijters
2002-12-18 19:00:25 +03:00
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;
2004-09-09 15:17:55 +04:00
using IKVM.Attributes;
using IKVM.Runtime;
2005-06-01 13:49:30 +04:00
namespace IKVM.Internal
2002-12-18 19:00:25 +03:00
{
2005-08-02 11:24:54 +04:00
enum HardError : short
{
NoClassDefFoundError,
IllegalAccessError,
InstantiationError,
IncompatibleClassChangeError,
NoSuchFieldError,
AbstractMethodError,
NoSuchMethodError,
LinkageError
}
2005-06-01 13:49:30 +04:00
sealed class ClassFile
2005-01-10 11:24:27 +03:00
{
2005-06-01 13:49:30 +04:00
private ConstantPoolItem[] constantpool;
private string[] utf8_cp;
private Modifiers access_flags;
private ushort this_class;
private ushort super_class;
private ConstantPoolItemClass[] interfaces;
private Field[] fields;
private Method[] methods;
private string sourceFile;
private ushort majorVersion;
private bool deprecated;
2005-10-01 15:16:11 +04:00
private string signature;
private string[] enclosingMethod;
2005-06-01 13:49:30 +04:00
private string ikvmAssembly;
private InnerClass[] innerClasses;
2005-11-01 17:01:42 +03:00
private object[] annotations;
2005-01-10 11:24:27 +03:00
2005-06-01 13:49:30 +04:00
private class SupportedVersions
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
internal static readonly int Minimum = 45;
2005-10-01 15:16:11 +04:00
#if GENERICS
internal static readonly int Maximum = 49;
#else
2005-06-01 13:49:30 +04:00
internal static readonly int Maximum = JVM.SafeGetEnvironmentVariable("IKVM_EXPERIMENTAL_JDK_5_0") == null ? 48 : 49;
2005-10-01 15:16:11 +04:00
#endif
2005-06-01 13:49:30 +04:00
}
2005-08-03 16:59:16 +04:00
// This method parses just enough of the class file to obtain its name, 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)
{
const string inputClassName = "(unknown)";
BigEndianBinaryReader br = new BigEndianBinaryReader(buf, offset, length);
if(br.ReadUInt32() != 0xCAFEBABE)
{
throw new ClassFormatError("{0} (Bad magic number)", inputClassName);
}
int minorVersion = br.ReadUInt16();
int majorVersion = br.ReadUInt16();
if(majorVersion < SupportedVersions.Minimum || majorVersion > SupportedVersions.Maximum)
{
throw new UnsupportedClassVersionError(inputClassName + " (" + 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.NameAndType:
case Constant.Float:
case Constant.Integer:
br.Skip(4);
break;
case Constant.String:
br.Skip(2);
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);
}
}
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);
}
}
internal ClassFile(byte[] buf, int offset, int length, string inputClassName)
2005-06-01 13:49:30 +04:00
{
try
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
BigEndianBinaryReader br = new BigEndianBinaryReader(buf, offset, length);
if(br.ReadUInt32() != 0xCAFEBABE)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
throw new ClassFormatError("{0} (Bad magic number)", inputClassName);
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
int minorVersion = br.ReadUInt16();
majorVersion = br.ReadUInt16();
if(majorVersion < SupportedVersions.Minimum || majorVersion > SupportedVersions.Maximum)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
throw new UnsupportedClassVersionError(inputClassName + " (" + majorVersion + "." + minorVersion + ")");
}
int constantpoolcount = br.ReadUInt16();
constantpool = new ConstantPoolItem[constantpoolcount];
utf8_cp = new string[constantpoolcount];
for(int i = 1; i < constantpoolcount; i++)
{
Constant tag = (Constant)br.ReadByte();
switch(tag)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
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.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);
2002-12-18 19:00:25 +03:00
}
}
2005-06-01 13:49:30 +04:00
for(int i = 1; i < constantpoolcount; i++)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
if(constantpool[i] != null)
{
try
{
constantpool[i].Resolve(this);
}
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);
}
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
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
// NOTE although the vmspec implies (in 4.1) that ACC_SUPER is illegal on interfaces, it doesn't enforce this
2005-11-01 17:01:42 +03:00
if((IsInterface && IsFinal)
|| (IsAbstract && IsFinal)
|| (majorVersion >= 49 && IsAnnotation && !IsInterface))
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
throw new ClassFormatError("{0} (Illegal class modifiers 0x{1:X})", inputClassName, access_flags);
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
this_class = br.ReadUInt16();
ValidateConstantPoolItemClass(inputClassName, this_class);
super_class = br.ReadUInt16();
2005-08-03 16:59:16 +04:00
ValidateConstantPoolItemClass(inputClassName, super_class);
2005-06-01 13:49:30 +04:00
if(IsInterface && (super_class == 0 || this.SuperClass != "java.lang.Object"))
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
throw new ClassFormatError("{0} (Interfaces must have java.lang.Object as superclass)", Name);
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
// 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] == '[')
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
throw new ClassFormatError("Bad name");
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
int interfaces_count = br.ReadUInt16();
interfaces = new ConstantPoolItemClass[interfaces_count];
for(int i = 0; i < interfaces.Length; i++)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
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;
for(int j = 0; j < i; j++)
{
2005-07-20 13:42:11 +04:00
if(ReferenceEquals(interfaces[j].Name, cpi.Name))
2005-06-01 13:49:30 +04:00
{
throw new ClassFormatError("{0} (Repetitive interface name)", Name);
}
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
int fields_count = br.ReadUInt16();
fields = new Field[fields_count];
for(int i = 0; i < fields_count; i++)
2004-08-30 19:56:23 +04:00
{
2005-06-01 13:49:30 +04:00
fields[i] = new Field(this, br);
string name = fields[i].Name;
2005-11-01 17:01:42 +03:00
if(!IsValidFieldName(name))
2005-06-01 13:49:30 +04:00
{
throw new ClassFormatError("{0} (Illegal field name \"{1}\")", Name, name);
}
2005-07-20 13:42:11 +04:00
for(int j = 0; j < i; j++)
2005-06-01 13:49:30 +04:00
{
2005-07-20 13:42:11 +04:00
if(ReferenceEquals(fields[j].Name, name) && ReferenceEquals(fields[j].Signature, fields[i].Signature))
{
throw new ClassFormatError("{0} (Repetitive field name/signature)", Name);
}
2005-06-01 13:49:30 +04:00
}
2004-08-30 19:56:23 +04:00
}
2005-06-01 13:49:30 +04:00
int methods_count = br.ReadUInt16();
methods = new Method[methods_count];
for(int i = 0; i < methods_count; i++)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
methods[i] = new Method(this, br);
string name = methods[i].Name;
string sig = methods[i].Signature;
2005-11-01 17:01:42 +03:00
if(!IsValidMethodName(name) && name != "<init>" && name != "<clinit>")
2005-06-01 13:49:30 +04:00
{
throw new ClassFormatError("{0} (Illegal method name \"{1}\")", Name, name);
}
if((name == "<init>" || name == "<clinit>") && !sig.EndsWith("V"))
{
throw new ClassFormatError("{0} (Method \"{1}\" has illegal signature \"{2}\")", Name, name, sig);
}
2005-07-20 13:42:11 +04:00
for(int j = 0; j < i; j++)
2005-06-01 13:49:30 +04:00
{
2005-07-20 13:42:11 +04:00
if(ReferenceEquals(methods[j].Name, name) && ReferenceEquals(methods[j].Signature, sig))
{
throw new ClassFormatError("{0} (Repetitive method name/signature)", Name);
}
2005-06-01 13:49:30 +04:00
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
int attributes_count = br.ReadUInt16();
for(int i = 0; i < attributes_count; i++)
2004-08-30 19:56:23 +04:00
{
2005-06-01 13:49:30 +04:00
switch(GetConstantPoolUtf8String(br.ReadUInt16()))
{
case "Deprecated":
deprecated = true;
br.Skip(br.ReadUInt32());
break;
case "SourceFile":
if(br.ReadUInt32() != 2)
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
throw new ClassFormatError("SourceFile attribute has incorrect length");
2004-12-21 13:26:51 +03:00
}
2005-06-01 13:49:30 +04:00
sourceFile = GetConstantPoolUtf8String(br.ReadUInt16());
break;
case "InnerClasses":
2005-11-01 17:01:42 +03:00
{
2005-06-01 13:49:30 +04:00
// Sun totally ignores the length of InnerClasses attribute,
// so when we're running Fuzz this used to show up as lots of differences,
// now we do the same.
BigEndianBinaryReader rdr = br;
br.ReadUInt32();
ushort count = rdr.ReadUInt16();
innerClasses = new InnerClass[count];
for(int j = 0; j < innerClasses.Length; j++)
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
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);
}
2004-12-21 13:26:51 +03:00
}
2005-06-01 13:49:30 +04:00
break;
2005-11-01 17:01:42 +03:00
}
#if GENERICS
2005-10-01 15:16:11 +04:00
case "Signature":
if(majorVersion < 49)
{
goto default;
}
if(br.ReadUInt32() != 2)
{
throw new ClassFormatError("Signature attribute has incorrect length");
}
signature = GetConstantPoolUtf8String(br.ReadUInt16());
break;
case "EnclosingMethod":
if(majorVersion < 49)
{
goto default;
}
if(br.ReadUInt32() != 4)
{
throw new ClassFormatError("EnclosingMethod attribute has incorrect length");
}
else
{
int class_index = br.ReadUInt16();
int method_index = br.ReadUInt16();
if(method_index == 0)
{
enclosingMethod = new string[] {
GetConstantPoolClass(class_index),
null,
null
};
}
else
{
ConstantPoolItemNameAndType m = (ConstantPoolItemNameAndType)GetConstantPoolItem(method_index);
enclosingMethod = new string[] {
GetConstantPoolClass(class_index),
GetConstantPoolUtf8String(m.name_index),
GetConstantPoolUtf8String(m.descriptor_index).Replace('/', '.')
};
}
}
break;
2005-11-01 17:01:42 +03:00
case "RuntimeVisibleAnnotations":
if(majorVersion < 49)
{
goto default;
}
annotations = ReadAnnotations(br, this);
break;
#endif
2005-06-01 13:49:30 +04:00
case "IKVM.NET.Assembly":
if(br.ReadUInt32() != 2)
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
throw new ClassFormatError("IKVM.NET.Assembly attribute has incorrect length");
2004-12-21 13:26:51 +03:00
}
2005-06-01 13:49:30 +04:00
ikvmAssembly = GetConstantPoolUtf8String(br.ReadUInt16());
break;
default:
br.Skip(br.ReadUInt32());
break;
}
}
2005-07-20 13:42:11 +04:00
// now that we've constructed the high level objects, the utf8 table isn't needed anymore
// TODO remove utf8_cp field from ClassFile object
utf8_cp = null;
2005-06-01 13:49:30 +04:00
if(br.Position != offset + length)
{
throw new ClassFormatError("Extra bytes at the end of the class file");
2004-08-30 19:56:23 +04:00
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
catch(OverflowException)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
throw new ClassFormatError("Truncated class file (or section)");
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
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;
// }
2002-12-18 19:00:25 +03:00
}
2005-11-01 17:01:42 +03:00
private static object[] ReadAnnotations(BigEndianBinaryReader br, ClassFile classFile)
{
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);
}
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 type = classFile.GetConstantPoolUtf8String(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(rdr.ReadUInt16());
annot[2 + i * 2 + 1] = ReadAnnotationElementValue(rdr, classFile);
}
return annot;
}
private static object ReadAnnotationElementValue(BigEndianBinaryReader rdr, ClassFile classFile)
{
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(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(type_name_index),
classFile.GetConstantPoolUtf8String(const_name_index)
};
}
case (byte)'c':
return new object[] {
AnnotationDefaultAttribute.TAG_CLASS,
classFile.GetConstantPoolUtf8String(rdr.ReadUInt16())
};
case (byte)'@':
return ReadAnnotation(rdr, classFile);
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);
}
return array;
}
default:
throw new ClassFormatError("Invalid tag {0} in annotation element_value", tag);
}
}
2005-06-01 13:49:30 +04:00
private void ValidateConstantPoolItemClass(string classFile, ushort index)
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
if(index >= constantpool.Length || !(constantpool[index] is ConstantPoolItemClass))
{
throw new ClassFormatError("{0} (Bad constant pool index #{1})", classFile, index);
}
2004-12-21 13:26:51 +03:00
}
2005-11-01 17:01:42 +03:00
private static bool IsValidMethodName(string name)
{
if(name.Length == 0)
{
return false;
}
for(int i = 0; i < name.Length; i++)
{
if(".;[/<>".IndexOf(name[i]) != -1)
{
return false;
}
}
return true;
}
private static bool IsValidFieldName(string name)
{
if(name.Length == 0)
{
return false;
}
for(int i = 0; i < name.Length; i++)
{
if(".;[/".IndexOf(name[i]) != -1)
{
return false;
}
}
return true;
}
private static bool IsValidClassName(string name)
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
if(name.Length == 0)
2004-12-21 13:26:51 +03:00
{
return false;
}
2005-06-01 13:49:30 +04:00
if(!Char.IsLetter(name[0]) && name[0] != '$' && name[0] != '_')
{
2004-12-21 13:26:51 +03:00
return false;
2005-06-01 13:49:30 +04:00
}
for(int i = 1; i < name.Length; i++)
{
if(!Char.IsLetterOrDigit(name[i]) && name[i] != '$' && name[i] != '_')
{
return false;
}
}
return true;
2004-12-21 13:26:51 +03:00
}
2005-06-01 13:49:30 +04:00
private static bool IsValidFieldSig(string sig)
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
return IsValidFieldSigImpl(sig, 0, sig.Length);
2004-12-21 13:26:51 +03:00
}
2005-06-01 13:49:30 +04:00
private static bool IsValidFieldSigImpl(string sig, int start, int end)
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
if(start >= end)
{
return false;
}
switch(sig[start])
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
case 'L':
// TODO we might consider doing more checking here
return sig.IndexOf(';', start + 1) == end - 1;
case '[':
while(sig[start] == '[')
{
start++;
if(start == end)
{
return false;
}
}
return IsValidFieldSigImpl(sig, start, end);
2004-12-21 13:26:51 +03:00
case 'B':
case 'Z':
case 'C':
case 'S':
case 'I':
case 'J':
case 'F':
case 'D':
2005-06-01 13:49:30 +04:00
return start == end - 1;
2004-12-21 13:26:51 +03:00
default:
return false;
}
2005-06-01 13:49:30 +04:00
}
private static bool IsValidMethodSig(string sig)
{
if(sig.Length < 3 || sig[0] != '(')
{
return false;
}
int end = sig.IndexOf(')');
if(end == -1)
2004-12-21 13:26:51 +03:00
{
return false;
}
2005-06-01 13:49:30 +04:00
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;
2004-12-21 13:26:51 +03:00
}
2005-06-01 13:49:30 +04:00
internal int MajorVersion
2004-03-16 20:10:09 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return majorVersion;
}
2004-03-16 20:10:09 +03:00
}
2005-06-01 13:49:30 +04:00
internal void Link(TypeWrapper thisType, Hashtable classCache)
2003-01-02 18:44:17 +03:00
{
2005-06-01 13:49:30 +04:00
for(int i = 1; i < constantpool.Length; i++)
2003-01-02 18:44:17 +03:00
{
2005-06-01 13:49:30 +04:00
if(constantpool[i] != null)
{
constantpool[i].Link(thisType, classCache);
}
2003-01-02 18:44:17 +03:00
}
}
2005-06-01 13:49:30 +04:00
internal Modifiers Modifiers
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return access_flags;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal bool IsAbstract
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
// interfaces are implicitly abstract
return (access_flags & (Modifiers.Abstract | Modifiers.Interface)) != 0;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal bool IsFinal
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return (access_flags & Modifiers.Final) != 0;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal bool IsPublic
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return (access_flags & Modifiers.Public) != 0;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal bool IsInterface
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return (access_flags & Modifiers.Interface) != 0;
}
2002-12-18 19:00:25 +03:00
}
2005-11-01 17:01:42 +03:00
internal bool IsEnum
{
get
{
return (access_flags & Modifiers.Enum) != 0;
}
}
internal bool IsAnnotation
{
get
{
return (access_flags & Modifiers.Annotation) != 0;
}
}
2005-06-01 13:49:30 +04:00
internal bool IsSuper
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return (access_flags & Modifiers.Super) != 0;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal void RemoveUnusedFields()
2005-01-05 15:32:00 +03:00
{
2005-06-01 13:49:30 +04:00
ArrayList list = new ArrayList();
foreach(Field f in fields)
2005-01-05 15:32:00 +03:00
{
2005-06-01 13:49:30 +04:00
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);
}
2005-01-05 15:32:00 +03:00
}
2005-06-01 13:49:30 +04:00
fields = (Field[])list.ToArray(typeof(Field));
2005-01-05 15:32:00 +03:00
}
2005-06-01 13:49:30 +04:00
private bool IsReferenced(Field fld)
2005-01-05 15:32:00 +03:00
{
2005-06-01 13:49:30 +04:00
foreach(ConstantPoolItem cpi in constantpool)
2005-01-05 15:32:00 +03:00
{
2005-06-01 13:49:30 +04:00
ConstantPoolItemFieldref fieldref = cpi as ConstantPoolItemFieldref;
if(fieldref != null &&
fieldref.Class == this.Name &&
fieldref.Name == fld.Name &&
fieldref.Signature == fld.Signature)
{
return true;
}
2005-01-05 15:32:00 +03:00
}
2005-06-01 13:49:30 +04:00
return false;
2005-01-05 15:32:00 +03:00
}
2005-06-01 13:49:30 +04:00
internal ConstantPoolItemFieldref GetFieldref(int index)
{
return (ConstantPoolItemFieldref)constantpool[index];
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
// NOTE this returns an MI, because it used for both normal methods and interface methods
internal ConstantPoolItemMI GetMethodref(int index)
{
return (ConstantPoolItemMI)constantpool[index];
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
private ConstantPoolItem GetConstantPoolItem(int index)
{
return constantpool[index];
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
internal string GetConstantPoolClass(int index)
{
return ((ConstantPoolItemClass)constantpool[index]).Name;
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
internal TypeWrapper GetConstantPoolClassType(int index)
{
return ((ConstantPoolItemClass)constantpool[index]).GetClassType();
}
2003-01-06 16:56:37 +03:00
2005-06-01 13:49:30 +04:00
internal string GetConstantPoolUtf8String(int index)
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
string s = utf8_cp[index];
if(s == null)
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
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);
}
2004-12-21 13:26:51 +03:00
}
2005-06-01 13:49:30 +04:00
return s;
2004-12-21 13:26:51 +03:00
}
2003-12-20 01:19:18 +03:00
2005-06-01 13:49:30 +04:00
internal ConstantType GetConstantPoolConstantType(int index)
{
return constantpool[index].GetConstantType();
}
2003-12-20 01:19:18 +03:00
2005-06-01 13:49:30 +04:00
internal double GetConstantPoolConstantDouble(int index)
{
return ((ConstantPoolItemDouble)constantpool[index]).Value;
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
internal float GetConstantPoolConstantFloat(int index)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
return ((ConstantPoolItemFloat)constantpool[index]).Value;
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal int GetConstantPoolConstantInteger(int index)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
return ((ConstantPoolItemInteger)constantpool[index]).Value;
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal long GetConstantPoolConstantLong(int index)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
return ((ConstantPoolItemLong)constantpool[index]).Value;
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal string GetConstantPoolConstantString(int index)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
return ((ConstantPoolItemString)constantpool[index]).Value;
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal string Name
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return GetConstantPoolClass(this_class);
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal string SuperClass
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return GetConstantPoolClass(super_class);
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal Field[] Fields
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return fields;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal Method[] Methods
2003-11-17 15:01:50 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return methods;
}
2003-11-17 15:01:50 +03:00
}
2005-06-01 13:49:30 +04:00
internal ConstantPoolItemClass[] Interfaces
{
get
{
return interfaces;
}
}
2003-02-15 19:18:11 +03:00
2005-06-01 13:49:30 +04:00
internal string SourceFileAttribute
2003-02-15 19:18:11 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return sourceFile;
}
2003-02-15 19:18:11 +03:00
}
2005-11-01 17:01:42 +03:00
internal object[] Annotations
{
get
{
return annotations;
}
}
2005-10-01 15:16:11 +04:00
internal string GenericSignature
{
get
{
return signature;
}
}
internal string[] EnclosingMethod
{
get
{
return enclosingMethod;
}
}
2005-06-01 13:49:30 +04:00
internal string IKVMAssemblyAttribute
{
get
{
return ikvmAssembly;
}
}
2003-12-20 01:19:18 +03:00
2005-06-01 13:49:30 +04:00
internal bool DeprecatedAttribute
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return deprecated;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal struct InnerClass
2003-01-02 18:44:17 +03:00
{
2005-06-01 13:49:30 +04:00
internal ushort innerClass; // ConstantPoolItemClass
internal ushort outerClass; // ConstantPoolItemClass
internal ushort name; // ConstantPoolItemUtf8
internal Modifiers accessFlags;
2003-01-02 18:44:17 +03:00
}
2005-06-01 13:49:30 +04:00
internal InnerClass[] InnerClasses
2003-12-20 01:19:18 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return innerClasses;
}
2003-12-20 01:19:18 +03:00
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
internal enum ConstantType
{
Integer,
Long,
Float,
Double,
String,
Class
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
internal abstract class ConstantPoolItem
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
internal virtual void Resolve(ClassFile classFile)
{
}
internal virtual void Link(TypeWrapper thisType, Hashtable classCache)
{
}
internal virtual ConstantType GetConstantType()
{
throw new InvalidOperationException();
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal sealed class ConstantPoolItemClass : ConstantPoolItem
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
private ushort name_index;
private string name;
private TypeWrapper typeWrapper;
internal ConstantPoolItemClass(BigEndianBinaryReader br)
{
name_index = br.ReadUInt16();
}
internal override void Resolve(ClassFile classFile)
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
name = classFile.GetConstantPoolUtf8String(name_index);
if(name.Length > 0)
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
char prev = name[0];
if(Char.IsLetter(prev) || prev == '$' || prev == '_' || prev == '[')
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
int skip = 1;
int end = name.Length;
if(prev == '[')
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
// TODO optimize this
if(!IsValidFieldSig(name))
{
goto barf;
}
while(name[skip] == '[')
{
skip++;
}
if(name.EndsWith(";"))
{
end--;
}
2004-12-21 13:26:51 +03:00
}
2005-06-01 13:49:30 +04:00
for(int i = skip; i < end; i++)
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
char c = name[i];
if(!Char.IsLetterOrDigit(c) && c != '$' && c != '_' && (c != '/' || prev == '/'))
{
goto barf;
}
prev = c;
2004-12-21 13:26:51 +03:00
}
2005-06-01 13:49:30 +04:00
name = String.Intern(name.Replace('/', '.'));
return;
2004-12-21 13:26:51 +03:00
}
}
2005-06-01 13:49:30 +04:00
barf:
throw new ClassFormatError("Invalid class name \"{0}\"", name);
2004-12-21 13:26:51 +03:00
}
2004-08-30 19:56:23 +04:00
2005-06-01 13:49:30 +04:00
internal override void Link(TypeWrapper thisType, Hashtable classCache)
2004-08-30 19:56:23 +04:00
{
2005-06-01 13:49:30 +04:00
if(typeWrapper == null)
{
typeWrapper = LoadClassHelper(thisType.GetClassLoader(), classCache, name);
}
2004-08-30 19:56:23 +04:00
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
internal string Name
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return name;
}
2002-12-18 19:00:25 +03:00
}
2004-03-16 20:10:09 +03:00
2005-06-01 13:49:30 +04:00
internal TypeWrapper GetClassType()
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
return typeWrapper;
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
internal override ConstantType GetConstantType()
2003-12-24 14:51:41 +03:00
{
2005-06-01 13:49:30 +04:00
return ConstantType.Class;
2003-12-24 14:51:41 +03:00
}
2003-01-06 16:56:37 +03:00
}
2005-06-01 13:49:30 +04:00
private static TypeWrapper LoadClassHelper(ClassLoaderWrapper classLoader, Hashtable classCache, string name)
2003-01-06 16:56:37 +03:00
{
2005-06-01 13:49:30 +04:00
try
2003-03-17 17:02:46 +03:00
{
2005-06-01 13:49:30 +04:00
TypeWrapper wrapper = (TypeWrapper)classCache[name];
if(wrapper != null)
2003-06-10 17:28:47 +04:00
{
2005-06-01 13:49:30 +04:00
return wrapper;
}
wrapper = classLoader.LoadClassByDottedNameFast(name);
if(wrapper == null)
{
Tracer.Error(Tracer.ClassLoading, "Class not found: {0}", name);
wrapper = new UnloadableTypeWrapper(name);
}
return wrapper;
}
2005-08-24 15:35:00 +04:00
catch(RetargetableJavaException x)
2005-06-01 13:49:30 +04:00
{
if(!JVM.IsStaticCompiler && Tracer.ClassLoading.TraceError)
{
object cl = classLoader.GetJavaClassLoader();
if(cl != null)
2003-10-17 12:08:31 +04:00
{
2005-06-01 13:49:30 +04:00
System.Text.StringBuilder sb = new System.Text.StringBuilder();
Type type = cl.GetType();
while(type.FullName != "java.lang.ClassLoader")
2004-10-19 17:43:55 +04:00
{
2005-06-01 13:49:30 +04:00
type = type.BaseType;
}
System.Reflection.FieldInfo parentField = type.GetField("parent", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
if(parentField != null)
{
string sep = "";
while(cl != null)
{
sb.Append(sep).Append(cl);
sep = " -> ";
cl = parentField.GetValue(cl);
}
2004-10-19 17:43:55 +04:00
}
2005-06-01 13:49:30 +04:00
Tracer.Error(Tracer.ClassLoading, "ClassLoader chain: {0}", sb);
2003-10-17 12:08:31 +04:00
}
2005-08-24 15:35:00 +04:00
Exception m = IKVM.Runtime.Util.MapException(x.ToJava());
Tracer.Error(Tracer.ClassLoading, m.ToString() + Environment.NewLine + m.StackTrace);
2003-06-10 17:28:47 +04:00
}
2005-06-01 13:49:30 +04:00
return new UnloadableTypeWrapper(name);
2003-03-17 17:02:46 +03:00
}
2003-01-06 16:56:37 +03:00
}
2005-06-01 13:49:30 +04:00
private static TypeWrapper SigDecoderWrapper(ClassLoaderWrapper classLoader, Hashtable classCache, ref int index, string sig)
2004-03-20 16:25:08 +03:00
{
2005-06-01 13:49:30 +04:00
switch(sig[index++])
{
case 'B':
return PrimitiveTypeWrapper.BYTE;
case 'C':
return PrimitiveTypeWrapper.CHAR;
case 'D':
return PrimitiveTypeWrapper.DOUBLE;
case 'F':
return PrimitiveTypeWrapper.FLOAT;
case 'I':
return PrimitiveTypeWrapper.INT;
case 'J':
return PrimitiveTypeWrapper.LONG;
case 'L':
2004-03-20 16:25:08 +03:00
{
2005-06-01 13:49:30 +04:00
int pos = index;
index = sig.IndexOf(';', index) + 1;
return LoadClassHelper(classLoader, classCache, sig.Substring(pos, index - pos - 1));
}
case 'S':
return PrimitiveTypeWrapper.SHORT;
case 'Z':
return PrimitiveTypeWrapper.BOOLEAN;
case 'V':
return PrimitiveTypeWrapper.VOID;
case '[':
{
// TODO this can be optimized
string array = "[";
while(sig[index] == '[')
2004-03-20 16:25:08 +03:00
{
2005-06-01 13:49:30 +04:00
index++;
array += "[";
}
switch(sig[index])
{
case 'L':
{
int pos = index;
index = sig.IndexOf(';', index) + 1;
return LoadClassHelper(classLoader, classCache, array + sig.Substring(pos, index - pos));
}
case 'B':
case 'C':
case 'D':
case 'F':
case 'I':
case 'J':
case 'S':
case 'Z':
return LoadClassHelper(classLoader, classCache, array + sig[index++]);
default:
// TODO this should never happen, because ClassFile should validate the descriptors
throw new InvalidOperationException(sig.Substring(index));
2004-03-20 16:25:08 +03:00
}
}
2005-06-01 13:49:30 +04:00
default:
// TODO this should never happen, because ClassFile should validate the descriptors
throw new InvalidOperationException(sig.Substring(index));
2004-03-20 16:25:08 +03:00
}
}
2005-06-01 13:49:30 +04:00
internal static TypeWrapper[] ArgTypeWrapperListFromSig(ClassLoaderWrapper classLoader, Hashtable classCache, string sig)
2004-03-20 16:25:08 +03:00
{
2005-06-01 13:49:30 +04:00
if(sig[1] == ')')
{
return TypeWrapper.EmptyArray;
}
ArrayList list = new ArrayList();
for(int i = 1; sig[i] != ')';)
{
list.Add(SigDecoderWrapper(classLoader, classCache, ref i, sig));
}
TypeWrapper[] types = new TypeWrapper[list.Count];
list.CopyTo(types);
return types;
2004-03-20 16:25:08 +03:00
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
internal static TypeWrapper FieldTypeWrapperFromSig(ClassLoaderWrapper classLoader, Hashtable classCache, string sig)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
int index = 0;
return SigDecoderWrapper(classLoader, classCache, ref index, sig);
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal static TypeWrapper RetTypeWrapperFromSig(ClassLoaderWrapper classLoader, Hashtable classCache, string sig)
2003-12-20 01:19:18 +03:00
{
2005-06-01 13:49:30 +04:00
int index = sig.IndexOf(')') + 1;
return SigDecoderWrapper(classLoader, classCache, ref index, sig);
2003-12-20 01:19:18 +03:00
}
2005-06-01 13:49:30 +04:00
private sealed class ConstantPoolItemDouble : ConstantPoolItem
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
private double d;
internal ConstantPoolItemDouble(BigEndianBinaryReader br)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
d = br.ReadDouble();
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal override ConstantType GetConstantType()
{
return ConstantType.Double;
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
internal double Value
{
get
{
return d;
}
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal abstract class ConstantPoolItemFMI : ConstantPoolItem
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
private ushort class_index;
private ushort name_and_type_index;
private ConstantPoolItemClass clazz;
private string name;
private string descriptor;
internal ConstantPoolItemFMI(BigEndianBinaryReader br)
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
class_index = br.ReadUInt16();
name_and_type_index = br.ReadUInt16();
2004-12-21 13:26:51 +03:00
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
internal override void Resolve(ClassFile classFile)
{
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(name_and_type.name_index));
descriptor = classFile.GetConstantPoolUtf8String(name_and_type.descriptor_index);
Validate(name, descriptor);
descriptor = String.Intern(descriptor.Replace('/', '.'));
}
2004-12-21 13:26:51 +03:00
2005-06-01 13:49:30 +04:00
protected abstract void Validate(string name, string descriptor);
2004-08-30 19:56:23 +04:00
2005-06-01 13:49:30 +04:00
internal override void Link(TypeWrapper thisType, Hashtable classCache)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
clazz.Link(thisType, classCache);
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal string Name
{
get
{
return name;
}
}
internal string Signature
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return descriptor;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal string Class
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return clazz.Name;
}
2002-12-18 19:00:25 +03:00
}
2003-01-02 18:44:17 +03:00
2005-06-01 13:49:30 +04:00
internal TypeWrapper GetClassType()
{
return clazz.GetClassType();
}
2003-01-02 18:44:17 +03:00
}
2004-08-17 13:05:21 +04:00
2005-06-01 13:49:30 +04:00
internal sealed class ConstantPoolItemFieldref : ConstantPoolItemFMI
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
private FieldWrapper field;
private TypeWrapper fieldTypeWrapper;
2004-08-17 13:05:21 +04:00
2005-06-01 13:49:30 +04:00
internal ConstantPoolItemFieldref(BigEndianBinaryReader br) : base(br)
2004-12-21 13:26:51 +03:00
{
}
2005-06-01 13:49:30 +04:00
protected override void Validate(string name, string descriptor)
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
if(!IsValidFieldSig(descriptor))
{
throw new ClassFormatError("Invalid field signature \"{0}\"", descriptor);
}
2005-11-01 17:01:42 +03:00
if(!IsValidFieldName(name))
2005-06-01 13:49:30 +04:00
{
throw new ClassFormatError("Invalid field name \"{0}\"", name);
}
2004-12-21 13:26:51 +03:00
}
2005-06-01 13:49:30 +04:00
internal TypeWrapper GetFieldType()
{
return fieldTypeWrapper;
}
2004-08-17 13:05:21 +04:00
2005-06-01 13:49:30 +04:00
internal override void Link(TypeWrapper thisType, Hashtable classCache)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
base.Link(thisType, classCache);
if(fieldTypeWrapper == null)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
ClassLoaderWrapper classLoader = thisType.GetClassLoader();
fieldTypeWrapper = FieldTypeWrapperFromSig(classLoader, classCache, this.Signature);
TypeWrapper wrapper = GetClassType();
if(!wrapper.IsUnloadable)
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
field = wrapper.GetFieldWrapper(Name, Signature);
if(field != null)
2005-02-02 18:11:26 +03:00
{
2005-06-01 13:49:30 +04:00
bool ok = false;
try
{
field.Link();
ok = true;
}
finally
2005-02-02 18:11:26 +03:00
{
2005-06-01 13:49:30 +04:00
if(!ok)
{
fieldTypeWrapper = null;
}
2005-02-02 18:11:26 +03:00
}
}
2004-12-21 13:26:51 +03:00
}
2004-08-17 13:05:21 +04:00
}
}
2005-06-01 13:49:30 +04:00
internal FieldWrapper GetField()
{
return field;
}
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
internal class ConstantPoolItemMI : ConstantPoolItemFMI
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
private TypeWrapper[] argTypeWrappers;
private TypeWrapper retTypeWrapper;
protected MethodWrapper method;
protected MethodWrapper invokespecialMethod;
2003-01-02 18:44:17 +03:00
2005-06-01 13:49:30 +04:00
internal ConstantPoolItemMI(BigEndianBinaryReader br) : base(br)
2004-12-21 13:26:51 +03:00
{
}
2005-06-01 13:49:30 +04:00
protected override void Validate(string name, string descriptor)
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
if(!IsValidMethodSig(descriptor))
2004-12-21 13:26:51 +03:00
{
throw new ClassFormatError("Method {0} has invalid signature {1}", name, descriptor);
}
2005-06-01 13:49:30 +04:00
if(name == "<init>" || name == "<clinit>")
{
if(!descriptor.EndsWith("V"))
{
throw new ClassFormatError("Method {0} has invalid signature {1}", name, descriptor);
}
}
2005-11-01 17:01:42 +03:00
else if(!IsValidMethodName(name))
2005-06-01 13:49:30 +04:00
{
throw new ClassFormatError("Invalid method name \"{0}\"", name);
}
2004-12-21 13:26:51 +03:00
}
2005-06-01 13:49:30 +04:00
internal override void Link(TypeWrapper thisType, Hashtable classCache)
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
base.Link(thisType, classCache);
if(argTypeWrappers == null)
{
ClassLoaderWrapper classLoader = thisType.GetClassLoader();
argTypeWrappers = ArgTypeWrapperListFromSig(classLoader, classCache, this.Signature);
retTypeWrapper = RetTypeWrapperFromSig(classLoader, classCache, this.Signature);
}
2004-12-21 13:26:51 +03:00
}
2005-06-01 13:49:30 +04:00
internal TypeWrapper[] GetArgTypes()
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
return argTypeWrappers;
2004-12-21 13:26:51 +03:00
}
2003-01-02 18:44:17 +03:00
2005-06-01 13:49:30 +04:00
internal TypeWrapper GetRetType()
{
return retTypeWrapper;
}
2003-01-06 16:56:37 +03:00
2005-06-01 13:49:30 +04:00
internal MethodWrapper GetMethod()
{
return method;
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
internal MethodWrapper GetMethodForInvokespecial()
{
return invokespecialMethod != null ? invokespecialMethod : method;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal sealed class ConstantPoolItemMethodref : ConstantPoolItemMI
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
internal ConstantPoolItemMethodref(BigEndianBinaryReader br) : base(br)
{
}
2004-08-17 13:05:21 +04:00
2005-06-01 13:49:30 +04:00
internal override void Link(TypeWrapper thisType, Hashtable classCache)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
base.Link(thisType, classCache);
TypeWrapper wrapper = GetClassType();
if(!wrapper.IsUnloadable)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
method = wrapper.GetMethodWrapper(Name, Signature, Name != "<init>");
if(method != null)
{
method.Link();
}
if(Name != "<init>" &&
(thisType.Modifiers & (Modifiers.Interface | Modifiers.Super)) == Modifiers.Super &&
thisType != wrapper && thisType.IsSubTypeOf(wrapper))
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
invokespecialMethod = thisType.BaseTypeWrapper.GetMethodWrapper(Name, Signature, true);
if(invokespecialMethod != null)
{
invokespecialMethod.Link();
}
2004-08-17 13:05:21 +04:00
}
}
}
}
2005-06-01 13:49:30 +04:00
internal sealed class ConstantPoolItemInterfaceMethodref : ConstantPoolItemMI
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
internal ConstantPoolItemInterfaceMethodref(BigEndianBinaryReader br) : base(br)
2004-08-17 13:05:21 +04:00
{
}
2005-06-01 13:49:30 +04:00
private static MethodWrapper GetInterfaceMethod(TypeWrapper wrapper, string name, string sig)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
MethodWrapper method = wrapper.GetMethodWrapper(name, sig, false);
2004-08-17 13:05:21 +04:00
if(method != null)
{
return method;
}
2005-06-01 13:49:30 +04:00
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;
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
internal override void Link(TypeWrapper thisType, Hashtable classCache)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
base.Link(thisType, classCache);
TypeWrapper wrapper = GetClassType();
if(!wrapper.IsUnloadable)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
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();
}
2004-08-17 13:05:21 +04:00
}
}
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
private sealed class ConstantPoolItemFloat : ConstantPoolItem
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
private float v;
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
internal ConstantPoolItemFloat(BigEndianBinaryReader br)
{
v = br.ReadSingle();
}
internal override ConstantType GetConstantType()
{
return ConstantType.Float;
}
internal float Value
{
get
{
return v;
}
}
2003-12-20 01:19:18 +03:00
}
2005-06-01 13:49:30 +04:00
private sealed class ConstantPoolItemInteger : ConstantPoolItem
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
private int v;
internal ConstantPoolItemInteger(BigEndianBinaryReader br)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
v = br.ReadInt32();
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal override ConstantType GetConstantType()
{
return ConstantType.Integer;
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
internal int Value
{
get
{
return v;
}
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
private sealed class ConstantPoolItemLong : ConstantPoolItem
2003-12-20 01:19:18 +03:00
{
2005-06-01 13:49:30 +04:00
private long l;
2003-12-20 01:19:18 +03:00
2005-06-01 13:49:30 +04:00
internal ConstantPoolItemLong(BigEndianBinaryReader br)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
l = br.ReadInt64();
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal override ConstantType GetConstantType()
{
return ConstantType.Long;
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
internal long Value
{
get
{
return l;
}
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal sealed class ConstantPoolItemNameAndType : ConstantPoolItem
2003-12-20 01:19:18 +03:00
{
2005-06-01 13:49:30 +04:00
internal ushort name_index;
internal ushort descriptor_index;
2003-12-20 01:19:18 +03:00
2005-06-01 13:49:30 +04:00
internal ConstantPoolItemNameAndType(BigEndianBinaryReader br)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
name_index = br.ReadUInt16();
descriptor_index = br.ReadUInt16();
2002-12-18 19:00:25 +03:00
}
}
2005-06-01 13:49:30 +04:00
private sealed class ConstantPoolItemString : ConstantPoolItem
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
private ushort string_index;
private string s;
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
internal ConstantPoolItemString(BigEndianBinaryReader br)
{
string_index = br.ReadUInt16();
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
internal override void Resolve(ClassFile classFile)
{
s = classFile.GetConstantPoolUtf8String(string_index);
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
internal override ConstantType GetConstantType()
{
return ConstantType.String;
}
internal string Value
{
get
{
return s;
}
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal enum Constant
2003-12-20 01:19:18 +03:00
{
2005-06-01 13:49:30 +04:00
Utf8 = 1,
Integer = 3,
Float = 4,
Long = 5,
Double = 6,
Class = 7,
String = 8,
Fieldref = 9,
Methodref = 10,
InterfaceMethodref = 11,
NameAndType = 12
2003-12-20 01:19:18 +03:00
}
2005-06-01 13:49:30 +04:00
internal abstract class FieldOrMethod
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
protected Modifiers access_flags;
private string name;
private string descriptor;
protected bool deprecated;
2005-10-01 15:16:11 +04:00
protected string signature;
2005-11-01 17:01:42 +03:00
protected object[] annotations;
2005-06-01 13:49:30 +04:00
internal FieldOrMethod(ClassFile classFile, BigEndianBinaryReader br)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
access_flags = (Modifiers)br.ReadUInt16();
name = String.Intern(classFile.GetConstantPoolUtf8String(br.ReadUInt16()));
descriptor = classFile.GetConstantPoolUtf8String(br.ReadUInt16());
ValidateSig(classFile, descriptor);
descriptor = String.Intern(descriptor.Replace('/', '.'));
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
protected abstract void ValidateSig(ClassFile classFile, string descriptor);
2004-12-21 13:26:51 +03:00
2005-06-01 13:49:30 +04:00
internal string Name
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return name;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal string Signature
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return descriptor;
}
2003-01-06 16:56:37 +03:00
}
2005-11-01 17:01:42 +03:00
internal object[] Annotations
{
get
{
return annotations;
}
}
2005-10-01 15:16:11 +04:00
internal string GenericSignature
{
get
{
return signature;
}
}
2005-06-01 13:49:30 +04:00
internal Modifiers Modifiers
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return (Modifiers)access_flags;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal bool IsAbstract
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return (access_flags & Modifiers.Abstract) != 0;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal bool IsFinal
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return (access_flags & Modifiers.Final) != 0;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal bool IsPublic
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return (access_flags & Modifiers.Public) != 0;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal bool IsPrivate
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return (access_flags & Modifiers.Private) != 0;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal bool IsProtected
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return (access_flags & Modifiers.Protected) != 0;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal bool IsStatic
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return (access_flags & Modifiers.Static) != 0;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal bool IsSynchronized
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return (access_flags & Modifiers.Synchronized) != 0;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal bool IsVolatile
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return (access_flags & Modifiers.Volatile) != 0;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal bool IsTransient
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return (access_flags & Modifiers.Transient) != 0;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal bool IsNative
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return (access_flags & Modifiers.Native) != 0;
}
2002-12-18 19:00:25 +03:00
}
2005-11-01 17:01:42 +03:00
internal bool IsEnum
{
get
{
return (access_flags & Modifiers.Enum) != 0;
}
}
2005-06-01 13:49:30 +04:00
internal bool DeprecatedAttribute
2003-11-17 15:01:50 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return deprecated;
}
2003-11-17 15:01:50 +03:00
}
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
internal sealed class Field : FieldOrMethod
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
private object constantValue;
internal Field(ClassFile classFile, BigEndianBinaryReader br) : base(classFile, br)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
if((IsPrivate && IsPublic) || (IsPrivate && IsProtected) || (IsPublic && IsProtected)
|| (IsFinal && IsVolatile)
|| (classFile.IsInterface && (!IsPublic || !IsStatic || !IsFinal || IsTransient)))
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
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(br.ReadUInt16()))
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
case "Deprecated":
deprecated = true;
br.Skip(br.ReadUInt32());
break;
case "ConstantValue":
2004-08-30 19:56:23 +04:00
{
2005-06-01 13:49:30 +04:00
if(br.ReadUInt32() != 2)
2004-08-30 19:56:23 +04:00
{
2005-06-01 13:49:30 +04:00
throw new ClassFormatError("Invalid ConstantValue attribute length");
2004-08-30 19:56:23 +04:00
}
2005-06-01 13:49:30 +04:00
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;
2004-08-30 19:56:23 +04:00
}
2005-11-01 17:01:42 +03:00
#if GENERICS
2005-10-01 15:16:11 +04:00
case "Signature":
if(classFile.majorVersion < 49)
{
goto default;
}
if(br.ReadUInt32() != 2)
{
throw new ClassFormatError("Signature attribute has incorrect length");
}
signature = classFile.GetConstantPoolUtf8String(br.ReadUInt16());
break;
2005-11-01 17:01:42 +03:00
case "RuntimeVisibleAnnotations":
if(classFile.majorVersion < 49)
{
goto default;
}
annotations = ReadAnnotations(br, classFile);
break;
#endif
2005-06-01 13:49:30 +04:00
default:
br.Skip(br.ReadUInt32());
break;
2002-12-18 19:00:25 +03:00
}
}
}
2005-06-01 13:49:30 +04:00
protected override void ValidateSig(ClassFile classFile, string descriptor)
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
if(!IsValidFieldSig(descriptor))
{
throw new ClassFormatError("{0} (Field \"{1}\" has invalid signature \"{2}\")", classFile.Name, this.Name, descriptor);
}
2004-12-21 13:26:51 +03:00
}
2005-06-01 13:49:30 +04:00
internal object ConstantValue
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return constantValue;
}
2002-12-18 19:00:25 +03:00
}
}
2005-06-01 13:49:30 +04:00
internal sealed class Method : FieldOrMethod
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
private Code code;
private string[] exceptions;
2005-11-01 17:01:42 +03:00
private object annotationDefault;
2005-06-01 13:49:30 +04:00
internal Method(ClassFile classFile, BigEndianBinaryReader br) : base(classFile, br)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
// vmspec 4.6 says that all flags, except ACC_STRICT are ignored on <clinit>
if(Name == "<clinit>" && Signature == "()V")
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
access_flags &= Modifiers.Strictfp;
access_flags |= (Modifiers.Static | Modifiers.Private);
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
else
2004-08-30 19:56:23 +04:00
{
2005-06-01 13:49:30 +04:00
// 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((Name == "<init>" && (IsStatic || IsSynchronized || IsFinal || IsAbstract || IsNative))
|| (IsPrivate && IsPublic) || (IsPrivate && IsProtected) || (IsPublic && IsProtected)
|| (IsAbstract && (IsFinal || IsNative || IsPrivate || IsStatic || IsSynchronized))
|| (classFile.IsInterface && (!IsPublic || !IsAbstract)))
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
throw new ClassFormatError("{0} (Illegal method modifiers: 0x{1:X})", classFile.Name, access_flags);
2004-12-21 13:26:51 +03:00
}
2005-06-01 13:49:30 +04:00
}
int attributes_count = br.ReadUInt16();
for(int i = 0; i < attributes_count; i++)
{
switch(classFile.GetConstantPoolUtf8String(br.ReadUInt16()))
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
case "Deprecated":
deprecated = true;
br.Skip(br.ReadUInt32());
break;
case "Code":
2004-08-30 19:56:23 +04:00
{
2005-06-01 13:49:30 +04:00
if(!code.IsEmpty)
{
throw new ClassFormatError("{0} (Duplicate Code attribute)", classFile.Name);
}
BigEndianBinaryReader rdr = br.Section(br.ReadUInt32());
code.Read(classFile, this, rdr);
if(!rdr.IsAtEnd)
{
throw new ClassFormatError("{0} (Code attribute has wrong length)", classFile.Name);
}
break;
2004-08-30 19:56:23 +04:00
}
2005-06-01 13:49:30 +04:00
case "Exceptions":
2004-08-30 19:56:23 +04:00
{
2005-06-01 13:49:30 +04:00
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;
2004-08-30 19:56:23 +04:00
}
2005-11-01 17:01:42 +03:00
#if GENERICS
2005-10-01 15:16:11 +04:00
case "Signature":
if(classFile.majorVersion < 49)
{
goto default;
}
if(br.ReadUInt32() != 2)
{
throw new ClassFormatError("Signature attribute has incorrect length");
}
signature = classFile.GetConstantPoolUtf8String(br.ReadUInt16());
break;
2005-11-01 17:01:42 +03:00
case "RuntimeVisibleAnnotations":
if(classFile.majorVersion < 49)
{
goto default;
}
annotations = ReadAnnotations(br, classFile);
break;
case "AnnotationDefault":
{
if(classFile.majorVersion < 49)
{
goto default;
}
BigEndianBinaryReader rdr = br.Section(br.ReadUInt32());
annotationDefault = ReadAnnotationElementValue(rdr, classFile);
if(!rdr.IsAtEnd)
{
throw new ClassFormatError("{0} (AnnotationDefault attribute has wrong length)", classFile.Name);
}
break;
}
#endif
2005-06-01 13:49:30 +04:00
default:
br.Skip(br.ReadUInt32());
break;
}
}
if(IsAbstract || IsNative)
{
if(!code.IsEmpty)
{
throw new ClassFormatError("Abstract or native method cannot have a Code attribute");
}
}
else
{
if(code.IsEmpty)
{
if(this.Name == "<clinit>")
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
code.verifyError = string.Format("Class {0}, method {1} signature {2}: No Code attribute", classFile.Name, this.Name, this.Signature);
return;
2004-12-21 13:26:51 +03:00
}
2005-06-01 13:49:30 +04:00
throw new ClassFormatError("Method has no Code attribute");
2004-12-21 13:26:51 +03:00
}
2004-08-30 19:56:23 +04:00
}
}
2005-06-01 13:49:30 +04:00
protected override void ValidateSig(ClassFile classFile, string descriptor)
2004-08-30 19:56:23 +04:00
{
2005-06-01 13:49:30 +04:00
if(!IsValidMethodSig(descriptor))
2004-08-30 19:56:23 +04:00
{
2005-06-01 13:49:30 +04:00
throw new ClassFormatError("{0} (Method \"{1}\" has invalid signature \"{2}\")", classFile.Name, this.Name, descriptor);
2004-08-30 19:56:23 +04:00
}
}
2005-06-01 13:49:30 +04:00
internal bool IsStrictfp
2004-08-30 19:56:23 +04:00
{
2005-06-01 13:49:30 +04:00
get
2004-08-30 19:56:23 +04:00
{
2005-06-01 13:49:30 +04:00
return (access_flags & Modifiers.Strictfp) != 0;
2004-08-30 19:56:23 +04:00
}
}
2004-12-21 13:26:51 +03:00
2005-06-01 13:49:30 +04:00
// Is this the <clinit>()V method?
internal bool IsClassInitializer
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return Name == "<clinit>" && Signature == "()V";
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal string[] ExceptionsAttribute
2003-08-13 19:00:41 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return exceptions;
}
2003-08-13 19:00:41 +04:00
}
2005-11-01 17:01:42 +03:00
internal object[][] ParameterAnnotations
{
get
{
// TODO
return null;
}
}
internal object AnnotationDefault
{
get
{
return annotationDefault;
}
}
2005-06-01 13:49:30 +04:00
internal string VerifyError
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return code.verifyError;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
// maps argument 'slot' (as encoded in the xload/xstore instructions) into the ordinal
internal int[] ArgMap
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return code.argmap;
}
2004-12-21 13:26:51 +03:00
}
2005-06-01 13:49:30 +04:00
internal int MaxStack
2003-11-17 15:01:50 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return code.max_stack;
}
2003-11-17 15:01:50 +03:00
}
2005-06-01 13:49:30 +04:00
internal int MaxLocals
2004-08-30 19:56:23 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return code.max_locals;
}
2004-08-30 19:56:23 +04:00
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
internal Instruction[] Instructions
2004-08-30 19:56:23 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return code.instructions;
}
2004-08-30 19:56:23 +04:00
}
2005-06-01 13:49:30 +04:00
// maps a PC to an index in the Instruction[], invalid PCs return -1
internal int[] PcIndexMap
2004-08-30 19:56:23 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return code.pcIndexMap;
}
2004-08-30 19:56:23 +04:00
}
2005-06-01 13:49:30 +04:00
internal ExceptionTableEntry[] ExceptionTable
2004-08-30 19:56:23 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return code.exception_table;
}
2004-08-30 19:56:23 +04:00
}
2005-06-01 13:49:30 +04:00
internal LineNumberTableEntry[] LineNumberTableAttribute
2004-08-30 19:56:23 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return code.lineNumberTable;
}
2004-08-30 19:56:23 +04:00
}
2005-06-01 13:49:30 +04:00
internal LocalVariableTableEntry[] LocalVariableTableAttribute
2004-08-30 19:56:23 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return code.localVariableTable;
}
2004-08-30 19:56:23 +04:00
}
2005-06-01 13:49:30 +04:00
private struct Code
2004-08-30 19:56:23 +04:00
{
2005-06-01 13:49:30 +04:00
internal string verifyError;
internal ushort max_stack;
internal ushort max_locals;
internal Instruction[] instructions;
internal int[] pcIndexMap;
internal ExceptionTableEntry[] exception_table;
internal int[] argmap;
internal LineNumberTableEntry[] lineNumberTable;
internal LocalVariableTableEntry[] localVariableTable;
2004-08-30 19:56:23 +04:00
2005-06-01 13:49:30 +04:00
internal void Read(ClassFile classFile, Method method, BigEndianBinaryReader br)
{
max_stack = br.ReadUInt16();
max_locals = br.ReadUInt16();
uint code_length = br.ReadUInt32();
if(code_length > 65536)
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
throw new ClassFormatError("{0} (Invalid Code length {1})", classFile.Name, code_length);
2004-12-21 13:26:51 +03:00
}
2005-06-01 13:49:30 +04:00
Instruction[] instructions = new Instruction[code_length + 1];
int basePosition = br.Position;
int instructionIndex = 0;
try
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
BigEndianBinaryReader rdr = br.Section(code_length);
while(!rdr.IsAtEnd)
{
instructions[instructionIndex++].Read((ushort)(rdr.Position - basePosition), rdr);
}
// 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);
ushort exception_table_length = br.ReadUInt16();
exception_table = new ExceptionTableEntry[exception_table_length];
for(int i = 0; i < exception_table_length; i++)
{
exception_table[i] = new ExceptionTableEntry();
exception_table[i].start_pc = br.ReadUInt16();
exception_table[i].end_pc = br.ReadUInt16();
exception_table[i].handler_pc = br.ReadUInt16();
exception_table[i].catch_type = br.ReadUInt16();
exception_table[i].ordinal = i;
}
ushort attributes_count = br.ReadUInt16();
for(int i = 0; i < attributes_count; i++)
{
switch(classFile.GetConstantPoolUtf8String(br.ReadUInt16()))
{
case "LineNumberTable":
if(JVM.NoStackTraceInfo)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
br.Skip(br.ReadUInt32());
}
else
{
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)
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
throw new ClassFormatError("{0} (LineNumberTable attribute has wrong length)", classFile.Name);
2004-12-21 13:26:51 +03:00
}
}
2005-06-01 13:49:30 +04:00
break;
case "LocalVariableTable":
if(JVM.Debug || JVM.IsStaticCompiler)
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
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(rdr.ReadUInt16());
localVariableTable[j].descriptor = classFile.GetConstantPoolUtf8String(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)
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
else
2004-08-30 19:56:23 +04:00
{
2005-06-01 13:49:30 +04:00
br.Skip(br.ReadUInt32());
2004-08-30 19:56:23 +04:00
}
2005-06-01 13:49:30 +04:00
break;
default:
2004-08-30 19:56:23 +04:00
br.Skip(br.ReadUInt32());
2005-06-01 13:49:30 +04:00
break;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
// build the pcIndexMap
pcIndexMap = new int[this.instructions[instructionIndex - 1].PC + 1];
for(int i = 0; i < pcIndexMap.Length; i++)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
pcIndexMap[i] = -1;
}
for(int i = 0; i < instructionIndex - 1; i++)
{
pcIndexMap[this.instructions[i].PC] = i;
}
// build the argmap
string sig = method.Signature;
ArrayList args = new ArrayList();
int pos = 0;
if(!method.IsStatic)
{
args.Add(pos++);
}
for(int i = 1; sig[i] != ')'; i++)
{
args.Add(pos++);
switch(sig[i])
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
case 'L':
2004-08-30 19:56:23 +04:00
i = sig.IndexOf(';', i);
2005-06-01 13:49:30 +04:00
break;
case 'D':
case 'J':
args.Add(-1);
break;
case '[':
{
while(sig[i] == '[')
{
i++;
}
if(sig[i] == 'L')
{
i = sig.IndexOf(';', i);
}
break;
2004-08-30 19:56:23 +04:00
}
2002-12-18 19:00:25 +03:00
}
}
2005-06-01 13:49:30 +04:00
argmap = new int[args.Count];
args.CopyTo(argmap);
if(args.Count > max_locals)
{
throw new ClassFormatError("{0} (Arguments can't fit into locals)", classFile.Name);
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal bool IsEmpty
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return instructions == null;
}
2002-12-18 19:00:25 +03:00
}
}
2005-06-01 13:49:30 +04:00
internal sealed class ExceptionTableEntry
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
internal ushort start_pc;
internal ushort end_pc;
internal ushort handler_pc;
internal ushort catch_type;
internal int ordinal;
2002-12-18 19:00:25 +03:00
}
2005-08-02 11:24:54 +04:00
[Flags]
internal enum InstructionFlags : byte
{
Reachable = 1,
Processed = 2,
BranchTarget = 4
}
2005-06-01 13:49:30 +04:00
internal struct Instruction
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
private ushort pc;
private NormalizedByteCode normopcode;
2005-08-02 11:24:54 +04:00
internal InstructionFlags flags;
2005-06-01 13:49:30 +04:00
private int arg1;
private short arg2;
private SwitchEntry[] switch_entries;
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
struct SwitchEntry
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
internal int value;
internal int target_offset;
}
2005-08-02 11:24:54 +04:00
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 HardErrorMessageId
{
get
{
return arg1;
}
}
internal bool IsReachable
{
get
{
return (flags & InstructionFlags.Reachable) != 0;
}
}
2005-08-05 12:40:54 +04:00
internal void PatchOpCode(NormalizedByteCode bc)
{
this.normopcode = bc;
}
2005-06-01 13:49:30 +04:00
internal void SetTermNop(ushort pc)
{
// TODO what happens if we already have exactly the maximum number of instructions?
this.pc = pc;
2005-07-20 14:47:59 +04:00
this.normopcode = NormalizedByteCode.__nop;
2005-06-01 13:49:30 +04:00
}
internal void Read(ushort pc, BigEndianBinaryReader br)
{
this.pc = pc;
ByteCode bc = (ByteCode)br.ReadByte();
switch(ByteCodeMetaData.GetMode(bc))
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
case ByteCodeMode.Simple:
break;
case ByteCodeMode.Constant_1:
case ByteCodeMode.Local_1:
arg1 = br.ReadByte();
break;
case ByteCodeMode.Constant_2:
arg1 = br.ReadUInt16();
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();
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();
arg2 = br.ReadSByte();
break;
case ByteCodeMode.Tableswitch:
2004-08-30 19:56:23 +04:00
{
2005-06-01 13:49:30 +04:00
// 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_offset = br.ReadInt32();
}
this.switch_entries = entries;
break;
2004-08-30 19:56:23 +04:00
}
2005-06-01 13:49:30 +04:00
case ByteCodeMode.Lookupswitch:
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
// 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_offset = br.ReadInt32();
}
this.switch_entries = entries;
break;
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
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)
2004-08-30 19:56:23 +04:00
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);
}
2005-06-01 13:49:30 +04:00
break;
default:
throw new ClassFormatError("Invalid opcode: {0}", bc);
}
this.normopcode = ByteCodeMetaData.GetNormalizedByteCode(bc);
2005-07-20 14:47:59 +04:00
arg1 = ByteCodeMetaData.GetArg(bc, arg1);
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal int PC
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return pc;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal NormalizedByteCode NormalizedOpCode
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return normopcode;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal int Arg1
{
get
{
return arg1;
}
}
internal int Arg2
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return arg2;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal int NormalizedArg1
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return arg1;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal int DefaultOffset
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return arg1;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal int SwitchEntryCount
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return switch_entries.Length;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal int GetSwitchValue(int i)
{
return switch_entries[i].value;
}
internal int GetSwitchTargetOffset(int i)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
return switch_entries[i].target_offset;
2002-12-18 19:00:25 +03:00
}
}
2005-06-01 13:49:30 +04:00
internal struct LineNumberTableEntry
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
internal ushort start_pc;
internal ushort line_number;
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal struct LocalVariableTableEntry
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
internal ushort start_pc;
internal ushort length;
internal string name;
internal string descriptor;
internal ushort index;
2002-12-18 19:00:25 +03:00
}
}
}
}