2002-12-18 19:00:25 +03:00
|
|
|
/*
|
2004-03-20 16:25:08 +03:00
|
|
|
Copyright (C) 2002, 2003, 2004 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;
|
|
|
|
|
|
|
|
class ClassFile
|
|
|
|
{
|
|
|
|
private ConstantPoolItem[] constantpool;
|
|
|
|
private Modifiers access_flags;
|
2003-01-06 16:56:37 +03:00
|
|
|
private ConstantPoolItemClass this_cpi;
|
|
|
|
private ConstantPoolItemClass super_cpi;
|
|
|
|
private ConstantPoolItemClass[] interfaces;
|
2002-12-18 19:00:25 +03:00
|
|
|
private Field[] fields;
|
|
|
|
private Method[] methods;
|
|
|
|
private Attribute[] attributes;
|
|
|
|
private string sourceFile;
|
|
|
|
private bool sourceFileCached;
|
2003-02-20 17:18:38 +03:00
|
|
|
private ClassFile outerClass;
|
2004-03-16 20:10:09 +03:00
|
|
|
private int majorVersion;
|
2002-12-18 19:00:25 +03:00
|
|
|
private static readonly char[] illegalcharacters = { '<', '>' };
|
|
|
|
|
|
|
|
internal ClassFile(byte[] buf, int offset, int length, string inputClassName)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
BigEndianBinaryReader br = new BigEndianBinaryReader(buf, offset);
|
|
|
|
if(br.ReadUInt32() != 0xCAFEBABE)
|
|
|
|
{
|
2004-02-02 12:46:13 +03:00
|
|
|
throw new ClassFormatError("Bad magic number");
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
2004-03-16 20:10:09 +03:00
|
|
|
int minorVersion = br.ReadUInt16();
|
|
|
|
majorVersion = br.ReadUInt16();
|
2004-08-17 13:05:21 +04:00
|
|
|
if(majorVersion < 45 || majorVersion > 48)
|
2002-12-18 19:00:25 +03:00
|
|
|
{
|
2004-03-16 20:10:09 +03:00
|
|
|
throw new UnsupportedClassVersionError(majorVersion + "." + minorVersion);
|
|
|
|
}
|
2004-08-17 13:05:21 +04:00
|
|
|
Hashtable classCache = new Hashtable();
|
2002-12-18 19:00:25 +03:00
|
|
|
int constantpoolcount = br.ReadUInt16();
|
|
|
|
constantpool = new ConstantPoolItem[constantpoolcount];
|
|
|
|
for(int i = 1; i < constantpoolcount; i++)
|
|
|
|
{
|
2004-08-17 13:05:21 +04:00
|
|
|
constantpool[i] = ConstantPoolItem.Read(inputClassName, classCache, br);
|
2002-12-18 19:00:25 +03:00
|
|
|
// LONG and DOUBLE items take up two slots...
|
|
|
|
if(constantpool[i].IsWide)
|
|
|
|
{
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for(int i = 1; i < constantpoolcount; i++)
|
|
|
|
{
|
|
|
|
if(constantpool[i] != null)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
constantpool[i].Resolve(this);
|
|
|
|
}
|
|
|
|
catch(IndexOutOfRangeException)
|
|
|
|
{
|
2004-02-02 12:46:13 +03:00
|
|
|
throw new ClassFormatError("{0} (Invalid constant pool item #{1})", inputClassName, i);
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
catch(InvalidCastException)
|
|
|
|
{
|
2004-02-02 12:46:13 +03:00
|
|
|
throw new ClassFormatError("{0} (Invalid constant pool item #{1})", inputClassName, i);
|
2002-12-18 19:00:25 +03: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
|
|
|
|
if((IsInterface && IsFinal) || (IsAbstract && IsFinal))
|
|
|
|
{
|
2004-02-02 12:46:13 +03:00
|
|
|
throw new ClassFormatError("{0} (Illegal class modifiers 0x{1:X})", inputClassName, access_flags);
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
int this_class = br.ReadUInt16();
|
|
|
|
try
|
|
|
|
{
|
2003-01-06 16:56:37 +03:00
|
|
|
this_cpi = (ConstantPoolItemClass)constantpool[this_class];
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
catch(Exception)
|
|
|
|
{
|
2004-02-02 12:46:13 +03:00
|
|
|
throw new ClassFormatError("{0} (Class name has bad constant pool index)", inputClassName);
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
int super_class = br.ReadUInt16();
|
|
|
|
// NOTE for convenience we allow parsing java/lang/Object (which has no super class), so
|
|
|
|
// we check for super_class != 0
|
|
|
|
if(super_class != 0)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2003-01-06 16:56:37 +03:00
|
|
|
super_cpi = (ConstantPoolItemClass)constantpool[super_class];
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
catch(Exception)
|
|
|
|
{
|
2004-02-02 12:46:13 +03:00
|
|
|
throw new ClassFormatError("{0} (Bad superclass constant pool index)", inputClassName);
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2003-05-30 16:08:59 +04:00
|
|
|
if(this.Name != "java.lang.Object")
|
2002-12-18 19:00:25 +03:00
|
|
|
{
|
2004-02-02 12:46:13 +03:00
|
|
|
throw new ClassFormatError("{0} (Bad superclass index)", Name);
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
}
|
2003-05-30 16:08:59 +04:00
|
|
|
if(IsInterface && (super_class == 0 || super_cpi.Name != "java.lang.Object"))
|
2002-12-18 19:00:25 +03:00
|
|
|
{
|
2004-02-02 12:46:13 +03:00
|
|
|
throw new ClassFormatError("{0} (Interfaces must have java.lang.Object as superclass)", Name);
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
2004-08-17 13:05:21 +04:00
|
|
|
// TODO are there any more checks we need to do on the class name?
|
|
|
|
if(Name.Length == 0 || Name[0] == '[')
|
|
|
|
{
|
|
|
|
throw new ClassFormatError("Bad name");
|
|
|
|
}
|
2002-12-18 19:00:25 +03:00
|
|
|
int interfaces_count = br.ReadUInt16();
|
2003-01-06 16:56:37 +03:00
|
|
|
interfaces = new ConstantPoolItemClass[interfaces_count];
|
2002-12-18 19:00:25 +03:00
|
|
|
Hashtable interfaceNames = new Hashtable();
|
|
|
|
for(int i = 0; i < interfaces_count; i++)
|
|
|
|
{
|
|
|
|
int index = br.ReadUInt16();
|
|
|
|
if(index == 0 || index >= constantpool.Length)
|
|
|
|
{
|
2004-02-02 12:46:13 +03:00
|
|
|
throw new ClassFormatError("{0} (Illegal constant pool index)", Name);
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
ConstantPoolItemClass cpi = constantpool[index] as ConstantPoolItemClass;
|
|
|
|
if(cpi == null)
|
|
|
|
{
|
2004-02-02 12:46:13 +03:00
|
|
|
throw new ClassFormatError("{0} (Interface name has bad constant type)", Name);
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
2003-01-06 16:56:37 +03:00
|
|
|
interfaces[i] = (ConstantPoolItemClass)GetConstantPoolItem(index);
|
2002-12-18 19:00:25 +03:00
|
|
|
if(interfaceNames.ContainsKey(interfaces[i]))
|
|
|
|
{
|
2004-02-02 12:46:13 +03:00
|
|
|
throw new ClassFormatError("{0} (Repetitive interface name)", Name);
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
interfaceNames.Add(interfaces[i], interfaces[i]);
|
|
|
|
}
|
|
|
|
int fields_count = br.ReadUInt16();
|
|
|
|
fields = new Field[fields_count];
|
|
|
|
Hashtable fieldNameSigs = new Hashtable();
|
|
|
|
for(int i = 0; i < fields_count; i++)
|
|
|
|
{
|
2004-08-17 13:05:21 +04:00
|
|
|
fields[i] = new Field(this, classCache, br);
|
2002-12-18 19:00:25 +03:00
|
|
|
string name = fields[i].Name;
|
|
|
|
// NOTE It's not in the vmspec (as far as I can tell), but Sun's VM doens't allow names that
|
|
|
|
// contain '<' or '>'
|
|
|
|
if(name.Length == 0 || name.IndexOfAny(illegalcharacters) != -1)
|
|
|
|
{
|
2004-02-02 12:46:13 +03:00
|
|
|
throw new ClassFormatError("{0} (Illegal field name \"{1}\")", Name, name);
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
string nameSig = name + fields[i].Signature;
|
|
|
|
if(fieldNameSigs.ContainsKey(nameSig))
|
|
|
|
{
|
2004-02-02 12:46:13 +03:00
|
|
|
throw new ClassFormatError("{0} (Repetitive field name/signature)", Name);
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
fieldNameSigs.Add(nameSig, nameSig);
|
|
|
|
}
|
|
|
|
int methods_count = br.ReadUInt16();
|
|
|
|
methods = new Method[methods_count];
|
|
|
|
Hashtable methodNameSigs = new Hashtable();
|
|
|
|
for(int i = 0; i < methods_count; i++)
|
|
|
|
{
|
2004-08-17 13:05:21 +04:00
|
|
|
methods[i] = new Method(this, classCache, br);
|
2002-12-18 19:00:25 +03:00
|
|
|
string name = methods[i].Name;
|
|
|
|
string sig = methods[i].Signature;
|
|
|
|
if(name.Length == 0 || (name.IndexOfAny(illegalcharacters) != -1 && name != "<init>" && name != "<clinit>"))
|
|
|
|
{
|
2004-02-02 12:46:13 +03:00
|
|
|
throw new ClassFormatError("{0} (Illegal method name \"{1}\")", Name, name);
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
if((name == "<init>" || name == "<clinit>") && !sig.EndsWith("V"))
|
|
|
|
{
|
2004-02-02 12:46:13 +03:00
|
|
|
throw new ClassFormatError("{0} (Method \"{1}\" has illegal signature \"{2}\")", Name, name, sig);
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
string nameSig = name + sig;
|
|
|
|
if(methodNameSigs.ContainsKey(nameSig))
|
|
|
|
{
|
2004-02-02 12:46:13 +03:00
|
|
|
throw new ClassFormatError("{0} (Repetitive method name/signature)", Name);
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
methodNameSigs.Add(nameSig, nameSig);
|
|
|
|
}
|
|
|
|
int attributes_count = br.ReadUInt16();
|
|
|
|
attributes = new Attribute[attributes_count];
|
|
|
|
for(int i = 0; i < attributes_count; i++)
|
|
|
|
{
|
|
|
|
attributes[i] = Attribute.Read(this, br);
|
|
|
|
}
|
|
|
|
if(br.Position != offset + length)
|
|
|
|
{
|
|
|
|
if(br.Position > offset + length)
|
|
|
|
{
|
2004-02-02 12:46:13 +03:00
|
|
|
throw new ClassFormatError("Truncated class file");
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-02-02 12:46:13 +03:00
|
|
|
throw new ClassFormatError("Extra bytes at the end of the class file");
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch(IndexOutOfRangeException)
|
|
|
|
{
|
2004-02-02 12:46:13 +03:00
|
|
|
throw new ClassFormatError("Truncated class file");
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
// catch(Exception)
|
|
|
|
// {
|
|
|
|
// FileStream fs = File.Create(inputClassName + ".broken");
|
|
|
|
// fs.Write(buf, offset, length);
|
|
|
|
// fs.Close();
|
|
|
|
// throw;
|
|
|
|
// }
|
|
|
|
}
|
|
|
|
|
2004-03-16 20:10:09 +03:00
|
|
|
internal int MajorVersion
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return majorVersion;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-05-30 16:08:59 +04:00
|
|
|
// NOTE this property is only used when statically compiling
|
|
|
|
// (and it is set by the static compiler's class loader in vm.cs)
|
2003-02-20 17:18:38 +03:00
|
|
|
internal ClassFile OuterClass
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return outerClass;
|
|
|
|
}
|
|
|
|
set
|
|
|
|
{
|
|
|
|
outerClass = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-08-17 13:05:21 +04:00
|
|
|
internal void Link(TypeWrapper thisType)
|
2003-01-02 18:44:17 +03:00
|
|
|
{
|
|
|
|
for(int i = 1; i < constantpool.Length; i++)
|
|
|
|
{
|
|
|
|
if(constantpool[i] != null)
|
|
|
|
{
|
2004-08-17 13:05:21 +04:00
|
|
|
constantpool[i].Link(thisType);
|
2003-01-02 18:44:17 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-12-18 19:00:25 +03:00
|
|
|
internal Modifiers Modifiers
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return 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 IsInterface
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return (access_flags & Modifiers.Interface) != 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal bool IsSuper
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return (access_flags & Modifiers.Super) != 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal ConstantPoolItemFieldref GetFieldref(int index)
|
|
|
|
{
|
|
|
|
return (ConstantPoolItemFieldref)constantpool[index];
|
|
|
|
}
|
|
|
|
|
2004-08-17 13:05:21 +04:00
|
|
|
// NOTE this returns an MI, because it used for both normal methods and interface methods
|
|
|
|
internal ConstantPoolItemMI GetMethodref(int index)
|
2002-12-18 19:00:25 +03:00
|
|
|
{
|
2004-08-17 13:05:21 +04:00
|
|
|
return (ConstantPoolItemMI)constantpool[index];
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
private ConstantPoolItem GetConstantPoolItem(int index)
|
|
|
|
{
|
|
|
|
return constantpool[index];
|
|
|
|
}
|
|
|
|
|
|
|
|
internal string GetConstantPoolClass(int index)
|
|
|
|
{
|
|
|
|
return ((ConstantPoolItemClass)constantpool[index]).Name;
|
|
|
|
}
|
|
|
|
|
2003-01-06 16:56:37 +03:00
|
|
|
internal TypeWrapper GetConstantPoolClassType(int index, ClassLoaderWrapper classLoader)
|
|
|
|
{
|
|
|
|
return ((ConstantPoolItemClass)constantpool[index]).GetClassType(classLoader);
|
|
|
|
}
|
|
|
|
|
2002-12-18 19:00:25 +03:00
|
|
|
private string GetConstantPoolString(int index)
|
|
|
|
{
|
|
|
|
return ((ConstantPoolItemString)constantpool[index]).Value;
|
|
|
|
}
|
|
|
|
|
2003-05-30 16:08:59 +04:00
|
|
|
private ConstantPoolItemUtf8 GetConstantPoolUtf8(int index)
|
|
|
|
{
|
|
|
|
return ((ConstantPoolItemUtf8)constantpool[index]);
|
|
|
|
}
|
|
|
|
|
|
|
|
internal string GetConstantPoolUtf8String(int index)
|
2002-12-18 19:00:25 +03:00
|
|
|
{
|
2003-05-30 16:08:59 +04:00
|
|
|
return GetConstantPoolUtf8(index).Value;
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
|
2003-12-20 01:19:18 +03:00
|
|
|
internal ConstantType GetConstantPoolConstantType(int index)
|
2002-12-18 19:00:25 +03:00
|
|
|
{
|
2003-12-20 01:19:18 +03:00
|
|
|
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;
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
internal string Name
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
2003-01-06 16:56:37 +03:00
|
|
|
return this_cpi.Name;
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal string PackageName
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
2003-01-06 16:56:37 +03:00
|
|
|
string name = Name;
|
2003-05-30 16:08:59 +04:00
|
|
|
int index = name.LastIndexOf('.');
|
2002-12-18 19:00:25 +03:00
|
|
|
if(index == -1)
|
|
|
|
{
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
return name.Substring(0, index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal string SuperClass
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
2003-01-06 16:56:37 +03:00
|
|
|
return super_cpi.Name;
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal Field[] Fields
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return fields;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal Method[] Methods
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return methods;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-08-17 13:05:21 +04:00
|
|
|
internal ConstantPoolItemClass[] Interfaces
|
2002-12-18 19:00:25 +03:00
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
2004-08-17 13:05:21 +04:00
|
|
|
return interfaces;
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private Attribute GetAttribute(string name)
|
|
|
|
{
|
|
|
|
for(int i = 0; i < attributes.Length; i++)
|
|
|
|
{
|
|
|
|
if(attributes[i].Name == name)
|
|
|
|
{
|
|
|
|
return attributes[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal string SourceFileAttribute
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
if(!sourceFileCached)
|
|
|
|
{
|
|
|
|
sourceFileCached = true;
|
|
|
|
Attribute attr = GetAttribute("SourceFile");
|
|
|
|
if(attr != null)
|
|
|
|
{
|
|
|
|
sourceFile = ((ConstantPoolItemUtf8)GetConstantPoolItem(attr.Data.ReadUInt16())).Value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return sourceFile;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-08-17 13:05:21 +04:00
|
|
|
internal string IKVMAssemblyAttribute
|
2002-12-18 19:00:25 +03:00
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
2003-08-21 14:06:34 +04:00
|
|
|
Attribute attr = GetAttribute("IKVM.NET.Assembly");
|
2002-12-18 19:00:25 +03:00
|
|
|
if(attr != null)
|
|
|
|
{
|
|
|
|
return ((ConstantPoolItemUtf8)GetConstantPoolItem(attr.Data.ReadUInt16())).Value;
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-11-17 15:01:50 +03:00
|
|
|
internal bool DeprecatedAttribute
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return GetAttribute("Deprecated") != null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-02-15 19:18:11 +03:00
|
|
|
internal struct InnerClass
|
|
|
|
{
|
2003-02-18 12:30:34 +03:00
|
|
|
internal int innerClass; // ConstantPoolItemClass
|
|
|
|
internal int outerClass; // ConstantPoolItemClass
|
|
|
|
internal int name; // ConstantPoolItemUtf8
|
2003-02-15 19:18:11 +03:00
|
|
|
internal Modifiers accessFlags;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal InnerClass[] InnerClasses
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
Attribute attr = GetAttribute("InnerClasses");
|
|
|
|
if(attr != null)
|
|
|
|
{
|
|
|
|
BigEndianBinaryReader rdr = attr.Data;
|
|
|
|
ushort count = rdr.ReadUInt16();
|
|
|
|
InnerClass[] list = new InnerClass[count];
|
|
|
|
for(int i = 0; i < list.Length; i++)
|
|
|
|
{
|
2003-02-18 12:30:34 +03:00
|
|
|
list[i].innerClass = rdr.ReadUInt16();
|
|
|
|
list[i].outerClass = rdr.ReadUInt16();
|
|
|
|
list[i].name = rdr.ReadUInt16();
|
2003-02-15 19:18:11 +03:00
|
|
|
list[i].accessFlags = (Modifiers)rdr.ReadUInt16();
|
|
|
|
}
|
|
|
|
return list;
|
|
|
|
}
|
2003-05-30 16:08:59 +04:00
|
|
|
return null;
|
2003-02-15 19:18:11 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-12-20 01:19:18 +03:00
|
|
|
internal enum ConstantType
|
|
|
|
{
|
|
|
|
Integer,
|
|
|
|
Long,
|
|
|
|
Float,
|
|
|
|
Double,
|
2004-03-16 20:10:09 +03:00
|
|
|
String,
|
|
|
|
Class
|
2003-12-20 01:19:18 +03:00
|
|
|
}
|
|
|
|
|
2002-12-18 19:00:25 +03:00
|
|
|
internal abstract class ConstantPoolItem
|
|
|
|
{
|
|
|
|
internal virtual bool IsWide
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal virtual void Resolve(ClassFile classFile)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2004-08-17 13:05:21 +04:00
|
|
|
internal virtual void Link(TypeWrapper thisType)
|
2003-01-02 18:44:17 +03:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2003-12-20 01:19:18 +03:00
|
|
|
internal virtual ConstantType GetConstantType()
|
|
|
|
{
|
|
|
|
throw new InvalidOperationException();
|
|
|
|
}
|
|
|
|
|
2004-08-17 13:05:21 +04:00
|
|
|
internal static ConstantPoolItem Read(string inputClassName, Hashtable classCache, BigEndianBinaryReader br)
|
2002-12-18 19:00:25 +03:00
|
|
|
{
|
|
|
|
byte tag = br.ReadByte();
|
|
|
|
switch((Constant)tag)
|
|
|
|
{
|
|
|
|
case Constant.Class:
|
2004-08-17 13:05:21 +04:00
|
|
|
return new ConstantPoolItemClass(classCache, br);
|
2002-12-18 19:00:25 +03:00
|
|
|
case Constant.Double:
|
|
|
|
return new ConstantPoolItemDouble(br);
|
|
|
|
case Constant.Fieldref:
|
|
|
|
return new ConstantPoolItemFieldref(br);
|
|
|
|
case Constant.Float:
|
|
|
|
return new ConstantPoolItemFloat(br);
|
|
|
|
case Constant.Integer:
|
|
|
|
return new ConstantPoolItemInteger(br);
|
|
|
|
case Constant.InterfaceMethodref:
|
|
|
|
return new ConstantPoolItemInterfaceMethodref(br);
|
|
|
|
case Constant.Long:
|
|
|
|
return new ConstantPoolItemLong(br);
|
|
|
|
case Constant.Methodref:
|
|
|
|
return new ConstantPoolItemMethodref(br);
|
|
|
|
case Constant.NameAndType:
|
2004-08-17 13:05:21 +04:00
|
|
|
return new ConstantPoolItemNameAndType(classCache, br);
|
2002-12-18 19:00:25 +03:00
|
|
|
case Constant.String:
|
|
|
|
return new ConstantPoolItemString(br);
|
|
|
|
case Constant.Utf8:
|
|
|
|
return new ConstantPoolItemUtf8(inputClassName, br);
|
|
|
|
default:
|
2004-02-02 12:46:13 +03:00
|
|
|
throw new ClassFormatError("{0} (Illegal constant pool type 0x{1:X})", inputClassName, tag);
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-08-17 13:05:21 +04:00
|
|
|
internal class ConstantPoolItemClass : ConstantPoolItem
|
2002-12-18 19:00:25 +03:00
|
|
|
{
|
|
|
|
private ushort name_index;
|
|
|
|
private string name;
|
2003-01-02 18:44:17 +03:00
|
|
|
private TypeWrapper typeWrapper;
|
2004-08-17 13:05:21 +04:00
|
|
|
private Hashtable classCache;
|
2002-12-18 19:00:25 +03:00
|
|
|
|
2004-08-17 13:05:21 +04:00
|
|
|
internal ConstantPoolItemClass(Hashtable classCache, BigEndianBinaryReader br)
|
2002-12-18 19:00:25 +03:00
|
|
|
{
|
2004-08-17 13:05:21 +04:00
|
|
|
this.classCache = classCache;
|
2002-12-18 19:00:25 +03:00
|
|
|
name_index = br.ReadUInt16();
|
|
|
|
}
|
|
|
|
|
|
|
|
internal override void Resolve(ClassFile classFile)
|
|
|
|
{
|
2003-05-30 16:08:59 +04:00
|
|
|
name = ((ConstantPoolItemUtf8)classFile.GetConstantPoolItem(name_index)).DottifiedValue;;
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
internal string Name
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
}
|
2003-01-02 18:44:17 +03:00
|
|
|
|
|
|
|
internal TypeWrapper GetClassType(ClassLoaderWrapper classLoader)
|
|
|
|
{
|
|
|
|
if(typeWrapper == null)
|
|
|
|
{
|
2004-08-17 13:05:21 +04:00
|
|
|
typeWrapper = LoadClassHelper(classLoader, classCache, name);
|
2003-01-02 18:44:17 +03:00
|
|
|
}
|
|
|
|
return typeWrapper;
|
|
|
|
}
|
2004-03-16 20:10:09 +03:00
|
|
|
|
|
|
|
internal override ConstantType GetConstantType()
|
|
|
|
{
|
|
|
|
return ConstantType.Class;
|
|
|
|
}
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
|
2004-08-17 13:05:21 +04:00
|
|
|
private static TypeWrapper LoadClassHelper(ClassLoaderWrapper classLoader, Hashtable classCache, string name)
|
2003-01-06 16:56:37 +03:00
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2004-08-17 13:05:21 +04:00
|
|
|
TypeWrapper wrapper = (TypeWrapper)classCache[name];
|
|
|
|
if(wrapper != null)
|
|
|
|
{
|
|
|
|
return wrapper;
|
|
|
|
}
|
|
|
|
wrapper = classLoader.LoadClassByDottedNameFast(name);
|
2003-12-24 14:51:41 +03:00
|
|
|
if(wrapper == null)
|
|
|
|
{
|
2004-03-08 18:18:47 +03:00
|
|
|
Tracer.Error(Tracer.ClassLoading, "Class not found: {0}", name);
|
2003-12-24 14:51:41 +03:00
|
|
|
wrapper = new UnloadableTypeWrapper(name);
|
|
|
|
}
|
|
|
|
return wrapper;
|
2003-01-06 16:56:37 +03:00
|
|
|
}
|
2003-03-17 17:02:46 +03:00
|
|
|
catch(Exception x)
|
2003-01-06 16:56:37 +03:00
|
|
|
{
|
|
|
|
// TODO it might not be a good idea to catch .NET system exceptions here
|
2004-03-08 18:18:47 +03:00
|
|
|
if(Tracer.ClassLoading.TraceError)
|
2003-03-17 17:02:46 +03:00
|
|
|
{
|
2003-06-10 17:28:47 +04:00
|
|
|
object cl = classLoader.GetJavaClassLoader();
|
2003-10-17 12:08:31 +04:00
|
|
|
if(cl != null)
|
2003-06-10 17:28:47 +04:00
|
|
|
{
|
2003-10-17 12:08:31 +04:00
|
|
|
System.Text.StringBuilder sb = new System.Text.StringBuilder();
|
|
|
|
Type type = cl.GetType();
|
|
|
|
while(type.FullName != "java.lang.ClassLoader")
|
|
|
|
{
|
|
|
|
type = type.BaseType;
|
|
|
|
}
|
|
|
|
string sep = "";
|
|
|
|
while(cl != null)
|
|
|
|
{
|
|
|
|
sb.Append(sep).Append(cl);
|
|
|
|
sep = " -> ";
|
|
|
|
cl = type.InvokeMember("getParent", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.InvokeMethod | System.Reflection.BindingFlags.Instance, null, cl, new object[0]);
|
|
|
|
}
|
2004-03-08 18:18:47 +03:00
|
|
|
Tracer.Error(Tracer.ClassLoading, "ClassLoader chain: {0}", sb);
|
2003-06-10 17:28:47 +04:00
|
|
|
}
|
2004-03-08 18:18:47 +03:00
|
|
|
x = ExceptionHelper.MapExceptionFast(x);
|
|
|
|
Tracer.Error(Tracer.ClassLoading, x.ToString() + Environment.NewLine + x.StackTrace);
|
2003-03-17 17:02:46 +03:00
|
|
|
}
|
2003-01-06 16:56:37 +03:00
|
|
|
return new UnloadableTypeWrapper(name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-08-17 13:05:21 +04:00
|
|
|
private static TypeWrapper SigDecoderWrapper(ClassLoaderWrapper classLoader, Hashtable classCache, ref int index, string sig)
|
2004-03-20 16:25:08 +03: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':
|
|
|
|
{
|
|
|
|
int pos = index;
|
|
|
|
index = sig.IndexOf(';', index) + 1;
|
2004-08-17 13:05:21 +04:00
|
|
|
return LoadClassHelper(classLoader, classCache, sig.Substring(pos, index - pos - 1));
|
2004-03-20 16:25:08 +03:00
|
|
|
}
|
|
|
|
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] == '[')
|
|
|
|
{
|
|
|
|
index++;
|
|
|
|
array += "[";
|
|
|
|
}
|
|
|
|
switch(sig[index])
|
|
|
|
{
|
|
|
|
case 'L':
|
|
|
|
{
|
|
|
|
int pos = index;
|
|
|
|
index = sig.IndexOf(';', index) + 1;
|
2004-08-17 13:05:21 +04:00
|
|
|
return LoadClassHelper(classLoader, classCache, array + sig.Substring(pos, index - pos));
|
2004-03-20 16:25:08 +03:00
|
|
|
}
|
|
|
|
case 'B':
|
|
|
|
case 'C':
|
|
|
|
case 'D':
|
|
|
|
case 'F':
|
|
|
|
case 'I':
|
|
|
|
case 'J':
|
|
|
|
case 'S':
|
|
|
|
case 'Z':
|
2004-08-17 13:05:21 +04:00
|
|
|
return LoadClassHelper(classLoader, classCache, array + sig[index++]);
|
2004-03-20 16:25:08 +03:00
|
|
|
default:
|
|
|
|
// TODO this should never happen, because ClassFile should validate the descriptors
|
|
|
|
throw new InvalidOperationException(sig.Substring(index));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
// TODO this should never happen, because ClassFile should validate the descriptors
|
|
|
|
throw new InvalidOperationException(sig.Substring(index));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-08-17 13:05:21 +04:00
|
|
|
internal static TypeWrapper[] ArgTypeWrapperListFromSig(ClassLoaderWrapper classLoader, Hashtable classCache, string sig)
|
2004-03-20 16:25:08 +03:00
|
|
|
{
|
|
|
|
if(sig[1] == ')')
|
|
|
|
{
|
|
|
|
return TypeWrapper.EmptyArray;
|
|
|
|
}
|
|
|
|
ArrayList list = new ArrayList();
|
|
|
|
for(int i = 1; sig[i] != ')';)
|
|
|
|
{
|
2004-08-17 13:05:21 +04:00
|
|
|
list.Add(SigDecoderWrapper(classLoader, classCache, ref i, sig));
|
2004-03-20 16:25:08 +03:00
|
|
|
}
|
|
|
|
TypeWrapper[] types = new TypeWrapper[list.Count];
|
|
|
|
list.CopyTo(types);
|
|
|
|
return types;
|
|
|
|
}
|
|
|
|
|
2004-08-17 13:05:21 +04:00
|
|
|
internal static TypeWrapper FieldTypeWrapperFromSig(ClassLoaderWrapper classLoader, Hashtable classCache, string sig)
|
2004-03-20 16:25:08 +03:00
|
|
|
{
|
|
|
|
int index = 0;
|
2004-08-17 13:05:21 +04:00
|
|
|
return SigDecoderWrapper(classLoader, classCache, ref index, sig);
|
2004-03-20 16:25:08 +03:00
|
|
|
}
|
|
|
|
|
2004-08-17 13:05:21 +04:00
|
|
|
internal static TypeWrapper RetTypeWrapperFromSig(ClassLoaderWrapper classLoader, Hashtable classCache, string sig)
|
2004-03-20 16:25:08 +03:00
|
|
|
{
|
|
|
|
int index = sig.IndexOf(')') + 1;
|
2004-08-17 13:05:21 +04:00
|
|
|
return SigDecoderWrapper(classLoader, classCache, ref index, sig);
|
2004-03-20 16:25:08 +03:00
|
|
|
}
|
|
|
|
|
2002-12-18 19:00:25 +03:00
|
|
|
private class ConstantPoolItemDouble : ConstantPoolItem
|
|
|
|
{
|
|
|
|
private double d;
|
|
|
|
|
|
|
|
internal ConstantPoolItemDouble(BigEndianBinaryReader br)
|
|
|
|
{
|
|
|
|
d = br.ReadDouble();
|
|
|
|
}
|
|
|
|
|
2003-12-20 01:19:18 +03:00
|
|
|
internal override ConstantType GetConstantType()
|
|
|
|
{
|
|
|
|
return ConstantType.Double;
|
|
|
|
}
|
|
|
|
|
2002-12-18 19:00:25 +03:00
|
|
|
internal double Value
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal override bool IsWide
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal class ConstantPoolItemFMI : ConstantPoolItem
|
|
|
|
{
|
|
|
|
private ushort class_index;
|
|
|
|
private ushort name_and_type_index;
|
2004-08-17 13:05:21 +04:00
|
|
|
protected ConstantPoolItemNameAndType name_and_type;
|
2002-12-27 12:01:16 +03:00
|
|
|
private ConstantPoolItemClass clazz;
|
2002-12-18 19:00:25 +03:00
|
|
|
|
|
|
|
internal ConstantPoolItemFMI(BigEndianBinaryReader br)
|
|
|
|
{
|
|
|
|
class_index = br.ReadUInt16();
|
|
|
|
name_and_type_index = br.ReadUInt16();
|
|
|
|
}
|
|
|
|
|
|
|
|
internal override void Resolve(ClassFile classFile)
|
|
|
|
{
|
2002-12-27 12:01:16 +03:00
|
|
|
name_and_type = (ConstantPoolItemNameAndType)classFile.GetConstantPoolItem(name_and_type_index);
|
|
|
|
clazz = (ConstantPoolItemClass)classFile.GetConstantPoolItem(class_index);
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
internal string Name
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
2002-12-27 12:01:16 +03:00
|
|
|
return name_and_type.Name;
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal string Signature
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
2002-12-27 12:01:16 +03:00
|
|
|
return name_and_type.Type;
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal string Class
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
2002-12-27 12:01:16 +03:00
|
|
|
return clazz.Name;
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
}
|
2003-01-02 18:44:17 +03:00
|
|
|
|
|
|
|
internal TypeWrapper GetClassType(ClassLoaderWrapper classLoader)
|
|
|
|
{
|
|
|
|
return clazz.GetClassType(classLoader);
|
|
|
|
}
|
2004-08-17 13:05:21 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
internal class ConstantPoolItemFieldref : ConstantPoolItemFMI
|
|
|
|
{
|
|
|
|
private FieldWrapper field;
|
|
|
|
|
|
|
|
internal ConstantPoolItemFieldref(BigEndianBinaryReader br) : base(br)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
internal TypeWrapper GetFieldType(ClassLoaderWrapper classLoader)
|
|
|
|
{
|
|
|
|
return name_and_type.GetFieldType(classLoader);
|
|
|
|
}
|
|
|
|
|
|
|
|
internal override void Link(TypeWrapper thisType)
|
|
|
|
{
|
|
|
|
ClassLoaderWrapper classLoader = thisType.GetClassLoader();
|
|
|
|
GetFieldType(classLoader);
|
|
|
|
TypeWrapper wrapper = GetClassType(classLoader);
|
|
|
|
if(!wrapper.IsUnloadable)
|
|
|
|
{
|
|
|
|
field = wrapper.GetFieldWrapper(Name, GetFieldType(classLoader));
|
|
|
|
if(field != null)
|
|
|
|
{
|
|
|
|
field.Link();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal FieldWrapper GetField()
|
|
|
|
{
|
|
|
|
return field;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal class ConstantPoolItemMI : ConstantPoolItemFMI
|
|
|
|
{
|
|
|
|
protected MethodWrapper method;
|
|
|
|
protected MethodWrapper invokespecialMethod;
|
|
|
|
|
|
|
|
internal ConstantPoolItemMI(BigEndianBinaryReader br) : base(br)
|
|
|
|
{
|
|
|
|
}
|
2003-01-02 18:44:17 +03:00
|
|
|
|
|
|
|
internal TypeWrapper[] GetArgTypes(ClassLoaderWrapper classLoader)
|
|
|
|
{
|
|
|
|
return name_and_type.GetArgTypes(classLoader);
|
|
|
|
}
|
|
|
|
|
|
|
|
internal TypeWrapper GetRetType(ClassLoaderWrapper classLoader)
|
|
|
|
{
|
|
|
|
return name_and_type.GetRetType(classLoader);
|
|
|
|
}
|
2003-01-06 16:56:37 +03:00
|
|
|
|
2004-08-17 13:05:21 +04:00
|
|
|
internal MethodWrapper GetMethod()
|
2003-01-06 16:56:37 +03:00
|
|
|
{
|
2004-08-17 13:05:21 +04:00
|
|
|
return method;
|
2003-01-06 16:56:37 +03:00
|
|
|
}
|
2002-12-18 19:00:25 +03:00
|
|
|
|
2004-08-17 13:05:21 +04:00
|
|
|
internal MethodWrapper GetMethodForInvokespecial()
|
2002-12-18 19:00:25 +03:00
|
|
|
{
|
2004-08-17 13:05:21 +04:00
|
|
|
return invokespecialMethod != null ? invokespecialMethod : method;
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-08-17 13:05:21 +04:00
|
|
|
internal class ConstantPoolItemMethodref : ConstantPoolItemMI
|
2002-12-18 19:00:25 +03:00
|
|
|
{
|
|
|
|
internal ConstantPoolItemMethodref(BigEndianBinaryReader br) : base(br)
|
|
|
|
{
|
|
|
|
}
|
2004-08-17 13:05:21 +04:00
|
|
|
|
|
|
|
internal override void Link(TypeWrapper thisType)
|
|
|
|
{
|
|
|
|
ClassLoaderWrapper classLoader = thisType.GetClassLoader();
|
|
|
|
TypeWrapper wrapper = GetClassType(classLoader);
|
|
|
|
GetArgTypes(classLoader);
|
|
|
|
GetRetType(classLoader);
|
|
|
|
if(!wrapper.IsUnloadable)
|
|
|
|
{
|
|
|
|
MethodDescriptor md = new MethodDescriptor(Name, Signature);
|
|
|
|
method = wrapper.GetMethodWrapper(md, Name != "<init>");
|
|
|
|
if(method != null)
|
|
|
|
{
|
|
|
|
method.Link();
|
|
|
|
}
|
|
|
|
if(Name != "<init>" &&
|
|
|
|
(thisType.Modifiers & (Modifiers.Interface | Modifiers.Super)) == Modifiers.Super &&
|
|
|
|
thisType != wrapper && thisType.IsSubTypeOf(wrapper))
|
|
|
|
{
|
|
|
|
invokespecialMethod = thisType.BaseTypeWrapper.GetMethodWrapper(md, true);
|
|
|
|
if(invokespecialMethod != null)
|
|
|
|
{
|
|
|
|
invokespecialMethod.Link();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
|
2004-08-17 13:05:21 +04:00
|
|
|
internal class ConstantPoolItemInterfaceMethodref : ConstantPoolItemMI
|
2002-12-18 19:00:25 +03:00
|
|
|
{
|
|
|
|
internal ConstantPoolItemInterfaceMethodref(BigEndianBinaryReader br) : base(br)
|
|
|
|
{
|
|
|
|
}
|
2004-08-17 13:05:21 +04:00
|
|
|
|
|
|
|
private static MethodWrapper GetInterfaceMethod(TypeWrapper wrapper, MethodDescriptor md)
|
|
|
|
{
|
|
|
|
MethodWrapper method = wrapper.GetMethodWrapper(md, false);
|
|
|
|
if(method != null)
|
|
|
|
{
|
|
|
|
return method;
|
|
|
|
}
|
|
|
|
TypeWrapper[] interfaces = wrapper.Interfaces;
|
|
|
|
for(int i = 0; i < interfaces.Length; i++)
|
|
|
|
{
|
|
|
|
method = GetInterfaceMethod(interfaces[i], md);
|
|
|
|
if(method != null)
|
|
|
|
{
|
|
|
|
return method;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal override void Link(TypeWrapper thisType)
|
|
|
|
{
|
|
|
|
ClassLoaderWrapper classLoader = thisType.GetClassLoader();
|
|
|
|
TypeWrapper wrapper = GetClassType(classLoader);
|
|
|
|
GetArgTypes(classLoader);
|
|
|
|
GetRetType(classLoader);
|
|
|
|
if(!wrapper.IsUnloadable)
|
|
|
|
{
|
|
|
|
MethodDescriptor md = new MethodDescriptor(Name, Signature);
|
|
|
|
method = GetInterfaceMethod(wrapper, md);
|
|
|
|
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(md, false);
|
|
|
|
}
|
|
|
|
if(method != null)
|
|
|
|
{
|
|
|
|
method.Link();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
private class ConstantPoolItemFloat : ConstantPoolItem
|
|
|
|
{
|
|
|
|
private float v;
|
|
|
|
|
|
|
|
internal ConstantPoolItemFloat(BigEndianBinaryReader br)
|
|
|
|
{
|
|
|
|
v = br.ReadSingle();
|
|
|
|
}
|
|
|
|
|
2003-12-20 01:19:18 +03:00
|
|
|
internal override ConstantType GetConstantType()
|
|
|
|
{
|
|
|
|
return ConstantType.Float;
|
|
|
|
}
|
|
|
|
|
2002-12-18 19:00:25 +03:00
|
|
|
internal float Value
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private class ConstantPoolItemInteger : ConstantPoolItem
|
|
|
|
{
|
|
|
|
private int v;
|
|
|
|
|
|
|
|
internal ConstantPoolItemInteger(BigEndianBinaryReader br)
|
|
|
|
{
|
|
|
|
v = br.ReadInt32();
|
|
|
|
}
|
|
|
|
|
2003-12-20 01:19:18 +03:00
|
|
|
internal override ConstantType GetConstantType()
|
|
|
|
{
|
|
|
|
return ConstantType.Integer;
|
|
|
|
}
|
|
|
|
|
2002-12-18 19:00:25 +03:00
|
|
|
internal int Value
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private class ConstantPoolItemLong : ConstantPoolItem
|
|
|
|
{
|
|
|
|
private long l;
|
|
|
|
|
|
|
|
internal ConstantPoolItemLong(BigEndianBinaryReader br)
|
|
|
|
{
|
|
|
|
l = br.ReadInt64();
|
|
|
|
}
|
|
|
|
|
2003-12-20 01:19:18 +03:00
|
|
|
internal override ConstantType GetConstantType()
|
|
|
|
{
|
|
|
|
return ConstantType.Long;
|
|
|
|
}
|
|
|
|
|
2002-12-18 19:00:25 +03:00
|
|
|
internal long Value
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return l;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal override bool IsWide
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-08-17 13:05:21 +04:00
|
|
|
internal class ConstantPoolItemNameAndType : ConstantPoolItem
|
2002-12-18 19:00:25 +03:00
|
|
|
{
|
|
|
|
private ushort name_index;
|
|
|
|
private ushort descriptor_index;
|
|
|
|
private string name;
|
|
|
|
private string descriptor;
|
2003-01-02 18:44:17 +03:00
|
|
|
private TypeWrapper[] argTypeWrappers;
|
|
|
|
private TypeWrapper retTypeWrapper;
|
|
|
|
private TypeWrapper fieldTypeWrapper;
|
2004-08-17 13:05:21 +04:00
|
|
|
private Hashtable classCache;
|
2002-12-18 19:00:25 +03:00
|
|
|
|
2004-08-17 13:05:21 +04:00
|
|
|
internal ConstantPoolItemNameAndType(Hashtable classCache, BigEndianBinaryReader br)
|
2002-12-18 19:00:25 +03:00
|
|
|
{
|
2004-08-17 13:05:21 +04:00
|
|
|
this.classCache = classCache;
|
2002-12-18 19:00:25 +03:00
|
|
|
name_index = br.ReadUInt16();
|
|
|
|
descriptor_index = br.ReadUInt16();
|
|
|
|
}
|
|
|
|
|
|
|
|
internal override void Resolve(ClassFile classFile)
|
|
|
|
{
|
|
|
|
ConstantPoolItemUtf8 nameUtf8 = (ConstantPoolItemUtf8)classFile.GetConstantPoolItem(name_index);
|
|
|
|
nameUtf8.Resolve(classFile);
|
|
|
|
name = nameUtf8.Value;
|
|
|
|
ConstantPoolItemUtf8 descriptorUtf8 = (ConstantPoolItemUtf8)classFile.GetConstantPoolItem(descriptor_index);
|
|
|
|
descriptorUtf8.Resolve(classFile);
|
2003-05-30 16:08:59 +04:00
|
|
|
descriptor = descriptorUtf8.DottifiedValue;
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
internal string Name
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal string Type
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return descriptor;
|
|
|
|
}
|
|
|
|
}
|
2003-01-02 18:44:17 +03:00
|
|
|
|
|
|
|
internal TypeWrapper[] GetArgTypes(ClassLoaderWrapper classLoader)
|
|
|
|
{
|
|
|
|
if(argTypeWrappers == null)
|
|
|
|
{
|
2004-08-17 13:05:21 +04:00
|
|
|
argTypeWrappers = ArgTypeWrapperListFromSig(classLoader, classCache, descriptor);
|
2003-01-02 18:44:17 +03:00
|
|
|
}
|
|
|
|
return argTypeWrappers;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal TypeWrapper GetRetType(ClassLoaderWrapper classLoader)
|
|
|
|
{
|
|
|
|
if(retTypeWrapper == null)
|
|
|
|
{
|
2004-08-17 13:05:21 +04:00
|
|
|
retTypeWrapper = RetTypeWrapperFromSig(classLoader, classCache, descriptor);
|
2003-01-02 18:44:17 +03:00
|
|
|
}
|
|
|
|
return retTypeWrapper;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal TypeWrapper GetFieldType(ClassLoaderWrapper classLoader)
|
|
|
|
{
|
|
|
|
if(fieldTypeWrapper == null)
|
|
|
|
{
|
2004-08-17 13:05:21 +04:00
|
|
|
fieldTypeWrapper = FieldTypeWrapperFromSig(classLoader, classCache, descriptor);
|
2003-01-02 18:44:17 +03:00
|
|
|
}
|
|
|
|
return fieldTypeWrapper;
|
|
|
|
}
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
private class ConstantPoolItemString : ConstantPoolItem
|
|
|
|
{
|
|
|
|
private ushort string_index;
|
|
|
|
private string s;
|
|
|
|
|
|
|
|
internal ConstantPoolItemString(BigEndianBinaryReader br)
|
|
|
|
{
|
|
|
|
string_index = br.ReadUInt16();
|
|
|
|
}
|
|
|
|
|
|
|
|
internal override void Resolve(ClassFile classFile)
|
|
|
|
{
|
|
|
|
ConstantPoolItemUtf8 utf8 = (ConstantPoolItemUtf8)classFile.GetConstantPoolItem(string_index);
|
|
|
|
utf8.Resolve(classFile);
|
|
|
|
s = utf8.Value;
|
|
|
|
}
|
|
|
|
|
2003-12-20 01:19:18 +03:00
|
|
|
internal override ConstantType GetConstantType()
|
|
|
|
{
|
|
|
|
return ConstantType.String;
|
|
|
|
}
|
|
|
|
|
2002-12-18 19:00:25 +03:00
|
|
|
internal string Value
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private class ConstantPoolItemUtf8 : ConstantPoolItem
|
|
|
|
{
|
|
|
|
private string s;
|
|
|
|
|
|
|
|
internal ConstantPoolItemUtf8(string inputClassName, BigEndianBinaryReader br)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
s = br.ReadString();
|
|
|
|
}
|
|
|
|
catch(FormatException)
|
|
|
|
{
|
2004-02-02 12:46:13 +03:00
|
|
|
throw new ClassFormatError("{0} (Illegal UTF8 string in constant pool)", inputClassName);
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal string Value
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
}
|
2003-05-30 16:08:59 +04:00
|
|
|
|
|
|
|
internal string DottifiedValue
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return s.Replace('/', '.');
|
|
|
|
}
|
|
|
|
}
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
private enum Constant
|
|
|
|
{
|
|
|
|
Utf8 = 1,
|
|
|
|
Integer = 3,
|
|
|
|
Float = 4,
|
|
|
|
Long = 5,
|
|
|
|
Double = 6,
|
|
|
|
Class = 7,
|
|
|
|
String = 8,
|
|
|
|
Fieldref = 9,
|
|
|
|
Methodref = 10,
|
|
|
|
InterfaceMethodref = 11,
|
|
|
|
NameAndType = 12
|
|
|
|
}
|
|
|
|
|
|
|
|
internal class Attribute
|
|
|
|
{
|
|
|
|
private string name;
|
|
|
|
private BigEndianBinaryReader data;
|
|
|
|
|
|
|
|
private Attribute()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
internal static Attribute Read(ClassFile classFile, BigEndianBinaryReader br)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
int name_index = br.ReadUInt16();
|
2003-05-30 16:08:59 +04:00
|
|
|
string name = classFile.GetConstantPoolUtf8(name_index).Value;
|
2002-12-18 19:00:25 +03:00
|
|
|
int attribute_length = br.ReadInt32();
|
|
|
|
Attribute a = new Attribute();
|
|
|
|
a.name = name;
|
2004-08-17 13:05:21 +04:00
|
|
|
a.data = br.Section(attribute_length);
|
2002-12-18 19:00:25 +03:00
|
|
|
return a;
|
|
|
|
}
|
|
|
|
catch(InvalidCastException)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
catch(NullReferenceException)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
catch(IndexOutOfRangeException)
|
|
|
|
{
|
|
|
|
}
|
2004-02-02 12:46:13 +03:00
|
|
|
throw new ClassFormatError("{0} (Attribute name invalid type)", classFile.Name);
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
internal string Name
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal BigEndianBinaryReader Data
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return data.Duplicate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal class FieldOrMethod
|
|
|
|
{
|
|
|
|
private ClassFile classFile;
|
|
|
|
protected Modifiers access_flags;
|
|
|
|
private ushort name_index;
|
|
|
|
private ushort descriptor_index;
|
|
|
|
private Attribute[] attributes;
|
2003-01-06 16:56:37 +03:00
|
|
|
private TypeWrapper[] argTypeWrappers;
|
|
|
|
private TypeWrapper retTypeWrapper;
|
|
|
|
private TypeWrapper fieldTypeWrapper;
|
2004-08-17 13:05:21 +04:00
|
|
|
private Hashtable classCache;
|
2002-12-18 19:00:25 +03:00
|
|
|
|
2004-08-17 13:05:21 +04:00
|
|
|
internal FieldOrMethod(ClassFile classFile, Hashtable classCache, BigEndianBinaryReader br)
|
2002-12-18 19:00:25 +03:00
|
|
|
{
|
|
|
|
this.classFile = classFile;
|
2004-08-17 13:05:21 +04:00
|
|
|
this.classCache = classCache;
|
2002-12-18 19:00:25 +03:00
|
|
|
access_flags = (Modifiers)br.ReadUInt16();
|
|
|
|
// TODO check that name is ConstantPoolItemUtf8
|
|
|
|
name_index = br.ReadUInt16();
|
|
|
|
// TODO check that descriptor is ConstantPoolItemUtf8 and validate the descriptor
|
|
|
|
descriptor_index = br.ReadUInt16();
|
|
|
|
int attributes_count = br.ReadUInt16();
|
|
|
|
attributes = new Attribute[attributes_count];
|
|
|
|
for(int i = 0; i < attributes_count; i++)
|
|
|
|
{
|
|
|
|
attributes[i] = Attribute.Read(classFile, br);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal string Name
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
2003-05-30 16:08:59 +04:00
|
|
|
return classFile.GetConstantPoolUtf8(name_index).Value;
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal string Signature
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
2003-05-30 16:08:59 +04:00
|
|
|
return classFile.GetConstantPoolUtf8(descriptor_index).DottifiedValue;
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-01-06 16:56:37 +03:00
|
|
|
internal TypeWrapper[] GetArgTypes(ClassLoaderWrapper classLoader)
|
|
|
|
{
|
|
|
|
if(argTypeWrappers == null)
|
|
|
|
{
|
2004-08-17 13:05:21 +04:00
|
|
|
argTypeWrappers = ArgTypeWrapperListFromSig(classLoader, classCache, Signature);
|
2003-01-06 16:56:37 +03:00
|
|
|
}
|
|
|
|
return argTypeWrappers;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal TypeWrapper GetRetType(ClassLoaderWrapper classLoader)
|
|
|
|
{
|
|
|
|
if(retTypeWrapper == null)
|
|
|
|
{
|
2004-08-17 13:05:21 +04:00
|
|
|
retTypeWrapper = RetTypeWrapperFromSig(classLoader, classCache, Signature);
|
2003-01-06 16:56:37 +03:00
|
|
|
}
|
|
|
|
return retTypeWrapper;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal TypeWrapper GetFieldType(ClassLoaderWrapper classLoader)
|
|
|
|
{
|
|
|
|
if(fieldTypeWrapper == null)
|
|
|
|
{
|
2004-08-17 13:05:21 +04:00
|
|
|
fieldTypeWrapper = FieldTypeWrapperFromSig(classLoader, classCache, Signature);
|
2003-01-06 16:56:37 +03:00
|
|
|
}
|
|
|
|
return fieldTypeWrapper;
|
|
|
|
}
|
|
|
|
|
2002-12-18 19:00:25 +03:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected Attribute GetAttribute(string name)
|
|
|
|
{
|
|
|
|
foreach(Attribute attr in attributes)
|
|
|
|
{
|
|
|
|
if(attr.Name == name)
|
|
|
|
{
|
|
|
|
return attr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal ClassFile ClassFile
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return classFile;
|
|
|
|
}
|
|
|
|
}
|
2003-11-17 15:01:50 +03:00
|
|
|
|
|
|
|
internal bool DeprecatedAttribute
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return GetAttribute("Deprecated") != null;
|
|
|
|
}
|
|
|
|
}
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
internal class Field : FieldOrMethod
|
|
|
|
{
|
|
|
|
private object constantValue;
|
|
|
|
|
2004-08-17 13:05:21 +04:00
|
|
|
internal Field(ClassFile classFile, Hashtable classCache, BigEndianBinaryReader br) : base(classFile, classCache, br)
|
2002-12-18 19:00:25 +03:00
|
|
|
{
|
|
|
|
if((IsPrivate && IsPublic) || (IsPrivate && IsProtected) || (IsPublic && IsProtected)
|
|
|
|
|| (IsFinal && IsVolatile)
|
|
|
|
|| (classFile.IsInterface && (!IsPublic || !IsStatic || !IsFinal || IsTransient)))
|
|
|
|
{
|
2004-02-02 12:46:13 +03:00
|
|
|
throw new ClassFormatError("{0} (Illegal field modifiers: 0x{1:X})", classFile.Name, access_flags);
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
2003-12-20 01:19:18 +03:00
|
|
|
// spec (4.7.2) says we should silently ignore ConstantValue attribute on non-static fields
|
|
|
|
// NOTE a field doesn't have to be final to have a constant value!
|
|
|
|
if(IsStatic)
|
2002-12-18 19:00:25 +03:00
|
|
|
{
|
2003-12-20 01:19:18 +03:00
|
|
|
Attribute attr = GetAttribute("ConstantValue");
|
|
|
|
if(attr != null)
|
2002-12-18 19:00:25 +03:00
|
|
|
{
|
2003-12-20 01:19:18 +03:00
|
|
|
ushort index = attr.Data.ReadUInt16();
|
|
|
|
try
|
|
|
|
{
|
|
|
|
switch(Signature)
|
|
|
|
{
|
|
|
|
case "I":
|
|
|
|
constantValue = classFile.GetConstantPoolConstantInteger(index);
|
|
|
|
break;
|
|
|
|
case "S":
|
|
|
|
constantValue = (short)classFile.GetConstantPoolConstantInteger(index);
|
|
|
|
break;
|
|
|
|
case "B":
|
|
|
|
constantValue = (sbyte)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:
|
2004-02-02 12:46:13 +03:00
|
|
|
throw new ClassFormatError("{0} (Invalid signature for constant)", classFile.Name);
|
2003-12-20 01:19:18 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
catch(InvalidCastException)
|
2002-12-18 19:00:25 +03:00
|
|
|
{
|
2004-02-02 12:46:13 +03:00
|
|
|
throw new ClassFormatError("{0} (Bad index into constant pool)", classFile.Name);
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
2003-12-20 01:19:18 +03:00
|
|
|
catch(IndexOutOfRangeException)
|
2002-12-18 19:00:25 +03:00
|
|
|
{
|
2004-02-02 12:46:13 +03:00
|
|
|
throw new ClassFormatError("{0} (Bad index into constant pool)", classFile.Name);
|
2003-12-20 01:19:18 +03:00
|
|
|
}
|
|
|
|
catch(InvalidOperationException)
|
|
|
|
{
|
2004-02-02 12:46:13 +03:00
|
|
|
throw new ClassFormatError("{0} (Bad index into constant pool)", classFile.Name);
|
2003-12-20 01:19:18 +03:00
|
|
|
}
|
|
|
|
catch(NullReferenceException)
|
|
|
|
{
|
2004-02-02 12:46:13 +03:00
|
|
|
throw new ClassFormatError("{0} (Bad index into constant pool)", classFile.Name);
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal object ConstantValue
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return constantValue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal class Method : FieldOrMethod
|
|
|
|
{
|
|
|
|
private Code code;
|
|
|
|
|
2004-08-17 13:05:21 +04:00
|
|
|
internal Method(ClassFile classFile, Hashtable classCache, BigEndianBinaryReader br) : base(classFile, classCache, br)
|
2002-12-18 19:00:25 +03:00
|
|
|
{
|
|
|
|
// vmspec 4.6 says that all flags, except ACC_STRICT are ignored on <clinit>
|
2003-06-20 17:46:13 +04:00
|
|
|
if(Name == "<clinit>" && Signature == "()V")
|
2002-12-18 19:00:25 +03:00
|
|
|
{
|
|
|
|
access_flags &= Modifiers.Strictfp;
|
|
|
|
access_flags |= (Modifiers.Static | Modifiers.Private);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-06-14 14:36:38 +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)
|
2004-08-17 13:05:21 +04:00
|
|
|
if((Name == "<init>" && (IsStatic || IsSynchronized || IsFinal || IsAbstract || IsNative))
|
2002-12-18 19:00:25 +03:00
|
|
|
|| (IsPrivate && IsPublic) || (IsPrivate && IsProtected) || (IsPublic && IsProtected)
|
2004-06-14 14:36:38 +04:00
|
|
|
|| (IsAbstract && (IsFinal || IsNative || IsPrivate || IsStatic || IsSynchronized))
|
2002-12-18 19:00:25 +03:00
|
|
|
|| (classFile.IsInterface && (!IsPublic || !IsAbstract)))
|
|
|
|
{
|
2004-02-02 12:46:13 +03:00
|
|
|
throw new ClassFormatError("{0} (Illegal method modifiers: 0x{1:X})", classFile.Name, access_flags);
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// TODO if the method is abstract or native it may not have a Code attribute (right?)
|
|
|
|
// and if it is not abstract or native, it must have a Code attribute
|
|
|
|
}
|
|
|
|
|
2004-01-17 14:12:12 +03:00
|
|
|
internal bool IsStrictfp
|
2002-12-18 19:00:25 +03:00
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return (access_flags & Modifiers.Strictfp) != 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-08-13 19:00:41 +04:00
|
|
|
// Is this the <clinit>()V method?
|
|
|
|
internal bool IsClassInitializer
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return Name == "<clinit>" && Signature == "()V";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-12-18 19:00:25 +03:00
|
|
|
internal Code CodeAttribute
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
if(code == null)
|
|
|
|
{
|
|
|
|
Attribute attr = GetAttribute("Code");
|
|
|
|
if(attr != null)
|
|
|
|
{
|
|
|
|
code = new Code(this, attr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return code;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-11-17 15:01:50 +03:00
|
|
|
internal string[] ExceptionsAttribute
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
Attribute attr = GetAttribute("Exceptions");
|
|
|
|
if(attr != null)
|
|
|
|
{
|
|
|
|
BigEndianBinaryReader rdr = attr.Data;
|
|
|
|
ushort count = rdr.ReadUInt16();
|
|
|
|
string[] exceptions = new string[count];
|
|
|
|
for(int i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
exceptions[i] = ClassFile.GetConstantPoolClass(rdr.ReadUInt16());
|
|
|
|
}
|
|
|
|
return exceptions;
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-12-18 19:00:25 +03:00
|
|
|
internal class Code
|
|
|
|
{
|
|
|
|
private Method method;
|
|
|
|
private ushort max_stack;
|
|
|
|
private ushort max_locals;
|
|
|
|
private Instruction[] instructions;
|
|
|
|
private int[] pcIndexMap;
|
|
|
|
private ExceptionTableEntry[] exception_table;
|
|
|
|
private Attribute[] codeAttributes;
|
|
|
|
private int[] argmap;
|
|
|
|
private LineNumberTableEntry[] lineNumberTable;
|
|
|
|
private bool lineNumberTableCached;
|
|
|
|
private LocalVariableTableEntry[] localVariableTable;
|
|
|
|
private bool localVariableTableCached;
|
|
|
|
|
|
|
|
internal Code(Method method, Attribute attr)
|
|
|
|
{
|
|
|
|
this.method = method;
|
|
|
|
BigEndianBinaryReader br = attr.Data;
|
|
|
|
max_stack = br.ReadUInt16();
|
|
|
|
max_locals = br.ReadUInt16();
|
|
|
|
uint code_length = br.ReadUInt32();
|
|
|
|
ArrayList instructions = new ArrayList();
|
|
|
|
int basePosition = br.Position;
|
|
|
|
while(br.Position - basePosition < code_length)
|
|
|
|
{
|
|
|
|
instructions.Add(Instruction.Read(this, br.Position - basePosition, br));
|
|
|
|
}
|
|
|
|
// we add an additional nop instruction to make it easier for consumers of the code array
|
|
|
|
instructions.Add(new Instruction(this, br.Position - basePosition, ByteCode.__nop));
|
|
|
|
this.instructions = (Instruction[])instructions.ToArray(typeof(Instruction));
|
|
|
|
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();
|
|
|
|
codeAttributes = new Attribute[attributes_count];
|
|
|
|
for(int i = 0; i < attributes_count; i++)
|
|
|
|
{
|
|
|
|
codeAttributes[i] = Attribute.Read(method.ClassFile, br);
|
|
|
|
}
|
|
|
|
// build the pcIndexMap
|
|
|
|
pcIndexMap = new int[this.instructions[this.instructions.Length - 1].PC + 1];
|
|
|
|
for(int i = 0; i < pcIndexMap.Length; i++)
|
|
|
|
{
|
|
|
|
pcIndexMap[i] = -1;
|
|
|
|
}
|
2002-12-27 12:01:16 +03:00
|
|
|
for(int i = 0; i < this.instructions.Length - 1; i++)
|
2002-12-18 19:00:25 +03:00
|
|
|
{
|
|
|
|
pcIndexMap[this.instructions[i].PC] = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// maps argument 'slot' (as encoded in the xload/xstore instructions) into the ordinal
|
|
|
|
internal int[] ArgMap
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
if(argmap == null)
|
|
|
|
{
|
|
|
|
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])
|
|
|
|
{
|
|
|
|
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 = new int[args.Count];
|
|
|
|
args.CopyTo(argmap);
|
|
|
|
}
|
|
|
|
return argmap;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal Method Method
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return method;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal int MaxStack
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return max_stack;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal int MaxLocals
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return max_locals;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal Instruction[] Instructions
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return instructions;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// maps a PC to an index in the Instruction[], invalid PCs return -1
|
|
|
|
internal int[] PcIndexMap
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return pcIndexMap;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal ExceptionTableEntry[] ExceptionTable
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return exception_table;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private Attribute GetAttribute(string name)
|
|
|
|
{
|
|
|
|
foreach(Attribute attr in codeAttributes)
|
|
|
|
{
|
|
|
|
if(attr.Name == name)
|
|
|
|
{
|
|
|
|
return attr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal LineNumberTableEntry[] LineNumberTableAttribute
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
if(!lineNumberTableCached)
|
|
|
|
{
|
|
|
|
lineNumberTableCached = true;
|
|
|
|
Attribute attr = GetAttribute("LineNumberTable");
|
|
|
|
if(attr != null)
|
|
|
|
{
|
|
|
|
BigEndianBinaryReader rdr = attr.Data;
|
|
|
|
int count = rdr.ReadUInt16();
|
|
|
|
lineNumberTable = new LineNumberTableEntry[count];
|
|
|
|
for(int i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
lineNumberTable[i].start_pc = rdr.ReadUInt16();
|
|
|
|
lineNumberTable[i].line_number = rdr.ReadUInt16();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return lineNumberTable;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal LocalVariableTableEntry[] LocalVariableTableAttribute
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
if(!localVariableTableCached)
|
|
|
|
{
|
|
|
|
localVariableTableCached = true;
|
|
|
|
Attribute attr = GetAttribute("LocalVariableTable");
|
|
|
|
if(attr != null)
|
|
|
|
{
|
|
|
|
BigEndianBinaryReader rdr = attr.Data;
|
|
|
|
int count = rdr.ReadUInt16();
|
|
|
|
localVariableTable = new LocalVariableTableEntry[count];
|
|
|
|
for(int i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
localVariableTable[i].start_pc = rdr.ReadUInt16();
|
|
|
|
localVariableTable[i].length = rdr.ReadUInt16();
|
2003-05-30 16:08:59 +04:00
|
|
|
localVariableTable[i].name = method.ClassFile.GetConstantPoolUtf8(rdr.ReadUInt16()).Value;
|
|
|
|
localVariableTable[i].descriptor = method.ClassFile.GetConstantPoolUtf8(rdr.ReadUInt16()).DottifiedValue;
|
2002-12-18 19:00:25 +03:00
|
|
|
localVariableTable[i].index = rdr.ReadUInt16();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return localVariableTable;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal class ExceptionTableEntry
|
|
|
|
{
|
|
|
|
internal ushort start_pc;
|
|
|
|
internal ushort end_pc;
|
|
|
|
internal ushort handler_pc;
|
|
|
|
internal ushort catch_type;
|
|
|
|
internal int ordinal;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal class Instruction
|
|
|
|
{
|
|
|
|
private Method.Code method;
|
|
|
|
private int pc;
|
|
|
|
private ByteCode opcode;
|
|
|
|
private int arg1;
|
|
|
|
private int arg2;
|
|
|
|
private int default_offset;
|
|
|
|
private int[] values;
|
|
|
|
private int[] target_offsets;
|
|
|
|
|
|
|
|
internal Instruction(Method.Code method, int pc, ByteCode opcode)
|
|
|
|
: this(method, pc, opcode, 0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
private Instruction(Method.Code method, int pc, ByteCode opcode, int arg1)
|
|
|
|
: this(method, pc, opcode, arg1, 0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
private Instruction(Method.Code method, int pc, ByteCode opcode, int arg1, int arg2)
|
|
|
|
{
|
|
|
|
this.method = method;
|
|
|
|
this.pc = pc;
|
|
|
|
this.opcode = opcode;
|
|
|
|
this.arg1 = arg1;
|
|
|
|
this.arg2 = arg2;
|
|
|
|
}
|
|
|
|
|
|
|
|
private Instruction(Method.Code method, int pc, ByteCode opcode, int default_offset, int[] values, int[] target_offsets)
|
|
|
|
: this(method, pc, opcode)
|
|
|
|
{
|
|
|
|
this.default_offset = default_offset;
|
|
|
|
this.values = values;
|
|
|
|
this.target_offsets = target_offsets;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal static Instruction Read(Method.Code method, int pc, BigEndianBinaryReader br)
|
|
|
|
{
|
|
|
|
ByteCode bc = (ByteCode)br.ReadByte();
|
|
|
|
ByteCodeMode mode = ByteCodeMetaData.GetMode(bc);
|
|
|
|
if(bc == ByteCode.__wide)
|
|
|
|
{
|
|
|
|
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)
|
|
|
|
mode = ByteCodeMetaData.GetWideMode(bc);
|
|
|
|
}
|
|
|
|
switch(mode)
|
|
|
|
{
|
|
|
|
case ByteCodeMode.Simple:
|
|
|
|
return new Instruction(method, pc, bc);
|
|
|
|
case ByteCodeMode.Constant_1:
|
|
|
|
case ByteCodeMode.Local_1:
|
|
|
|
return new Instruction(method, pc, bc, br.ReadByte());
|
|
|
|
case ByteCodeMode.Constant_2:
|
|
|
|
case ByteCodeMode.Local_2:
|
|
|
|
return new Instruction(method, pc, bc, br.ReadUInt16());
|
|
|
|
case ByteCodeMode.Branch_2:
|
|
|
|
return new Instruction(method, pc, bc, br.ReadInt16());
|
|
|
|
case ByteCodeMode.Branch_4:
|
|
|
|
return new Instruction(method, pc, bc, br.ReadInt32());
|
|
|
|
case ByteCodeMode.Constant_2_1_1:
|
|
|
|
{
|
|
|
|
Instruction instr = new Instruction(method, pc, bc, br.ReadUInt16());
|
|
|
|
// TODO validate these
|
|
|
|
br.ReadByte(); // count
|
|
|
|
br.ReadByte(); // unused
|
|
|
|
return instr;
|
|
|
|
}
|
|
|
|
case ByteCodeMode.Immediate_1:
|
|
|
|
return new Instruction(method, pc, bc, br.ReadSByte());
|
|
|
|
case ByteCodeMode.Immediate_2:
|
|
|
|
return new Instruction(method, pc, bc, br.ReadInt16());
|
|
|
|
case ByteCodeMode.Local_1_Immediate_1:
|
|
|
|
return new Instruction(method, pc, bc, br.ReadByte(), br.ReadSByte());
|
|
|
|
case ByteCodeMode.Local_2_Immediate_2:
|
|
|
|
return new Instruction(method, pc, bc, br.ReadUInt16(), br.ReadInt16());
|
|
|
|
case ByteCodeMode.Constant_2_Immediate_1:
|
|
|
|
return new Instruction(method, pc, bc, br.ReadUInt16(), br.ReadSByte());
|
|
|
|
case ByteCodeMode.Tableswitch:
|
|
|
|
{
|
|
|
|
// skip the padding
|
|
|
|
int p = pc + 1;
|
|
|
|
int align = ((p + 3) & 0x7ffffffc) - p;
|
|
|
|
for(int i = 0; i < align; i++)
|
|
|
|
{
|
|
|
|
br.ReadByte();
|
|
|
|
}
|
|
|
|
int default_offset = br.ReadInt32();
|
|
|
|
int low = br.ReadInt32();
|
|
|
|
int high = br.ReadInt32();
|
|
|
|
int[] values = new int[high - low + 1];
|
|
|
|
int[] target_offset = new int[high - low + 1];
|
|
|
|
for(int i = low; i <= high; i++)
|
|
|
|
{
|
|
|
|
values[i - low] = i;
|
|
|
|
target_offset[i - low] = br.ReadInt32();
|
|
|
|
}
|
|
|
|
return new Instruction(method, pc, bc, default_offset, values, target_offset);
|
|
|
|
}
|
|
|
|
case ByteCodeMode.Lookupswitch:
|
|
|
|
{
|
|
|
|
// skip the padding
|
|
|
|
int p = pc + 1;
|
|
|
|
int align = ((p + 3) & 0x7ffffffc) - p;
|
|
|
|
for(int i = 0; i < align; i++)
|
|
|
|
{
|
|
|
|
br.ReadByte();
|
|
|
|
}
|
|
|
|
int default_offset = br.ReadInt32();
|
|
|
|
int count = br.ReadInt32();
|
|
|
|
int[] values = new int[count];
|
|
|
|
int[] target_offset = new int[count];
|
|
|
|
for(int i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
values[i] = br.ReadInt32();
|
|
|
|
target_offset[i] = br.ReadInt32();
|
|
|
|
}
|
|
|
|
return new Instruction(method, pc, bc, default_offset, values, target_offset);
|
|
|
|
}
|
|
|
|
default:
|
2004-02-02 12:46:13 +03:00
|
|
|
throw new ClassFormatError("Invalid opcode: {0}", bc);
|
2002-12-18 19:00:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal int PC
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return pc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal ByteCode OpCode
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return opcode;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal NormalizedByteCode NormalizedOpCode
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return ByteCodeMetaData.GetNormalizedByteCode(opcode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal int Arg1
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return arg1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal int Arg2
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return arg2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal int NormalizedArg1
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return ByteCodeMetaData.GetArg(opcode, arg1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal int DefaultOffset
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return default_offset;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal int[] Values
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return values;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal int[] TargetOffsets
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return target_offsets;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal Method.Code MethodCode
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return method;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal struct LineNumberTableEntry
|
|
|
|
{
|
|
|
|
internal int start_pc;
|
|
|
|
internal int line_number;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal struct LocalVariableTableEntry
|
|
|
|
{
|
|
|
|
internal int start_pc;
|
|
|
|
internal int length;
|
|
|
|
internal string name;
|
|
|
|
internal string descriptor;
|
|
|
|
internal int index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|