From 4304b157308ef9511f63abc66e8da44291bf7c41 Mon Sep 17 00:00:00 2001 From: Gilles Dubochet Date: Wed, 6 May 2009 13:44:21 +0000 Subject: MSIL is built as part of Sabbus, take 2. --- src/msil/ch/epfl/lamp/compiler/msil/Assembly.java | 254 +++ .../ch/epfl/lamp/compiler/msil/AssemblyName.java | 97 + src/msil/ch/epfl/lamp/compiler/msil/Attribute.java | 558 ++++++ .../ch/epfl/lamp/compiler/msil/BindingFlags.java | 170 ++ .../lamp/compiler/msil/CallingConventions.java | 76 + .../epfl/lamp/compiler/msil/ConstructorInfo.java | 55 + .../compiler/msil/CustomAttributeProvider.java | 83 + .../epfl/lamp/compiler/msil/EventAttributes.java | 33 + src/msil/ch/epfl/lamp/compiler/msil/EventInfo.java | 59 + .../epfl/lamp/compiler/msil/FieldAttributes.java | 120 ++ src/msil/ch/epfl/lamp/compiler/msil/FieldInfo.java | 113 ++ .../compiler/msil/ICustomAttributeProvider.java | 58 + .../ch/epfl/lamp/compiler/msil/MemberInfo.java | 48 + .../ch/epfl/lamp/compiler/msil/MemberTypes.java | 82 + .../epfl/lamp/compiler/msil/MethodAttributes.java | 159 ++ .../ch/epfl/lamp/compiler/msil/MethodBase.java | 145 ++ .../lamp/compiler/msil/MethodImplAttributes.java | 117 ++ .../ch/epfl/lamp/compiler/msil/MethodInfo.java | 57 + src/msil/ch/epfl/lamp/compiler/msil/Module.java | 156 ++ .../ch/epfl/lamp/compiler/msil/PEAssembly.java | 70 + src/msil/ch/epfl/lamp/compiler/msil/PEFile.java | 870 +++++++++ src/msil/ch/epfl/lamp/compiler/msil/PEModule.java | 327 ++++ src/msil/ch/epfl/lamp/compiler/msil/PEType.java | 399 ++++ .../lamp/compiler/msil/ParameterAttributes.java | 73 + .../ch/epfl/lamp/compiler/msil/ParameterInfo.java | 77 + .../lamp/compiler/msil/PropertyAttributes.java | 46 + .../ch/epfl/lamp/compiler/msil/PropertyInfo.java | 105 ++ src/msil/ch/epfl/lamp/compiler/msil/Type.java | 1042 +++++++++++ .../ch/epfl/lamp/compiler/msil/TypeAttributes.java | 191 ++ src/msil/ch/epfl/lamp/compiler/msil/Version.java | 72 + .../lamp/compiler/msil/emit/AssemblyBuilder.scala | 125 ++ .../compiler/msil/emit/ConstructorBuilder.scala | 65 + .../epfl/lamp/compiler/msil/emit/EmitUtils.scala | 55 + .../epfl/lamp/compiler/msil/emit/EmitUtils.scala2 | 55 + .../lamp/compiler/msil/emit/EmptyVisitor.scala | 83 + .../lamp/compiler/msil/emit/EmptyVisitor.scala2 | 83 + .../lamp/compiler/msil/emit/FieldBuilder.scala | 58 + .../msil/emit/ICustomAttributeSetter.scala | 19 + .../epfl/lamp/compiler/msil/emit/ILGenerator.scala | 538 ++++++ .../lamp/compiler/msil/emit/ILPrinterVisitor.scala | 735 ++++++++ .../ch/epfl/lamp/compiler/msil/emit/Label.scala | 149 ++ .../lamp/compiler/msil/emit/LocalBuilder.scala | 45 + .../lamp/compiler/msil/emit/MethodBuilder.scala | 71 + .../lamp/compiler/msil/emit/ModuleBuilder.scala | 134 ++ .../msil/emit/MultipleFilesILPrinterVisitor.scala | 139 ++ .../ch/epfl/lamp/compiler/msil/emit/OpCode.scala | 1935 ++++++++++++++++++++ .../ch/epfl/lamp/compiler/msil/emit/OpCodes.scala | 1196 ++++++++++++ .../lamp/compiler/msil/emit/ParameterBuilder.scala | 45 + .../msil/emit/SingleFileILPrinterVisitor.scala | 94 + .../epfl/lamp/compiler/msil/emit/TypeBuilder.scala | 230 +++ .../epfl/lamp/compiler/msil/emit/Visitable.scala | 25 + .../ch/epfl/lamp/compiler/msil/emit/Visitor.scala | 59 + .../compiler/msil/tests/CustomAttributesTest.java | 32 + .../lamp/compiler/msil/tests/JavaTypeTest.java | 19 + .../epfl/lamp/compiler/msil/tests/MembersTest.java | 101 + .../epfl/lamp/compiler/msil/tests/TableDump.java | 312 ++++ .../ch/epfl/lamp/compiler/msil/tests/Test.java | 93 + .../ch/epfl/lamp/compiler/msil/util/PESection.java | 58 + .../ch/epfl/lamp/compiler/msil/util/PEStream.java | 200 ++ .../ch/epfl/lamp/compiler/msil/util/Signature.java | 119 ++ .../ch/epfl/lamp/compiler/msil/util/Table.java | 1600 ++++++++++++++++ .../epfl/lamp/compiler/msil/util/VJSAssembly.java | 294 +++ .../epfl/lamp/compiler/msil/util/VJSAssembly.java2 | 294 +++ 63 files changed, 14772 insertions(+) create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/Assembly.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/AssemblyName.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/Attribute.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/BindingFlags.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/CallingConventions.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/ConstructorInfo.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/CustomAttributeProvider.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/EventAttributes.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/EventInfo.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/FieldAttributes.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/FieldInfo.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/ICustomAttributeProvider.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/MemberInfo.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/MemberTypes.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/MethodAttributes.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/MethodBase.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/MethodImplAttributes.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/MethodInfo.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/Module.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/PEAssembly.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/PEFile.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/PEModule.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/PEType.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/ParameterAttributes.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/ParameterInfo.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/PropertyAttributes.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/PropertyInfo.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/Type.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/TypeAttributes.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/Version.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/emit/AssemblyBuilder.scala create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/emit/ConstructorBuilder.scala create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/emit/EmitUtils.scala create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/emit/EmitUtils.scala2 create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/emit/EmptyVisitor.scala create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/emit/EmptyVisitor.scala2 create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/emit/FieldBuilder.scala create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/emit/ICustomAttributeSetter.scala create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/emit/ILGenerator.scala create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/emit/ILPrinterVisitor.scala create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/emit/Label.scala create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/emit/LocalBuilder.scala create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/emit/MethodBuilder.scala create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/emit/ModuleBuilder.scala create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/emit/MultipleFilesILPrinterVisitor.scala create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/emit/OpCode.scala create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/emit/OpCodes.scala create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/emit/ParameterBuilder.scala create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/emit/SingleFileILPrinterVisitor.scala create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/emit/TypeBuilder.scala create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/emit/Visitable.scala create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/emit/Visitor.scala create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/tests/CustomAttributesTest.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/tests/JavaTypeTest.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/tests/MembersTest.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/tests/TableDump.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/tests/Test.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/util/PESection.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/util/PEStream.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/util/Signature.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/util/Table.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/util/VJSAssembly.java create mode 100644 src/msil/ch/epfl/lamp/compiler/msil/util/VJSAssembly.java2 (limited to 'src/msil/ch/epfl/lamp') diff --git a/src/msil/ch/epfl/lamp/compiler/msil/Assembly.java b/src/msil/ch/epfl/lamp/compiler/msil/Assembly.java new file mode 100644 index 0000000000..509575b26e --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/Assembly.java @@ -0,0 +1,254 @@ +/* + * System.Reflection-like API for access to .NET assemblies (DLL & EXE) + */ + +// $Id$ + +package ch.epfl.lamp.compiler.msil; + +import ch.epfl.lamp.compiler.msil.util.Table; +import ch.epfl.lamp.compiler.msil.util.Table.AssemblyDef; +import ch.epfl.lamp.compiler.msil.util.Table.ModuleDef; + +import java.util.HashMap; +import java.util.Iterator; +import java.io.File; +import java.io.FileNotFoundException; + +/** + * Defines an Assembly, which is a reusable, versionable, and self-describing + * building block of a common language runtime application. + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +public abstract class Assembly extends CustomAttributeProvider { + + //########################################################################## + // static members + + // all the assemblies + public static final HashMap assemblies = new HashMap(); + + /** Loads an assembly from the specified path. */ + public static Assembly LoadFrom(String assemblyFileName) { + File afile = new File(assemblyFileName); + return LoadFrom(afile.getParentFile(), afile.getName()); + } + + /** Loads an assembly with the given name from the given directory. */ + public static Assembly LoadFrom(File dir, String name) { + File file = null; + PEFile pefile = null; +// try { +// if (dir == null) +// dir = new File("."); +// dir = dir.getCanonicalFile(); +// } catch (java.io.IOException e) {} + + if (name.endsWith(".exe") || name.endsWith(".EXE") || + name.endsWith(".dll") || name.endsWith(".DLL")) + { + file = new File(dir, name); + pefile = getPEFile(file); + name = name.substring(0, name.length() - 4); + } + + File adir = pefile == null ? new File(dir, name) : null; + + if (pefile == null) { + file = new File(dir, name + ".dll"); + pefile = getPEFile(file); + } + if (pefile == null) { + file = new File(dir, name + ".DLL"); + pefile = getPEFile(file); + } + if (pefile == null && adir.exists()) { + file = new File(adir, name + ".dll"); + pefile = getPEFile(file); + } + if (pefile == null && adir.exists()) { + file = new File(adir, name + ".DLL"); + pefile = getPEFile(file); + } + + if (pefile == null) { + file = new File(dir, name + ".exe"); + pefile = getPEFile(file); + } + if (pefile == null) { + file = new File(dir, name + ".EXE"); + pefile = getPEFile(file); + } + if (pefile == null && adir.exists()) { + file = new File(adir, name + ".exe"); + pefile = getPEFile(file); + } + if (pefile == null && adir.exists()) { + file = new File(adir, name + ".EXE"); + pefile = getPEFile(file); + } + + if (pefile == null) + throw new RuntimeException("Cannot find assembly " + new File(dir, name)); + return getPEAssembly(pefile); + } + + private static Assembly getPEAssembly(PEFile pefile) { + AssemblyDef assem = pefile.AssemblyDef; + if (assem == null) + throw new RuntimeException("File " + pefile + + " does not contain a manifest"); + assem.readRow(1); + String name = pefile.getString(assem.Name); + Assembly a = (Assembly) assemblies.get(name); + if (a != null) { + return a; + } + + AssemblyName an = new AssemblyName(); + an.Name = pefile.getString(assem.Name); + an.Version = new Version(assem.MajorVersion, assem.MinorVersion, + assem.BuildNumber, assem.RevisionNumber); + an.SetPublicKey(pefile.getBlob(assem.PublicKey)); + return new PEAssembly(pefile, an); + } + + protected static PEFile getPEFile(File f) { + PEFile pefile = null; + try { pefile = new PEFile(f.getAbsolutePath()); } + catch (FileNotFoundException e) {} + catch (RuntimeException e) {} + return pefile; + } + + //########################################################################## + // public fields + + /** The entry point of this assembly. */ + public MethodInfo EntryPoint; + + /** the display name of the assembly. */ + public final String FullName; + + //########################################################################## + // constructor + + protected Assembly(AssemblyName an, boolean external) { + assemblyName = an; + FullName = an.toString(); + if(external) { + assemblies.put(an.Name, this); + } + //System.out.println("assemblies after adding the current one: " + assemblies); + } + + protected Assembly(AssemblyName an) { + this(an, false); + } + + protected static Assembly getAssembly(String name) { + return (Assembly) assemblies.get(name); + } + + //########################################################################## + // instrumental methods + + /** @return the file from which this assembly was loaded. */ + public File getFile() { + throw new RuntimeException("Not supported"); + } + + /** Gets the specified module in this assembly. Works on filenames. */ + public Module GetModule(String name) { + initModules(); + return (Module)modulesMap.get(name); + } + + /** Get all the modules of the assembly. */ + public Module[] GetModules() { + initModules(); + return (Module[])modulesMap.values(). + toArray(new Module[modulesMap.size()]); + } + + /** Get the corresponding type. */ + public Type GetType(String name) { + initModules(); + Iterator modules = modulesMap.values().iterator(); + Type t = null; + while (t == null && modules.hasNext()) { + t = ((Module)modules.next()).GetType(name); + } + return t; + } + + /** @return an array of all types defined in the assembly. */ + public synchronized Type[] GetTypes() { + if (types != null) + return (Type[])types.clone(); + initModules(); + + Iterator modules = modulesMap.values().iterator(); + Type[] newTypes = ((Module)modules.next()).GetTypes(); + while (modules.hasNext()) { + Module module = (Module)modules.next(); + Type[] mtypes = module.GetTypes(); + Type[] oldTypes = newTypes; + newTypes = new Type[oldTypes.length + mtypes.length]; + System.arraycopy(oldTypes, 0, newTypes, 0, oldTypes.length); + System.arraycopy(mtypes, 0, newTypes, oldTypes.length, mtypes.length); + } + types = newTypes; + return (Type[]) types.clone(); + } + + public AssemblyName GetName() { + return assemblyName; + } + + public String toString() { + return FullName; + } + + //########################################################################## + // protected members + + // the assembly name + protected final AssemblyName assemblyName; + + // all the types exported by the assembly + protected Type[] types = null; + + // the module defined in this assembly (only one right now) + private final HashMap/**/ modulesMap = new HashMap(); + + protected void addType(Type type) { + Type.addType(type); + } + + protected void addModule(String name, Module module) { + modulesMap.put(name, module); + } + + private boolean initModules = true; + protected final void initModules() { + if (initModules) { + loadModules(); + initModules = false; + } + } + + /** used for lazy construction of the Assembly. */ + protected abstract void loadModules(); + + void dumpTypes() { + Type[] types = GetTypes(); + for (int i = 0; i < types.length; i++) + System.out.println(types[i]); + } + + //########################################################################## + +} // class Assembly diff --git a/src/msil/ch/epfl/lamp/compiler/msil/AssemblyName.java b/src/msil/ch/epfl/lamp/compiler/msil/AssemblyName.java new file mode 100644 index 0000000000..3e1b6a6f57 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/AssemblyName.java @@ -0,0 +1,97 @@ +/* + * System.Reflection-like API for access to .NET assemblies (DLL & EXE) + */ + +// $Id$ + +package ch.epfl.lamp.compiler.msil; + +import javax.crypto.Mac; + +import java.security.MessageDigest; + +import ch.epfl.lamp.compiler.msil.util.Table; + +/** + * Fully describes an assembly's unique identity. + * Right now it's only the name + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +public class AssemblyName { + + //########################################################################## + // public interface + + /** The simple, unencrypted name of the assembly. */ + public String Name; + + /** + * Gets or sets the major, minor, revision, and build numbers + * of the assembly. + */ + public Version Version; + + /** + * Gets a strong name consisting of a public key, a given name, + * and version parts. + */ + public byte[] GetPublicKeyToken() { + return publicKeyToken == null ? null : (byte[]) publicKeyToken.clone(); + } + + /** + * Sets a strong name consisting of a public key, a given name, + * and version parts. + */ + public void SetPublicKeyToken(byte[] key) { + this.publicKeyToken = key.length == 0 ? null : (byte[]) key.clone(); + } + + /** + * Returns the public key identifying the originator of the assembly. + */ + public byte[] GetPublicKey() { + return publicKey == null ? null : (byte[]) publicKey.clone(); + } + + /** + * Sets the public key identifying the originator of the assembly. + */ + public void SetPublicKey(byte[] key) { + if (key.length > 0) { + this.publicKey = (byte[]) key.clone(); + byte[] hash = sha.digest(key); + byte[] keyToken = new byte[8]; + for (int i = 0; i < keyToken.length; i++) + keyToken[i] = hash[hash.length - 1 - i]; + this.publicKeyToken = keyToken; + //System.out.println("Pubic key and key token of assembly " + this + ":"); + //System.out.println("\tPublic key = " + Table.bytes2hex(key)); + //System.out.println("\tKey token = " + Table.bytes2hex(keyToken)); + } + } + + public String toString() { + return Name + ", Version=" + Version; + } + + //########################################################################## + + private byte[] publicKeyToken; + + private byte[] publicKey; + + private static final MessageDigest sha; + static { + MessageDigest md = null; + try { + md = MessageDigest.getInstance("SHA"); + } catch (java.security.NoSuchAlgorithmException e) {} + sha = md; + } + + //########################################################################## + +} // class AssemblyName diff --git a/src/msil/ch/epfl/lamp/compiler/msil/Attribute.java b/src/msil/ch/epfl/lamp/compiler/msil/Attribute.java new file mode 100644 index 0000000000..b136f9423e --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/Attribute.java @@ -0,0 +1,558 @@ +/* + * System.Reflection-like API for access to .NET assemblies (DLL & EXE) + */ + +// $Id$ + +package ch.epfl.lamp.compiler.msil; + +import ch.epfl.lamp.compiler.msil.util.Signature; + +import java.util.Map; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Iterator; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.io.UnsupportedEncodingException; + +/** + * Describes custom attribute instances. + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +public class Attribute { + + //########################################################################## + + private final ConstructorInfo constr; + + private final byte[] value; + + Attribute(ConstructorInfo constr, byte[] value) { + assert constr != null; + this.constr = constr; + assert value != null : constr.toString(); + this.value = value; + } + + //########################################################################## + // public interface + + /** @return the type (class) of the attribute. */ + public Type GetType() { return constr.DeclaringType; } + + /** @return the constructor of this attribute. */ + public ConstructorInfo getConstructor() { + return constr; + } + + /** @return the Blob with serialized constructor & named arguments. */ + public byte[] getValue() { + byte[] value = new byte[this.value.length]; + System.arraycopy(this.value, 0, value, 0, value.length); + return value; + } + + /**@return an array with the arguments to the attribute's contructor. */ + public Object[] getConstructorArguments() { + parseBlob(); + Object[] cas = new Object[constrArgs.length]; + System.arraycopy(constrArgs, 0, cas, 0, cas.length); + return cas; + } + + /** @return the named argument with the given name. */ + public NamedArgument getNamedArgument(String name) { + return (NamedArgument)namedArgs.get(name); + } + + /** @return an array of all named arguments for this attribute. */ + public NamedArgument[] getNamedArguments() { + NamedArgument[] nargs = + (NamedArgument[])namedArgs.values().toArray(NamedArgument.EMPTY); + return nargs; + } + + /** @return a string representation of this attribute. */ + public String toString() { + parseBlob(); + ParameterInfo[] params = constr.GetParameters(); + assert params.length == constrArgs.length : this.constr; + StringBuffer str = new StringBuffer(); + str.append('['); + str.append(constr.DeclaringType.FullName); + str.append('('); + for (int i = 0; i < constrArgs.length; i++) { + if (i > 0) + str.append(", "); + Type t = params[i].ParameterType; + if (t.IsEnum()) { + str.append('('); + str.append(t.FullName); + str.append(')'); + } + formatValue(str, constrArgs[i]); + } + NamedArgument[] nargs = getNamedArguments(); + for (int i = 0; i < nargs.length; i++) { + str.append(", ").append(nargs[i]); + } + str.append(")]"); + return str.toString(); + } + + //######################################################################### + + private static final Map type2id = new HashMap(); + private static final Map id2type = new HashMap(); + static { + map("Boolean", Signature.ELEMENT_TYPE_BOOLEAN); + map("Char", Signature.ELEMENT_TYPE_CHAR); + map("SByte", Signature.ELEMENT_TYPE_I1); + map("Byte", Signature.ELEMENT_TYPE_U1); + map("Int16", Signature.ELEMENT_TYPE_I2); + map("UInt16", Signature.ELEMENT_TYPE_U2); + map("Int32", Signature.ELEMENT_TYPE_I4); + map("UInt32", Signature.ELEMENT_TYPE_U4); + map("Int64", Signature.ELEMENT_TYPE_I8); + map("UInt64", Signature.ELEMENT_TYPE_U8); + map("Single", Signature.ELEMENT_TYPE_R4); + map("Double", Signature.ELEMENT_TYPE_R8); + map("String", Signature.ELEMENT_TYPE_STRING); + map("Type", Signature.X_ELEMENT_TYPE_TYPE); + map("Object", Signature.ELEMENT_TYPE_OBJECT); + } + private static void map(String type, int id) { + Type t = Type.GetType("System." + type); + assert type != null : type + " -> " + id; + Integer i = new Integer(id); + type2id.put(t, i); + id2type.put(i, t); + } + private static int getTypeId(Type type) { + Integer id = (Integer)type2id.get(type); + assert id != null : type; + return id.intValue(); + } + + private Object[] constrArgs; + private Map namedArgs; + private ByteBuffer buf; + + private void parseBlob() { + try { parseBlob0(); } + catch (RuntimeException e) { + throw new RuntimeException(PEFile.bytes2hex(value), e); + } + } + + private void parseBlob0() { + if (buf != null) + return; + buf = ByteBuffer.wrap(value); + buf.order(ByteOrder.LITTLE_ENDIAN); + + short sig = buf.getShort(); + assert sig == 1 : PEFile.bytes2hex(value); + ParameterInfo[] params = constr.GetParameters(); + constrArgs = new Object[params.length]; + for (int i = 0; i < params.length; i++) { + constrArgs[i] = parseElement(params[i].ParameterType); + } + + int ncount = buf.getShort(); + namedArgs = new LinkedHashMap(); + for (int i = 0; i < ncount; i++) { + int designator = buf.get(); + assert designator == Signature.X_ELEMENT_KIND_FIELD + || designator == Signature.X_ELEMENT_KIND_PROPERTY + : "0x" + PEFile.byte2hex(designator); + Type type = parseType(); + String name = parseString(); + Object value = parseElement(type); + NamedArgument narg = + new NamedArgument(designator, name, type, value); + namedArgs.put(name, narg); + } + } + + private Object parseElement(Type type) { + if (type.IsArray()) + return parseArray(type.GetElementType()); + if (type.IsEnum()) + return parseElement(type.getUnderlyingType()); + return parseElement(getTypeId(type)); + } + + private Object parseElement(int id) { + switch (id) { + case Signature.ELEMENT_TYPE_BOOLEAN: + return new Boolean(buf.get() == 0 ? false : true); + case Signature.ELEMENT_TYPE_CHAR: + return new Character(buf.getChar()); + case Signature.ELEMENT_TYPE_I1: + case Signature.ELEMENT_TYPE_U1: + return new Byte(buf.get()); + case Signature.ELEMENT_TYPE_I2: + case Signature.ELEMENT_TYPE_U2: + return new Short(buf.getShort()); + case Signature.ELEMENT_TYPE_I4: + case Signature.ELEMENT_TYPE_U4: + return new Integer(buf.getInt()); + case Signature.ELEMENT_TYPE_I8: + case Signature.ELEMENT_TYPE_U8: + return new Long(buf.getLong()); + case Signature.ELEMENT_TYPE_R4: + return new Float(buf.getFloat()); + case Signature.ELEMENT_TYPE_R8: + return new Double(buf.getDouble()); + case Signature.ELEMENT_TYPE_STRING: + return parseString(); + case Signature.X_ELEMENT_TYPE_TYPE: + return getType(); + case Signature.ELEMENT_TYPE_OBJECT: + Type type = parseType(); + return new BoxedArgument(type, parseElement(type)); + default: + throw new RuntimeException("Unknown type id: " + id); + } + } + + private Object parseArray(Type type) { + if (type.IsEnum()) + return parseArray(type.getUnderlyingType()); + return parseArray(getTypeId(type)); + } + + private Object parseArray(int id) { + switch (id) { + case Signature.ELEMENT_TYPE_BOOLEAN: + return parseBooleanArray(); + case Signature.ELEMENT_TYPE_CHAR: + return parseCharArray(); + case Signature.ELEMENT_TYPE_I1: + case Signature.ELEMENT_TYPE_U1: + return parseByteArray(); + case Signature.ELEMENT_TYPE_I2: + case Signature.ELEMENT_TYPE_U2: + return parseShortArray(); + case Signature.ELEMENT_TYPE_I4: + case Signature.ELEMENT_TYPE_U4: + return parseIntArray(); + case Signature.ELEMENT_TYPE_I8: + case Signature.ELEMENT_TYPE_U8: + return parseLongArray(); + case Signature.ELEMENT_TYPE_R4: + return parseFloatArray(); + case Signature.ELEMENT_TYPE_R8: + return parseDoubleArray(); + case Signature.ELEMENT_TYPE_STRING: + return parseStringArray(); + case Signature.X_ELEMENT_TYPE_ENUM: + return parseArray(getType()); + default: + throw new RuntimeException("Unknown type id: " + id); + } + } + + private Type parseType() { + int id = buf.get(); + switch (id) { + case Signature.ELEMENT_TYPE_SZARRAY: + return Type.mkArray(parseType(), 1); + case Signature.X_ELEMENT_TYPE_ENUM: + return getType(); + default: + Type t = (Type)id2type.get(new Integer(id)); + assert t != null : PEFile.byte2hex(id); + return t; + } + } + + private Type getType() { + String typename = parseString(); + int i = typename.indexOf(','); + // fully qualified assembly name follows + // just strip it on the assumtion theat the + // assembly is referenced in the externs and the + // type will be found + String name = (i < 0) ? typename : typename.substring(0, i); + Type t = Type.GetType(name); + if (t == null && i > 0) { + int j = typename.indexOf(',', i + 1); + if (j > 0) { + String assemName = typename.substring(i + 1, j); + try { + Assembly.LoadFrom(assemName); + } catch (Throwable e) { + throw new RuntimeException(typename, e); + } + t = Type.GetType(name); + } + } + assert t != null : typename; + return t; + } + + private boolean[] parseBooleanArray() { + boolean[] arr = new boolean[buf.getInt()]; + for (int i = 0; i < arr.length; i++) + arr[i] = buf.get() == 0 ? false : true; + return arr; + } + + private char[] parseCharArray() { + char[] arr = new char[buf.getInt()]; + for (int i = 0; i < arr.length; i++) + arr[i] = buf.getChar(); + return arr; + } + + private byte[] parseByteArray() { + byte[] arr = new byte[buf.getInt()]; + for (int i = 0; i < arr.length; i++) + arr[i] = buf.get(); + return arr; + } + + private short[] parseShortArray() { + short[] arr = new short[buf.getInt()]; + for (int i = 0; i < arr.length; i++) + arr[i] = buf.getShort(); + return arr; + } + + private int[] parseIntArray() { + int[] arr = new int[buf.getInt()]; + for (int i = 0; i < arr.length; i++) + arr[i] = buf.getInt(); + return arr; + } + + private long[] parseLongArray() { + long[] arr = new long[buf.getInt()]; + for (int i = 0; i < arr.length; i++) + arr[i] = buf.getLong(); + return arr; + } + + private float[] parseFloatArray() { + float[] arr = new float[buf.getInt()]; + for (int i = 0; i < arr.length; i++) + arr[i] = buf.getFloat(); + return arr; + } + + private double[] parseDoubleArray() { + double[] arr = new double[buf.getInt()]; + for (int i = 0; i < arr.length; i++) + arr[i] = buf.getDouble(); + return arr; + } + + private String[] parseStringArray() { + String[] arr = new String[buf.getInt()]; + for (int i = 0; i < arr.length; i++) + arr[i] = parseString(); + return arr; + } + + private String parseString() { + String str = null; + int length = parseLength(); + if (length < 0) + return null; + try { str = new String(value, buf.position(), length, "UTF-8" ); } + catch (UnsupportedEncodingException e) { throw new Error(e); } + buf.position(buf.position() + length); + return str; + } + + private int getByte() { + return (buf.get() + 0x0100) & 0xff; + } + + public int parseLength() { + int length = getByte(); + // check for invalid length format: the first, second or third + // most significant bits should be 0; if all are 1 the length is invalid. + if ((length & 0xe0) == 0xe0) + return -1; + if ((length & 0x80) != 0) { + length = ((length & 0x7f) << 8) | getByte(); + if ((length & 0x4000) != 0) + length = ((length & 0x3fff) << 16) | (getByte()<<8) | getByte(); + } + return length; + } + + //########################################################################## + private static void formatValue(StringBuffer str, Object o) { + Class c = (o == null) ? null : o.getClass(); + if (c == null) { + str.append(""); + } else if (c == String.class) { + str.append('"'); + str.append(o); + str.append('"'); + } else if (c == Character.class) { + str.append('\''); + str.append(o); + str.append('\''); + } else if (c == boolean[].class) { + str.append("new boolean[] {"); + boolean[] arr = (boolean[])o; + for (int i = 0; i < arr.length; i++) { + if (i > 0) str.append(", "); + str.append(arr[i]); + } + str.append('}'); + } else if (c == char[].class) { + str.append("new short[] {"); + short[] arr = (short[])o; + for (int i = 0; i < arr.length; i++) { + if (i > 0) str.append(", "); + str.append(arr[i]); + } + str.append('}'); + } else if (c == byte[].class) { + str.append("new byte[] {"); + byte[] arr = (byte[])o; + for (int i = 0; i < arr.length; i++) { + if (i > 0) str.append(", "); + str.append(arr[i]); + } + str.append('}'); + } else if (c == short[].class) { + str.append("new short[] {"); + short[] arr = (short[])o; + for (int i = 0; i < arr.length; i++) { + if (i > 0) str.append(", "); + str.append(arr[i]); + } + str.append('}'); + } else if (c == int[].class) { + str.append("new int[] {"); + int[] arr = (int[])o; + for (int i = 0; i < arr.length; i++) { + if (i > 0) str.append(", "); + str.append(arr[i]); + } + str.append('}'); + } else if (c == long[].class) { + str.append("new long[] {"); + long[] arr = (long[])o; + for (int i = 0; i < arr.length; i++) { + if (i > 0) str.append(", "); + str.append(arr[i]); + } + str.append('}'); + } else if (c == float[].class) { + str.append("new float[] {"); + float[] arr = (float[])o; + for (int i = 0; i < arr.length; i++) { + if (i > 0) str.append(", "); + str.append(arr[i]); + } + str.append('}'); + } else if (c == double[].class) { + str.append("new double[] {"); + double[] arr = (double[])o; + for (int i = 0; i < arr.length; i++) { + if (i > 0) str.append(", "); + str.append(arr[i]); + } + str.append('}'); + } else if (c == String[].class) { + str.append("new String[] {"); + String[] arr = (String[])o; + for (int i = 0; i < arr.length; i++) { + if (i > 0) str.append(", "); + formatValue(str, arr[i]); + } + str.append('}'); + } else if (o instanceof Type) { + str.append("typeof("); + str.append(o); + str.append(")"); + } else + str.append(o); + } + + //########################################################################## + + /** Represents named arguments (assigned outside of the constructor) + * of a custom attribute + */ + public static class NamedArgument { + + /** Designates if the named argument corresponds to a field or property. + * Possible values: + * Signature.X_ELEMENT_KIND_FIELD = 0x53 + * Signature.X_ELEMENT_KIND_PROPERTY = 0x54 + */ + public final int designator; + + /** The name of the field/property. */ + public final String name; + + /** Type of the field/property. */ + public final Type type; + + /** The value for the field/property. */ + public final Object value; + + /** An empty array NamedArgument. */ + public static final NamedArgument[] EMPTY = new NamedArgument[0]; + + public NamedArgument(int designator, String name,Type type,Object value) + { + this.designator = designator; + this.name = name; + this.type = type; + this.value = value; + } + + /** @return true if the named argument specifies a field; + * false otherwise. + */ + public boolean isField() { + return designator == Signature.X_ELEMENT_KIND_FIELD; + } + + /** @return true if the named argument specifies a property; + * false otherwise. + */ + public boolean isProperty() { + return designator == Signature.X_ELEMENT_KIND_PROPERTY; + } + + /** @return a string representation of the named argument. */ + public String toString() { + StringBuffer str = new StringBuffer(name); + str.append(" = "); + if (type.IsEnum()) + str.append('(').append(type.FullName).append(')'); + formatValue(str, value); + return str.toString(); + } + } + + //########################################################################## + + protected static final class BoxedArgument { + public final Type type; + public final Object value; + public BoxedArgument(Type type, Object value) { + this.type = type; this.value = value; + } + public String toString() { + return "(" + type.FullName + ")" + value; + } + } + + //########################################################################## + +} // class Attribute diff --git a/src/msil/ch/epfl/lamp/compiler/msil/BindingFlags.java b/src/msil/ch/epfl/lamp/compiler/msil/BindingFlags.java new file mode 100644 index 0000000000..c9a024409c --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/BindingFlags.java @@ -0,0 +1,170 @@ +/* + * System.Reflection-like API for access to .NET assemblies (DLL & EXE) + */ + +// $Id$ + +package ch.epfl.lamp.compiler.msil; + +/** + * Specifies flags that control binding and the way in which + * the search for members and types is conducted by reflection. + * + * Note: You must specify Instance or Static along with Public or NonPublic + * or no members will be returned. + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +public abstract class BindingFlags { + + //########################################################################## + + // disallows extending the class; + private BindingFlags() {} + + /** + * Specifies no binding flag. + */ + public static final int Default = 0x0000; + + /** + * Specifies that the case of the member name should not be considered + * when binding. + */ + public static final int IgnoreCase = 0x0001; + + /** + * Specifies that only members declared at the level of the supplied type's + * hierarchy should be considered. Inherited members are not considered. + */ + public static final int DeclaredOnly = 0x0002; + + /** + * Specifies that instance members are to be included in the search. + */ + public static final int Instance = 0x0004; + + /** + * Specifies that static members are to be included in the search. + */ + public static final int Static = 0x0008; + + /** + * Specifies that public members are to be included in the search. + */ + public static final int Public = 0x0010; + + /** + * Specifies that non-public members are to be included in the search. + */ + public static final int NonPublic = 0x0020; + + /** + * Specifies that static members up the hierarchy should be returned. + * Static members include fields, methods, events, and properties. + * Nested types are not returned. + */ + public static final int FlattenHierarchy = 0x0040; + + /** + * Specifies that a method is to be invoked. This may not be a constructor + * or a type initializer. + */ + public static final int InvokeMethod = 0x0100; + + /** + * Specifies that Reflection should create an instance of + * the specified type. Calls the constructor that matches + * the given arguments. The supplied member name is ignored. + * If the type of lookup is not specified, (Instance | Public) + * will apply. It is not possible to call a type initializer. + */ + public static final int CreateInstance = 0x0200; + + /** + * Specifies that the value of the specified field should be returned. + */ + public static final int GetField = 0x0400; + + /** + * Specifies that the value of the specified field should be set. + */ + public static final int SetField = 0x0800; + + /** + * Specifies that the value of the specified property should be returned. + */ + public static final int GetProperty = 0x1000; + + /** + * Specifies that the value of the specified property should be set. + * For COM properties, specifying this binding flag is equivalent to + * specifying PutDispProperty and PutRefDispProperty. + */ + public static final int SetProperty = 0x2000; + + /** + * Specifies that the PROPPUT member on a COM object should be invoked. + * PROPPUT specifies a property-setting function that uses a value. + * Use PutDispProperty if a property has both PROPPUT and PROPPUTREF + * and you need to distinguish which one is called. + */ + public static final int PutDispProperty = 0x4000; + + + /** + * Specifies that the PROPPUTREF member on a COM object should be invoked. + * PROPPUTREF specifies a property-setting function that uses a reference + * instead of a value. Use PutRefDispProperty if a property has both + * PROPPUT and PROPPUTREF and you need to distinguish which one is called. + */ + public static final int PutRefDispProperty = 0x8000; + + /** + * Specifies that types of the supplied arguments must exactly match + * the types of the corresponding formal parameters. Reflection + * throws an exception if the caller supplies a non-null Binder object, + * since that implies that the caller is supplying BindToXXX + * implementations that will pick the appropriate method. + * Reflection models the accessibility rules of the common type system. + * For example, if the caller is in the same assembly, the caller + * does not need special permissions for internal members. Otherwise, + * the caller needs ReflectionPermission. This is consistent with + * lookup of members that are protected, private, and so on. + * The general principle is that ChangeType should perform only + * widening coercions, which never lose data. An example of a + * widening coercion is coercing a value that is a 32-bit signed integer + * to a value that is a 64-bit signed integer. This is distinguished + * from a narrowing coercion, which may lose data. An example of + * a narrowing coercion is coercing a 64-bit signed integer to + * a 32-bit signed integer. + * The default binder ignores this flag, while custom binders can + * implement the semantics of this flag. + */ + public static final int ExactBinding = 0x10000; + + /** + * Used in COM interop to specify that the return value of the member + * can be ignored. + */ + public static final int IgnoreReturn = 0x100000 ; + + /** + * Returns the set of members whose parameter count matches the number + * of supplied arguments. This binding flag is used for methods with + * parameters that have default values and methods with variable arguments + * (varargs). This flag should only be used with Type.InvokeMember. + * Parameters with default values are used only in calls where trailing + * arguments are omitted. They must be the last arguments. + */ + public static final int OptionalParamBinding = 0x40000; + + /** + * Not implemented. + */ + public static final int SuppressChangeType = 0x20000; + + //########################################################################## + +} // class BindingFlags diff --git a/src/msil/ch/epfl/lamp/compiler/msil/CallingConventions.java b/src/msil/ch/epfl/lamp/compiler/msil/CallingConventions.java new file mode 100644 index 0000000000..925c5b8693 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/CallingConventions.java @@ -0,0 +1,76 @@ +/* + * System.Reflection-like API for access to .NET assemblies (DLL & EXE) + */ + +// $Id$ + +package ch.epfl.lamp.compiler.msil; + + +/** + * Calling conventions + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +public abstract class CallingConventions { + + //######################################################################## + + /** + * Specifies the default calling convention as determined by the + * common language runtime. + */ + public static final short Standard = (short) 0x0001; + + /** + * Specifies the calling convention for methods with variable arguments. + */ + public static final short VarArgs = (short) 0x0002; + + /** + * Specifies that either the Standard or the VarArgs calling + * convention may be used. + */ + public static final short Any = Standard | VarArgs; + + /** + * Specifies an instance or virtual method (not a static method). + * At run-time, the called method is passed a pointer to the target + * object as its first argument (the this pointer). The signature + * stored in metadata does not include the type of this first argument, + * because the method is known and its owner class can be discovered + * from metadata. + */ + public static final short HasThis = (short) 0x0020; + + /** + * Specifies that the signature is a function-pointer signature, + * representing a call to an instance or virtual method (not a static + * method). If ExplicitThis is set, HasThis must also be set. The first + * argument passed to the called method is still a this pointer, but the + * type of the first argument is now unknown. Therefore, a token that + * describes the type (or class) of the this pointer is explicitly stored + * into its metadata signature. + */ + public static final short ExplicitThis = (short) 0x0040; + + //######################################################################## + + private CallingConventions() {} + + public static String toString(int callConv) { + StringBuffer s = new StringBuffer(); + + if ((callConv & HasThis) != 0) { + s.append("instance"); + if ((callConv & ExplicitThis) != 0) + s.append(" explicit"); + } + + return s.toString(); + } + + //########################################################################## + +} // class CallingConventions diff --git a/src/msil/ch/epfl/lamp/compiler/msil/ConstructorInfo.java b/src/msil/ch/epfl/lamp/compiler/msil/ConstructorInfo.java new file mode 100644 index 0000000000..3dea39c2cf --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/ConstructorInfo.java @@ -0,0 +1,55 @@ +/* + * System.Reflection-like API for access to .NET assemblies (DLL & EXE) + */ + +// $Id$ + +package ch.epfl.lamp.compiler.msil; + +/** + * Discovers the attributes of a class constructor and provides + * access to constructor metadata. + * ConstructorInfo is used to discover the attributes of a constructor + * as well as to invoke a constructor. Objects are created by invoking + * either the GetConstructors or GetConstructor method of a Type object. + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +public class ConstructorInfo extends MethodBase { + //########################################################################## + + public final int MemberType() { return MemberTypes.Constructor; } + + public final boolean IsConstructor() { return true; } + + protected static final String CTOR = ".ctor"; + protected static final String CCTOR = ".cctor"; + protected static final ConstructorInfo[] EMPTY_ARRAY = + new ConstructorInfo[0]; + + protected static String getName(int attrs) { + return (attrs & MethodAttributes.Static) == 0 ? CTOR : CCTOR; + } + + /** Protected constructor */ + protected ConstructorInfo(Type declType, int attrs, Type[] paramTypes) { + super(getName(attrs), declType, attrs, paramTypes); + assert declType != null : "Owner can't be 'null' for a constructor!"; + } + + protected ConstructorInfo(Type declType, int attrs, ParameterInfo[] params) + { + super(getName(attrs), declType, attrs, params); + assert declType != null : "Owner can't be 'null' for a constructor!"; + } + + + public String toString() { + return MethodAttributes.toString(Attributes) + " " + Type.VOID() + + " " + DeclaringType.FullName + "::" + Name + params2String(); + } + + //########################################################################## + +} // class ConstructorInfo diff --git a/src/msil/ch/epfl/lamp/compiler/msil/CustomAttributeProvider.java b/src/msil/ch/epfl/lamp/compiler/msil/CustomAttributeProvider.java new file mode 100644 index 0000000000..32a50fdf9b --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/CustomAttributeProvider.java @@ -0,0 +1,83 @@ +/* + * System.Reflection-like API for access to .NET assemblies (DLL & EXE) + */ + +// $Id$ + +package ch.epfl.lamp.compiler.msil; + +import java.util.List; +import java.util.LinkedList; +import java.util.Iterator; + +/** + * @author Nikolay Mihaylov + * @version 1.0 + */ +public abstract class CustomAttributeProvider implements ICustomAttributeProvider { + + //########################################################################## + + protected List/**/ custAttrs; + private static final Object[] EMPTY = new Object[0]; + + //TODO: take inherit into account + public Object[] GetCustomAttributes(boolean inherit) { + initAttributes(null); + return custAttrs.size() == 0 ? EMPTY + : custAttrs.toArray(new Attribute[custAttrs.size()]); + } + + //TODO: take inherit into account + public Object[] GetCustomAttributes(Type attributeType, boolean inherit) { + initAttributes(attributeType); + List tAttrs = null; + if (constrType == attributeType) + tAttrs = custAttrs; + else { + tAttrs = new LinkedList(); + for (Iterator attrs = custAttrs.iterator(); attrs.hasNext(); ) { + Attribute a = (Attribute) attrs.next(); + if (a.GetType() == attributeType) tAttrs.add(a); + } + } + return tAttrs.size() == 0 ? EMPTY + : tAttrs.toArray(new Attribute[tAttrs.size()]); + } + + //TODO: take inherit into account + public boolean IsDefined(Type attributeType, boolean inherit) { + initAttributes(attributeType); + if (constrType == attributeType) + return custAttrs.size() > 0; + Iterator attrs = custAttrs.iterator(); + while (attrs.hasNext()) { + if (((Attribute)attrs.next()).GetType() == attributeType) + return true; + } + return false; +// return inherit && (DeclaringClass.BaseType != null) +// && DeclaringClass.BaseType.IsDefined(inherit); + } + + protected void addCustomAttribute(ConstructorInfo constr, byte[] value) { + Attribute attr = new Attribute(constr, value); + assert constrType == null || constrType == attr.GetType(); + if (custAttrs == null) + custAttrs = new LinkedList(); + custAttrs.add(attr); + } + + private void initAttributes(Type atype) { + if (custAttrs != null + && (constrType == null || constrType == atype)) + return; + custAttrs = new LinkedList(); + constrType = atype; + loadCustomAttributes(atype); + } + + protected void loadCustomAttributes(Type atype) {} + + private Type constrType; +} diff --git a/src/msil/ch/epfl/lamp/compiler/msil/EventAttributes.java b/src/msil/ch/epfl/lamp/compiler/msil/EventAttributes.java new file mode 100644 index 0000000000..f931f7bad6 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/EventAttributes.java @@ -0,0 +1,33 @@ +/* + * System.Reflection-like API for access to .NET assemblies (DLL & EXE) + */ + +// $Id$ + +package ch.epfl.lamp.compiler.msil; + +/** + * Specifies flags that describe the attributes of a an event. + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +public final class EventAttributes { + + //########################################################################## + + /** Specifies that the event has no attributes. */ + public static final short None = 0x000; + + /** Specifies a reserved flag for CLR use only. */ + public static final short ReservedMask = 0x0400; + + /** Specifies that the event is special in a way described by the name. */ + public static final short SpecialName = 0x0200; + + /** Specifies the the CLR should check name encoding. */ + public static final short RTSpecialName = 0x0400; + + //########################################################################## + +} // class EventAttributes diff --git a/src/msil/ch/epfl/lamp/compiler/msil/EventInfo.java b/src/msil/ch/epfl/lamp/compiler/msil/EventInfo.java new file mode 100644 index 0000000000..e2bea10f7f --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/EventInfo.java @@ -0,0 +1,59 @@ +/* + * System.Reflection-like API for access to .NET assemblies (DLL & EXE) + */ + +// $Id$ + +package ch.epfl.lamp.compiler.msil; + + +/** + * Discovers the attributes of an event + * and provides access to event metadata. + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +public class EventInfo extends MemberInfo { + + //########################################################################## + + public final int MemberType() { return MemberTypes.Event; } + + /** Attributes associated with the event. */ + public final short Attributes; + + /** The Type object for the underlying event-handler delegate + * associated with this event. + */ + public final Type EventHandlerType; + + public MethodInfo GetAddMethod() { return addMethod; } + + public MethodInfo GetRemoveMethod() { return removeMethod; } + + public String toString() { + return "" + EventHandlerType + " " + Name; + } + + //########################################################################## + + protected static final EventInfo[] EMPTY_ARRAY = new EventInfo[0]; + + protected MethodInfo addMethod; + + protected MethodInfo removeMethod; + + protected EventInfo(String name, Type declType, short attr, + Type handlerType, MethodInfo add, MethodInfo remove) + { + super(name, declType); + Attributes = attr; + EventHandlerType = handlerType; + this.addMethod = add; + this.removeMethod = remove; + } + + //########################################################################## + +} // class EventInfo diff --git a/src/msil/ch/epfl/lamp/compiler/msil/FieldAttributes.java b/src/msil/ch/epfl/lamp/compiler/msil/FieldAttributes.java new file mode 100644 index 0000000000..5e6cc84f1e --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/FieldAttributes.java @@ -0,0 +1,120 @@ +/* + * System.Reflection-like API for access to .NET assemblies (DLL & EXE) + */ + +// $Id$ + +package ch.epfl.lamp.compiler.msil; + +/** + * Specifies flags that describe the attributes of a field. + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +public final class FieldAttributes { + + //########################################################################## + + /** Specifies the access level of a given field. */ + public static final short FieldAccessMask = 0x0007; + + /** Member not refereneceable. */ + public static final short CompilerControlled = 0x0000; + + /** Field is accessible only by the parent type. */ + public static final short Private = 0x0001; + + /** Field is accessible only by subtypes in this assembly. */ + public static final short FamANDAssem = 0x0002; + + /** Field is accessible throughout the assembly. */ + public static final short Assembly = 0x0003; + + /** Field is accessible only by type and subtypes. */ + public static final short Family = 0x0004; + + /** Field is accessible by subtypes anywhere, + * as well as throughout this assembly. */ + public static final short FamORAssem = 0x0005; + + /** Specifies that the field is accessible by any member + * for whom this scope is visible. */ + public static final short Public = 0x0006; + + //########################################################################## + // + + /** Field represents the defined type, or else it is per-instance. */ + public static final short Static = 0x0010; + + /** Field is initialized only and cannot be written after initialization. */ + public static final short InitOnly = 0x0020; + + /** Value is compile-time constant. */ + public static final short Literal = 0x0040; + + /** Field does not have to be serialized when the type is remoted. */ + public static final short NotSerialized = 0x0080; + + /** Field is special. */ + public static final short SpecialName = 0x0200; + + //########################################################################## + // Interop attributes + + /** Implementation is forwarded through PInvoke */ + public static final short PinvokeImpl = 0x2000; + + + //########################################################################## + // Additional flags + + /** CLI provides 'special' behavior depending upon the name of the field */ + public static final short RTSpecialName = 0x0400; + + /** Field has marshalling information. */ + public static final short HasFieldMarshal = 0x1000; + + /** Field has a default value. */ + public static final short HasDefault = (short)0x8000; + + /** Field has a Relative Virtual Address (RVA). The RVA is the location + * of the method body in the current image, as an address relative + * to the start of the image file in which it is located. */ + public static final short HasFieldRVA = 0x0100; + + //########################################################################## + // + + public static String toString(short attrs) { + StringBuffer str = new StringBuffer(); + switch (attrs & FieldAccessMask) { + case CompilerControlled: str.append("compilercontrolled"); break; + case Private: str.append("private"); break; + case FamANDAssem: str.append("famandassem"); break; + case Assembly: str.append("assembly"); break; + case Family: str.append("family"); break; + case FamORAssem: str.append("famorassem"); break; + case Public: str.append("public"); break; + } + if ((attrs & Static) != 0) str.append(" static"); + if ((attrs & InitOnly) != 0) str.append(" initonly"); + if ((attrs & Literal) != 0) str.append(" literal"); + if ((attrs & NotSerialized) != 0) str.append(" notserialized"); + if ((attrs & SpecialName) != 0) str.append(" specialname"); + if ((attrs & PinvokeImpl) != 0) str.append(""); + if ((attrs & RTSpecialName) != 0) str.append(" rtspecialname"); + if ((attrs & HasFieldMarshal) != 0) str.append(" marshal()"); + //if ((attrs & HasDefault) != 0) str.append(" default(???)"); + return str.toString(); + } + + //########################################################################## + + // makes the class uninstantiable + private FieldAttributes() {} + + //########################################################################## + +} // class FieldAttributes diff --git a/src/msil/ch/epfl/lamp/compiler/msil/FieldInfo.java b/src/msil/ch/epfl/lamp/compiler/msil/FieldInfo.java new file mode 100644 index 0000000000..bd08e4a3e1 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/FieldInfo.java @@ -0,0 +1,113 @@ +/* + * System.Reflection-like API for access to .NET assemblies (DLL & EXE) + */ + +// $Id$ + +package ch.epfl.lamp.compiler.msil; + +/** + * Discovers the attributes of a field and provides access to field metadata. + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +public class FieldInfo extends MemberInfo { + + //########################################################################## + // public interface + + public final int MemberType() { return MemberTypes.Field; } + + /** Attributes associated with this field. */ + public final short Attributes; + + /** Type of the field represented by this FieldInfo object. */ + public final Type FieldType; + + protected final Object value; + + public final boolean IsStatic() { + return (Attributes & FieldAttributes.Static) != 0; + } + + public final boolean IsInitOnly() { + return (Attributes & FieldAttributes.InitOnly) != 0; + } + + public final boolean IsLiteral() { + return (Attributes & FieldAttributes.Literal) != 0; + + } + + public final boolean IsPublic() { + return (Attributes & FieldAttributes.FieldAccessMask) + == FieldAttributes.Public; + } + + public final boolean IsPrivate() { + return (Attributes & FieldAttributes.FieldAccessMask) + == FieldAttributes.Private; + } + + public final boolean IsFamily() { + return (Attributes & FieldAttributes.FieldAccessMask) + == FieldAttributes.Family; + } + + public final boolean IsAssembly() { + return (Attributes & FieldAttributes.FieldAccessMask) + == FieldAttributes.Assembly; + } + + public final boolean IsFamilyOrAssembly() { + return (Attributes & FieldAttributes.FieldAccessMask) + == FieldAttributes.FamORAssem; + } + + public final boolean IsFamilyAndAssembly() { + return (Attributes & FieldAttributes.FieldAccessMask) + == FieldAttributes.FamANDAssem; + } + public final boolean IsSpecialName() { + return (Attributes & FieldAttributes.SpecialName) != 0; + } + + public final boolean IsPinvokeImpl() { + return (Attributes & FieldAttributes.PinvokeImpl) != 0; + } + + public final boolean IsNotSerialized() { + return (Attributes & FieldAttributes.NotSerialized) != 0; + } + + public String toString() { + return FieldAttributes.toString(Attributes) + " " + + FieldType + " " + DeclaringType.FullName + "::" + Name; + } + + //########################################################################## + + protected static final FieldInfo[] EMPTY_ARRAY = new FieldInfo[0]; + + /** Initializes a new instance of the FieldInfo class. */ + protected FieldInfo(String name, Type declType, int attrs, Type fieldType) { + this(name, declType, attrs, fieldType, null); + } + + protected FieldInfo(String name, Type declType, + int attrs, Type fieldType, Object value) + { + super(name, declType); + FieldType = fieldType; + Attributes = (short) attrs; + this.value = value; + } + + /** + */ + public Object getValue() { return value; } + + //########################################################################## + +} // class FieldInfo diff --git a/src/msil/ch/epfl/lamp/compiler/msil/ICustomAttributeProvider.java b/src/msil/ch/epfl/lamp/compiler/msil/ICustomAttributeProvider.java new file mode 100644 index 0000000000..4eafc37ef3 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/ICustomAttributeProvider.java @@ -0,0 +1,58 @@ +/* + * System.Reflection-like API for access to .NET assemblies (DLL & EXE) + */ + +// $Id$ + +package ch.epfl.lamp.compiler.msil; + +/** + * Provides custom attributes for reflection objects that support them. + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +public interface ICustomAttributeProvider { + + //########################################################################## + // interface method definitions + + /** Returns an array of all of the custom attributes + * defined on this member, excluding named attributes, + * or an empty array if there are no custom attributes. + * + * @param inherit - When true, look up the hierarchy chain + * for the inherited custom attribute. + * @return - An array of Objects representing custom attributes, + * or an empty array. + */ + public Object[] GetCustomAttributes(boolean inherit); + + + /** Returns an array of custom attributes defined on this member, + * identified by type, or an empty array + * if there are no custom attributes of that type. + * + * @param attributeType - The type of the custom attributes. + * @param inherit - When true, look up the hierarchy chain + * for the inherited custom attribute. + * @return - An array of Objects representing custom attributes, + * or an empty array. + */ + public Object[] GetCustomAttributes(Type attributeType, boolean inherit); + + + /** Indicates whether one or more instance of attributeType + * is defined on this member + * + * @param attributeType - The type of the custom attributes + * @param inherit - When true, look up the hierarchy chain + * for the inherited custom attribute. + * @return - true if the attributeType is defined on this member; + * false otherwise. + */ + public boolean IsDefined(Type attributeType, boolean inherit); + + //########################################################################## + +} // interface ICustomAttributeProvider diff --git a/src/msil/ch/epfl/lamp/compiler/msil/MemberInfo.java b/src/msil/ch/epfl/lamp/compiler/msil/MemberInfo.java new file mode 100644 index 0000000000..14aac59e84 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/MemberInfo.java @@ -0,0 +1,48 @@ +/* + * System.Reflection-like API for access to .NET assemblies (DLL & EXE) + */ + +// $Id$ + +package ch.epfl.lamp.compiler.msil; + +/** + * The root class of the Reflection hierarchy. + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +public abstract class MemberInfo extends CustomAttributeProvider { + + //########################################################################## + + /** The name of this member. */ + public final String Name; + + /** + * The class that declares this member. + * Note: if the MemberInfo object is a global member, + * (that is, it was obtained from Module.GetMethods, + * which returns global methods on a module), then DeclaringType + * will be a null reference. + */ + public final Type DeclaringType; + + /** An enumerated value from the MemberTypes class, + * specifying a constructor, event, field, method, + * property, type information, all, or custom. */ + public abstract int MemberType(); + + //########################################################################## + // protected members + + protected static final MemberInfo[] EMPTY_ARRAY = new MemberInfo[0]; + + protected MemberInfo(String name, Type declType) { + Name = name; + DeclaringType = declType; + } + + //######################################################################## + +} // class MemberInfo diff --git a/src/msil/ch/epfl/lamp/compiler/msil/MemberTypes.java b/src/msil/ch/epfl/lamp/compiler/msil/MemberTypes.java new file mode 100644 index 0000000000..4536dc997f --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/MemberTypes.java @@ -0,0 +1,82 @@ +/* + * System.Reflection-like API for access to .NET assemblies (DLL & EXE) + */ + +// $Id$ + +package ch.epfl.lamp.compiler.msil; + +/** + * Marks each type of member that is defined as a derived class of MemberInfo. + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +public final class MemberTypes { + + //########################################################################## + + /** Specifies that the member is a constructor, + * representing a ConstructorInfo member. */ + public static final int Constructor = 0x01; + + + /** Specifies that the member is an event, + * representing an EventInfo member. */ + public static final int Event = 0x02; + + + /** Specifies that the member is a field, + * representing a FieldInfo member. */ + public static final int Field = 0x04; + + + /** Specifies that the member is a method, + * representing a MethodInfo member. */ + public static final int Method = 0x08; + + + /** Specifies that the member is a property, + * representing a PropertyInfo member. + */ + public static final int Property = 0x10; + + /** Specifies that the member is a type, + * representing a TypeInfo member. */ + public static final int TypeInfo = 0x20; + + + /** Specifies that the member is a custom member type. */ + public static final int Custom = 0x40; + + + /** Specifies that the member is a nested type, + * extending MemberInfo. */ + public static final int NestedType = 0x80; + + + /** Specifies all member types. */ + public static final int All = + Constructor | Event | Field | Method | Property | TypeInfo | NestedType; + + + public static String toString(int memberType) { + if ((memberType & Constructor) != 0) return "Constructor"; + if ((memberType & Event) != 0) return "Event"; + if ((memberType & Field) != 0) return "Field"; + if ((memberType & Method) != 0) return "Method"; + if ((memberType & Property) != 0) return "Property"; + if ((memberType & TypeInfo) != 0) return "TypeInfo"; + if ((memberType & Custom) != 0) return "Custom"; + if ((memberType & NestedType) != 0) return "NestedType"; + return "Unknown MemberType: " + memberType; + } + + //########################################################################## + + // makes the class uninstantiable + private MemberTypes() {} + + //########################################################################## + +} // class MemberTypes diff --git a/src/msil/ch/epfl/lamp/compiler/msil/MethodAttributes.java b/src/msil/ch/epfl/lamp/compiler/msil/MethodAttributes.java new file mode 100644 index 0000000000..3e8b658d49 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/MethodAttributes.java @@ -0,0 +1,159 @@ +/* + * System.Reflection-like API for access to .NET assemblies (DLL & EXE) + */ + +// $Id$ + +package ch.epfl.lamp.compiler.msil; + +/** Specifies flags for method attributes. + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +public final class MethodAttributes { + + //########################################################################## + // Method access attributes + + /** Bitmask used to retrieve accessibility information. */ + public static final short MemberAccessMask = 0x0007; + + ///** Member not referenceable*/ + //public static final short CompilerConstrolled = 0x0000; + + /** Indicates that the member cannot be referenced. */ + public static final short PrivateScope = 0x0000; + + /** Method is accessible only by the current class. */ + public static final short Private = 0x0001; + + /** Method is accessible to members of this type + * and its derived types that are in this assembly only. */ + public static final short FamANDAssem = 0x0002; + + /** Method is accessible to any class of this assembly. */ + public static final short Assembly = 0x0003; + + /** Method is accessible only to members of this class + * and its derived classes. */ + public static final short Family = 0x0004; + + /** Method is accessible to derived classes anywhere, + * as well as to any class in the assembly. */ + public static final short FamORAssem = 0x0005; + + /** Method is accessible to any object for which this object is in scope. */ + public static final short Public = 0x0006; + + + //########################################################################## + // Flags + + /** Method is defined on the type; otherwise, it is defined per instance. */ + public static final short Static = 0x0010; + + /** Method cannot be overridden. */ + public static final short Final = 0x0020; + + /** Method is virtual. */ + public static final short Virtual = 0x0040; + + /** Method hides by name and signature; otherwise, by name only. */ + public static final short HideBySig = 0x0080; + + + //########################################################################## + // vtable attributes + + /** Bitmask used to retrieve vtable attributes. */ + public static final short VtableLayoutMask = 0x0100; + + /** Method reuses existing slot in the vtable. */ + public static final short ReuseSlot = 0x0000; + + + /** Method always gets a new slot in the vtable. */ + public static final short NewSlot = 0x0100; + + + //########################################################################## + // Flags + + /** Method does not provide implementation. */ + public static final short Abstract = 0x0400; + + /** Method is special. */ + public static final short SpecialName = 0x0800; + + + //########################################################################## + // Interop attributes + + /** Method implementation is forwarded through PInvoke. */ + public static final short PInvokeImpl = 0x2000; + + /** Reserved: shall be zero for conforming implementations. + * Managed method is exported by thunk to unmanaged code. */ + public static final short UnmanagedExport = 0x0008; + + + //########################################################################## + // Additional flags + + /** CLI provides special behavior, depending on the name of the method. */ + public static final short RTSpecialName = 0x1000; + + /** Method has security associated with it. + * Reserved flag for runtime use only. + */ + public static final short HasSecurity = 0x00000040; + + /** + * Indicates that the method calls another method containing security code. + * Reserved flag for runtime use only. + */ + public static final short RequireSecObject = 0x00004000; + + /** Indicates a reserved flag for runtime use only. */ + public static final short ReservedMask = 0x0000; + + + //########################################################################## + + public static String toString(short attrs) { + StringBuffer str = new StringBuffer(accessFlagsToString(attrs)); + if ((attrs & Static) != 0) str.append(" static"); + if ((attrs & Final) != 0) str.append(" final"); + if ((attrs & Virtual) != 0) str.append(" virtual"); + if ((attrs & Abstract) != 0) str.append(" abstract"); + if ((attrs & HideBySig) != 0) str.append(" hidebysig"); + if ((attrs & NewSlot) != 0) str.append(" newslot"); + if ((attrs & SpecialName) != 0) str.append(" specialname"); + if ((attrs & PInvokeImpl) != 0) str.append(" pinvokeimpl(?!?)"); + if ((attrs & RTSpecialName) != 0) str.append(" rtspecialname"); + return str.toString(); + + } + + public static String accessFlagsToString(short attrs) { + switch (attrs & MemberAccessMask) { + case PrivateScope: return "compilercontrolled"; + case Private: return "private"; + case FamANDAssem: return "famandassem"; + case Assembly: return "assembly"; + case Family: return "family"; + case FamORAssem: return "famorassem"; + case Public: return "public"; + default: return "xxx"; + } + } + + //########################################################################## + + // makes the class uninstantiable + private MethodAttributes() {} + + //########################################################################## + +} // class Method Attributes diff --git a/src/msil/ch/epfl/lamp/compiler/msil/MethodBase.java b/src/msil/ch/epfl/lamp/compiler/msil/MethodBase.java new file mode 100644 index 0000000000..699edab6e3 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/MethodBase.java @@ -0,0 +1,145 @@ +/* + * System.Reflection-like API for access to .NET assemblies (DLL & EXE) + */ + +// $Id$ + +package ch.epfl.lamp.compiler.msil; + +/** + * The common superclass of MemberInfo and ConstructorInfo + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +public abstract class MethodBase extends MemberInfo { + + //########################################################################## + // public interface + + /** The attributes associated with this method/constructor. */ + public final short Attributes; + + /***/ + public final short CallingConvention; + + public abstract boolean IsConstructor(); + + public final boolean IsAbstract() { + return (Attributes & MethodAttributes.Abstract) != 0; + } + + public final boolean IsFinal() { + return (Attributes& MethodAttributes.Final) != 0; + } + + public final boolean IsVirtual() { + return (Attributes& MethodAttributes.Virtual) != 0; + } + + public final boolean IsStatic() { + return (Attributes & MethodAttributes.Static) != 0; + } + + public final boolean IsHideBySig() { + return (Attributes & MethodAttributes.HideBySig) != 0; + } + + public final boolean IsSpecialName() { + return (Attributes & MethodAttributes.SpecialName) != 0; + } + + + public final boolean IsPublic() { + return (Attributes & MethodAttributes.MemberAccessMask) + == MethodAttributes.Public; + } + + public final boolean IsPrivate() { + return (Attributes & MethodAttributes.MemberAccessMask) + == MethodAttributes.Private; + } + + public final boolean IsFamily() { + return (Attributes & MethodAttributes.MemberAccessMask) + == MethodAttributes.Family; + } + + public final boolean IsAssembly() { + return (Attributes & MethodAttributes.MemberAccessMask) + == MethodAttributes.Assembly; + } + + public final boolean IsFamilyOrAssembly() { + return (Attributes & MethodAttributes.MemberAccessMask) + == MethodAttributes.FamORAssem; + } + + public final boolean IsFamilyAndAssembly() { + return (Attributes & MethodAttributes.MemberAccessMask) + == MethodAttributes.FamANDAssem; + } + + + /** Returns the parameters of the method/constructor. */ + public ParameterInfo[] GetParameters() { + return (ParameterInfo[]) params.clone(); + } + + public int GetMethodImplementationFlags() { return implAttributes; } + + //########################################################################## + + /** Method parameters. */ + protected ParameterInfo[] params; + + protected short implAttributes; + + protected MethodBase(String name, Type declType, int attrs, Type[] paramTypes) + { + this(name, declType, attrs); + assert paramTypes != null; + params = new ParameterInfo[paramTypes.length]; + for (int i = 0; i < params.length; i++) + params[i] = new ParameterInfo(null, paramTypes[i], 0, i); + } + + protected MethodBase(String name, Type declType, int attrs, + ParameterInfo[] params) + { + this(name, declType, attrs); + this.params = params; + } + + /** + */ + private MethodBase(String name, Type declType, int attrs) { + super(name, declType); + + Attributes = (short) attrs; + + if (IsConstructor()) { + attrs |= MethodAttributes.SpecialName; + attrs |= MethodAttributes.RTSpecialName; + } + + CallingConvention = (short) (CallingConventions.Standard + | (IsStatic() ? (short)0 : CallingConventions.HasThis)); + } + + //########################################################################## + // internal methods + + protected String params2String() { + StringBuffer s = new StringBuffer("("); + for (int i = 0; i < params.length; i++) { + if (i > 0) s.append(", "); + s.append(params[i].ParameterType); + } + s.append(")"); + return s.toString(); + } + + //########################################################################## + +} // class MethodBase diff --git a/src/msil/ch/epfl/lamp/compiler/msil/MethodImplAttributes.java b/src/msil/ch/epfl/lamp/compiler/msil/MethodImplAttributes.java new file mode 100644 index 0000000000..1ad3f2a133 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/MethodImplAttributes.java @@ -0,0 +1,117 @@ +/* + * System.Reflection-like API for access to .NET assemblies (DLL & EXE) + */ + +// $Id$ + +package ch.epfl.lamp.compiler.msil; + +/** + * Method implementation attributes + * @author Nikolay Mihaylov + * @version 1.0 + */ +public abstract class MethodImplAttributes { + + //########################################################################## + + /** + * Specifies flags about code type. 3 + */ + public static final short CodeTypeMask = (short) 0x0003; + + /** + * Specifies that the method implementation is in MSIL. 0 + */ + public static final short IL = (short) 0x0000; + + /** + * Specifies that the method implementation is native. 1 + */ + public static final short Native = (short) 0x0001; + + /** + * This member supports the .NET Framework infrastructure and + * is not intended to be used directly from your code. 2 + */ + public static final short OPTIL = (short) 0x0002; + + /** + * Specifies that the method implementation is provided by the runtime. 3 + */ + public static final short Runtime = (short) 0x0003; + + + + /** + * Specifies whether the code is managed or unmanaged. 4 + */ + public static final short ManagedMask = (short) 0x0004; + + /** + * Specifies that the method implementation is managed, otherwise unmanaged. + */ + public static final short Managed = (short) 0x0000; + + /** + * Specifies that the method implementation is unmanaged, otherwise managed. + */ + public static final short Unmanaged = (short) 0x0004; + + + + /** + * Specifies that the method cannot be inlined. 8 + */ + public static final short NoInlining = (short) 0x0008; + + /** + * Specifies that the method is not defined. 16 + */ + public static final short ForwardRef = (short) 0x0010; + + /** + * Specifies that the method is single-threaded through the body. + * You can also use the C# lock statement or the Visual Basic + * Lock function for this purpose. 32 + */ + public static final short Synchronized = (short) 0x0020; + + /** + * Specifies that the method signature is exported exactly as declared. 128 + */ + public static final short PreserveSig = (short) 0x0080; + + /** + * Specifies an internal call. 4096 + */ + public static final short InternalCall = (short) 0x1000; + + /** + * Specifies a range check value. 65535 + */ + public static final short MaxMethodImplVal = (short) 0xffff; + + //########################################################################## + + public static String toString(int implAttr) { + StringBuffer s = new StringBuffer(); + switch (implAttr & CodeTypeMask) { + case IL: s.append("cil"); break; + case Native: s.append("native"); break; + case Runtime: s.append("runtime"); break; + } + switch (implAttr & ManagedMask) { + case Managed: s.append(" managed"); break; + case Unmanaged: s.append(" unmanaged"); break; + } + if ((implAttr & NoInlining) != 0) s.append(" noinlining"); + if ((implAttr & ForwardRef) != 0) s.append(" forwardref"); + if ((implAttr & Synchronized) != 0) s.append(" synchronized"); + if ((implAttr & InternalCall) != 0) s.append(" internalcall"); + return s.toString(); + } + + //########################################################################## + +} // class MethodImplAttributes diff --git a/src/msil/ch/epfl/lamp/compiler/msil/MethodInfo.java b/src/msil/ch/epfl/lamp/compiler/msil/MethodInfo.java new file mode 100644 index 0000000000..22b174d77b --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/MethodInfo.java @@ -0,0 +1,57 @@ +/* + * System.Reflection-like API for access to .NET assemblies (DLL & EXE) + */ + +// $Id$ + +package ch.epfl.lamp.compiler.msil; + +/** + * Discovers the attributes of a method and provides access to method metadata. + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +public class MethodInfo extends MethodBase { + + //########################################################################## + // public members + + public final int MemberType() { return MemberTypes.Method; } + + public final boolean IsConstructor() { return false; } + + /** The return type of this method. + */ + public final Type ReturnType; + + //########################################################################## + // protected members + + protected static final MethodInfo[] EMPTY_ARRAY = new MethodInfo[0]; + + /** + * Constructor Initializes a new instance of the MethodInfo class. + */ + protected MethodInfo(String name, Type declType, + int attrs, Type returnType, Type[] paramTypes ) + { + super(name, declType, attrs, paramTypes); + ReturnType = returnType; + } + + protected MethodInfo(String name, Type declType, + int attrs, Type returnType, ParameterInfo[] params ) + { + super(name, declType, attrs, params); + ReturnType = returnType; + } + + public String toString() { + return MethodAttributes.toString(Attributes) + " " + ReturnType + + " " + DeclaringType + "::" + Name + params2String(); + } + + //########################################################################## + +} // class MethodInfo diff --git a/src/msil/ch/epfl/lamp/compiler/msil/Module.java b/src/msil/ch/epfl/lamp/compiler/msil/Module.java new file mode 100644 index 0000000000..bd06c32223 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/Module.java @@ -0,0 +1,156 @@ +/* + * System.Reflection-like API for access to .NET assemblies (DLL & EXE) + */ + +// $Id$ + +package ch.epfl.lamp.compiler.msil; + +import java.util.Map; +import java.util.HashMap; + +/** + * Defines and represents a module. Get an instance of ModuleBuilder + * by calling DefineDynamicModule + * A module is a portable executable file of type .dll or .exe consisting + * of one or more classes and interfaces. There may be multiple namespaces + * contained in a single module, and a namespace may span multiple modules. + * One or more modules deployed as a unit compose an assembly. + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +public abstract class Module extends CustomAttributeProvider { + + //########################################################################## + // public fields + + /** String representing the name of the module with the path removed. */ + public final String Name; + + /** String representing the fully qualified name and path to this module. */ + public final String FullyQualifiedName; + + /** String representing the name of the module. */ + public String ScopeName; + + /** The Assembly the Module belongs to. */ + public final Assembly Assembly; + + //########################################################################## + // constructor + + protected Module(String name, String filename, + String scopeName, Assembly assembly) + { + this.Name = name; + this.FullyQualifiedName = filename; + this.ScopeName = scopeName; + this.Assembly = assembly; + } + + //########################################################################## + // public methods + + /** Returns the specified class, performing a case-sensitive search. */ + public Type GetType(String name) { + initTypes(); + return (Type) typesMap.get(name); + } + + /** + * @return all the classes defined within this module. + */ + public Type[] GetTypes() { + initTypes(); + return (Type[]) types.clone(); + } + + /** + * @return the global field with the specified name. + */ + public FieldInfo GetField(String name) { + for (int i = 0; i < fields.length; i++) + if (fields[i].Name.equals(name)) + return fields[i]; + return null; + } + + /** + * @return an array of the global fields of the module + */ + public FieldInfo[] GetFields() { + return (FieldInfo[]) fields.clone(); + } + + /** + * @return - the global method with the specified name + */ + public MethodInfo GetMethod(String name) { + for (int i = 0; i < methods.length; i++) + if (methods[i].Name.equals(name)) + return methods[i]; + return null; + } + + /** + * @return - an array of all the global methods defined in this modules. + */ + public MethodInfo[] GetMethods() { + return (MethodInfo[]) methods.clone(); + } + + /** + */ + public String toString() { return Name; } + + //######################################################################## + // protected members + + // all the types defined in this module + protected final Map typesMap = new HashMap(); + + // all the types defined in this module + protected Type[] types; + + // the global fields of the module + protected FieldInfo[] fields = FieldInfo.EMPTY_ARRAY; + + // the global methods of the module + protected MethodInfo[] methods = MethodInfo.EMPTY_ARRAY; + + protected Type addType(Type type) { + addType(type.FullName, type); + Assembly.addType(type); + return type; + } + + protected Type addType(String name, Type type) { + assert type!= null; + typesMap.put(name, type); + return type; + } + + private boolean initTypes = true; + protected final void initTypes() { + if (initTypes) { + loadTypes(); + initTypes = false; + } + } + + protected void loadTypes() {} + + private boolean initGlobals = true; + protected final void initGlobals() { + if (initGlobals) { + loadGlobals(); + initGlobals = false; + } + } + + protected void loadGlobals() {} + + //########################################################################## + +} // class Module diff --git a/src/msil/ch/epfl/lamp/compiler/msil/PEAssembly.java b/src/msil/ch/epfl/lamp/compiler/msil/PEAssembly.java new file mode 100644 index 0000000000..2d6d498bb0 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/PEAssembly.java @@ -0,0 +1,70 @@ +/* + * System.Reflection-like API for access to .NET assemblies (DLL & EXE) + */ + +// $Id$ + +package ch.epfl.lamp.compiler.msil; + +import ch.epfl.lamp.compiler.msil.util.Table; +import ch.epfl.lamp.compiler.msil.util.Table.*; + +import java.io.File; + +import java.util.Map; +import java.util.HashMap; + +/** Represents an assembly that resides in a real .NET assembly + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +final class PEAssembly extends Assembly { + + private final PEFile pefile; + + private PEModule mainModule; + + public PEAssembly(PEFile pefile, AssemblyName an) { + super(an, true); + this.pefile = pefile; + String name = pefile.ModuleDef(1).getName(); + mainModule = new PEModule(pefile, 1, name, this); + addModule(name, mainModule); + //initModules(); + } + + protected void loadModules() { + File parentDir = pefile.getParentFile(); + FileDef fd = pefile.FileDef; + for (int row = 1; row <= fd.rows; row++) { + fd.readRow(row); + String filename = fd.getName(); + File f = new File(parentDir, filename); + PEFile pe = Assembly.getPEFile(f); + if (pe == null) { + f = new File(filename); + pe = Assembly.getPEFile(f); + if (pe == null) + continue; +// throw new RuntimeException("Cannot find file " + filename + +// " referenced by assembly " + this); + } + String name = pe.ModuleDef(1).getName(); + PEModule module = new PEModule(pe, 1, name, this); + addModule(name, module); + } + } + + public File getFile() { + return pefile.getUnderlyingFile(); + } + + protected void loadCustomAttributes(Type attributeType) { + initModules(); + mainModule.initAttributes(this, 1, Table.AssemblyDef.ID, attributeType); + } + + //########################################################################## + +} // class PEAssembly diff --git a/src/msil/ch/epfl/lamp/compiler/msil/PEFile.java b/src/msil/ch/epfl/lamp/compiler/msil/PEFile.java new file mode 100644 index 0000000000..459bb39a20 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/PEFile.java @@ -0,0 +1,870 @@ +/* + * System.Reflection-like API for access to .NET assemblies (DLL & EXE) + */ + +// $Id$ + +package ch.epfl.lamp.compiler.msil; + +import ch.epfl.lamp.compiler.msil.util.*; +import ch.epfl.lamp.compiler.msil.util.Table.*; + +import ch.epfl.lamp.compiler.msil.Type; +import ch.epfl.lamp.compiler.msil.Module; + +import java.io.File; +import java.io.RandomAccessFile; +import java.io.PrintStream; +import java.io.IOException; +import java.io.FileNotFoundException; + +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.MappedByteBuffer; + +import java.util.Date; + +/** + * A class that represents a .NET PE/COFF image. + * + * @author Nikolay Mihaylov + * @version 1.0 + * @see Standard ECMA-335: Common Language Infrastructure (CLI), 4th edition (June 2006) + */ +public class PEFile { + + //########################################################################## + + public static final int INT_SIZE = 4; + + protected final int PE_SIGNATURE_OFFSET; + protected final int COFF_HEADER_OFFSET; + protected final int PE_HEADER_OFFSET; + + protected final int numOfSections; + protected final int CLI_RVA; + protected final int CLI_Length; + public final int rvaMetadata; + public final int posMetadata; + protected final int numOfStreams; + protected final int optHeaderSize; + + protected final File underlyingFile; + protected final RandomAccessFile file; + protected final MappedByteBuffer buf; + + protected final PESection [] sections; + + public PEStream Meta, Strings, US, Blob, GUID; + + private final Table [] tables = new Table[Table.MAX_NUMBER]; + + public final boolean isDLL; + + protected final int heapSizes; + public final boolean StringIsShort, BlobIsShort, GUIDIsShort; + + protected PEModule pemodule = null; + + //########################################################################## + // PEFile constructor + + private static void fileFormatCheck(boolean cond, String s) { + if (cond) + throw new RuntimeException(s); + } + + /** + */ + public PEFile(String filename) throws FileNotFoundException { + this.underlyingFile = new File(filename); + this.file = new RandomAccessFile(underlyingFile, "r"); + FileChannel fc = file.getChannel(); + MappedByteBuffer bb = null; + try { + bb = fc.map(FileChannel.MapMode.READ_ONLY, 0L, fc.size()); + } catch (IOException e) { throw new RuntimeException(e); } + + /** Ecma 335, 25 File format extensions to PE: + * + * "Unless stated otherwise, all binary values are stored in little-endian format." + */ + + bb.order(java.nio.ByteOrder.LITTLE_ENDIAN); + this.buf = bb; + + /** Ecma 335, 25.2.1 MS-DOS header: + * + * "The PE format starts with an MS-DOS stub of exactly the following 128 bytes to + * be placed at the front of the module." + * + * We are only checking for MZ (Mark Zbikowski) + */ + + seek(0); + fileFormatCheck(readByte() != 0x4d, "Invalid PE file format: " + filename); // 'M' + fileFormatCheck(readByte() != 0x5a, "Invalid PE file format: " + filename); // 'Z' + + /** Ecma 335, 25.2.1 MS-DOS header: + * + * "At offset 0x3c in the DOS header is a 4-byte unsigned integer offset, lfanew, + * to the PE signature (shall be “PE\0\0”), immediately followed by the PE file header. + */ + + seek(0x3c); + PE_SIGNATURE_OFFSET = readInt(); + seek(PE_SIGNATURE_OFFSET); + + fileFormatCheck(readByte() != 0x50, "Invalid PE file format: " + filename); // 'P' + fileFormatCheck(readByte() != 0x45, "Invalid PE file format: " + filename); // 'E' + fileFormatCheck(readByte() != 0x00, "Invalid PE file format: " + filename); // 0 + fileFormatCheck(readByte() != 0x00, "Invalid PE file format: " + filename); // 0 + + //trace("PE signature offset = 0x" + Table.int2hex(PE_SIGNATURE_OFFSET)); + + COFF_HEADER_OFFSET = PE_SIGNATURE_OFFSET + 4; + PE_HEADER_OFFSET = COFF_HEADER_OFFSET + 20; + + seek(COFF_HEADER_OFFSET); + skip(2); + /** Ecma 335, 25.2.2: "Number of sections; indicates size of the Section Table" */ + numOfSections = readShort(); + //trace("Number of sections = " + numOfSections); + + /** Ecma 335, 25.2.2: "Time and date the file was created in seconds since + * January 1st 1970 00:00:00 or 0." + */ + Date timeStamp = new Date(readInt() * 1000L); + //trace("Time stamp = " + timeStamp); + + skip(2 * INT_SIZE); + optHeaderSize = readShort(); + int characteristics = readShort(); + isDLL = (characteristics & 0x2000) != 0; + //trace("Characteristics = " + Integer.toHexString(characteristics)); + + seek(PE_HEADER_OFFSET + 208); // p.157, Partition II + + CLI_RVA = readInt(); + CLI_Length = readInt(); + //trace("CLI_RVA = 0x" + Table.int2hex(CLI_RVA)); + //trace("CLI_Length = 0x" + Table.int2hex(CLI_Length)); + + sections = new PESection[numOfSections]; + + seek(PE_HEADER_OFFSET + optHeaderSize); // go to the sections descriptors + + for (int i = 0; i < numOfSections; i++) { + seek(PE_HEADER_OFFSET + optHeaderSize + i * 40); + sections[i] = new PESection(this); + //sections[i].dump(System.out); + } + + seek(fromRVA(CLI_RVA)); + skip(8); + rvaMetadata = readInt(); + posMetadata = fromRVA(rvaMetadata); + //trace("rvaMetadata = 0x" + Table.int2hex(rvaMetadata)); + //trace("posMetadata = 0x" + Table.int2hex(posMetadata)); + + seek(posMetadata); + int magic = readInt(); + //trace("Magic metadata signature = 0x" + Table.int2hex(magic)); + fileFormatCheck(magic != 0x424a5342, "Invalid metadata signature!"); + skip(8); + + int strlength = readInt(); + //trace("version name string length = " + strlength); + skip(strlength); + align(INT_SIZE, posMetadata); + //trace("position of flags = 0x" + Table.int2hex((int)pos())); + skip(2); // ignore the flags + numOfStreams = readShort(); + //trace("Number of metadata streams = " + numOfStreams); + + for (int i = 0; i < numOfStreams; i++) { + PEStream strm = new PEStream(this); + //strm.dump(System.out); + if (strm.name.equals("#~") + || strm.name.equals("#-")) Meta = strm; + if (strm.name.equals("#Strings")) Strings = strm; + if (strm.name.equals("#US")) US = strm; + if (strm.name.equals("#Blob")) Blob = strm; + if (strm.name.equals("#GUID")) GUID = strm; + } + + seek(Meta.offset); + skip(6); + heapSizes = readByte(); + StringIsShort = (heapSizes & 0x01) == 0; + GUIDIsShort = (heapSizes & 0x02) == 0; + BlobIsShort = (heapSizes & 0x04) == 0; + + skip(1); + long tablesMask = readLong(); + long nonStandardTables = tablesMask & ~Table.VALID_TABLES_MASK; + skip(8); //go to the list of number of rows + for (int i = 0; i < tables.length; i++) { + tables[i] = Table.newTable + (this, i, ((tablesMask >> i) & 0x01) != 0 ? readInt() : 0); + } + + initIndexSize(); + initTableRefs(); + // populate the tables from the CLI image file + long start = pos(); + for (int i = 0; i < tables.length; i++) + start = tables[i].init(start); + + } // PEFile() + + + public final int[] indexSize = new int[Table.TABLE_SET_LENGTH]; + + private void initIndexSize() { + for (int i = 0; i < Table.TABLE_SET_LENGTH; i++) { + indexSize[i] = 2; + int[] tableSet = Table.TableSet[i]; + int treshold = (65536 >> Table.NoBits[i]); + for (int j = 0; j < tableSet.length; j++) { + if (tableSet[j] >= 0) { + Table t = tables[tableSet[j]]; + if (t.rows >= treshold) { + indexSize[i] = 4; + break; + } + } + } + } + } + + protected void initModule(PEModule module) { + if (pemodule != null) + throw new RuntimeException("File " + this + + " has already been assigned module " + + pemodule + "; new module is " + module); + this.pemodule = module; + } + + //########################################################################## + + public ModuleDef ModuleDef; + public ModuleDef ModuleDef(int i) { + ModuleDef.readRow(i); + return ModuleDef; + } + + public TypeRef TypeRef; + + public TypeDef TypeDef; + public TypeDef TypeDef(int i) { + TypeDef.readRow(i); + return TypeDef; + } + + public FieldTrans FieldTrans; + public FieldTrans FieldTrans(int i) { + FieldTrans.readRow(i); + return FieldTrans; + } + + public FieldDef FieldDef; + public FieldDef FieldDef(int i) { + FieldDef.readRow(i); + return FieldDef; + } + + public MethodTrans MethodTrans; + public MethodTrans MethodTrans(int i) { + MethodTrans.readRow(i); + return MethodTrans; + } + + public MethodDef MethodDef; + public MethodDef MethodDef(int i) { MethodDef.readRow(i); return MethodDef; } + + + public ParamDef ParamDef; + public ParamDef ParamDef(int i) { ParamDef.readRow(i); return ParamDef; } + + public InterfaceImpl InterfaceImpl; + public MemberRef MemberRef; + public Constant Constant; + public CustomAttribute CustomAttribute; + public FieldMarshal FieldMarshal; + public DeclSecurity DeclSecurity; + public ClassLayout ClassLayout; + public FieldLayout FieldLayout; + public StandAloneSig StandAloneSig; + public EventMap EventMap; + public EventDef EventDef; + public PropertyMap PropertyMap; + public PropertyDef PropertyDef; + public MethodSemantics MethodSemantics; + public MethodImpl MethodImpl; + public ModuleRef ModuleRef; + public TypeSpec TypeSpec; + public ImplMap ImplMap; + public FieldRVA FieldRVA; + public AssemblyDef AssemblyDef; + public AssemblyRef AssemblyRef; + public FileDef FileDef; + public ExportedType ExportedType; + public ManifestResource ManifestResource; + public NestedClass NestedClass; + + + private void initTableRefs() { + ModuleDef = (ModuleDef) getTable(Table.ModuleDef.ID); + TypeRef = (TypeRef) getTable(Table.TypeRef.ID); + TypeDef = (TypeDef) getTable(Table.TypeDef.ID); + FieldTrans = (FieldTrans) getTable(Table.FieldTrans.ID); + FieldDef = (FieldDef) getTable(Table.FieldDef.ID); + MethodTrans = (MethodTrans) getTable(Table.MethodTrans.ID); + MethodDef = (MethodDef) getTable(Table.MethodDef.ID); + ParamDef = (ParamDef) getTable(Table.ParamDef.ID); + InterfaceImpl = (InterfaceImpl) getTable(Table.InterfaceImpl.ID); + MemberRef = (MemberRef) getTable(Table.MemberRef.ID); + Constant = (Constant) getTable(Table.Constant.ID); + CustomAttribute = (CustomAttribute) getTable(Table.CustomAttribute.ID); + FieldMarshal = (FieldMarshal) getTable(Table.FieldMarshal.ID); + DeclSecurity = (DeclSecurity) getTable(Table.DeclSecurity.ID); + ClassLayout = (ClassLayout) getTable(Table.ClassLayout.ID); + FieldLayout = (FieldLayout) getTable(Table.FieldLayout.ID); + StandAloneSig = (StandAloneSig) getTable(Table.StandAloneSig.ID); + EventMap = (EventMap) getTable(Table.EventMap.ID); + EventDef = (EventDef) getTable(Table.EventDef.ID); + PropertyMap = (PropertyMap) getTable(Table.PropertyMap.ID); + PropertyDef = (PropertyDef) getTable(Table.PropertyDef.ID); + MethodSemantics = (MethodSemantics) getTable(Table.MethodSemantics.ID); + MethodImpl = (MethodImpl) getTable(Table.MethodImpl.ID); + ModuleRef = (ModuleRef) getTable(Table.ModuleRef.ID); + TypeSpec = (TypeSpec) getTable(Table.TypeSpec.ID); + ImplMap = (ImplMap) getTable(Table.ImplMap.ID); + FieldRVA = (FieldRVA) getTable(Table.FieldRVA.ID); + AssemblyDef = (AssemblyDef) getTable(Table.AssemblyDef.ID); + AssemblyRef = (AssemblyRef) getTable(Table.AssemblyRef.ID); + FileDef = (FileDef) getTable(Table.FileDef.ID); + ExportedType = (ExportedType) getTable(Table.ExportedType.ID); + NestedClass = (NestedClass) getTable(Table.NestedClass.ID); + ManifestResource = + (ManifestResource) getTable(Table.ManifestResource.ID); + } + + public static String long2hex(long a) { + StringBuffer str = new StringBuffer("0000000000000000"); + str.append(Long.toHexString(a)); + int l = str.length(); + return str.substring(l - 16, l); + } + + public static String int2hex(int a) { + StringBuffer str = new StringBuffer("00000000"); + str.append(Integer.toHexString(a)); + int l = str.length(); + return str.substring(l - 8, l); + } + + public static String short2hex(int a) { + StringBuffer str = new StringBuffer("0000"); + str.append(Integer.toHexString(a)); + int l = str.length(); + return str.substring(l - 4, l); + } + + public static String byte2hex(int a) { + StringBuffer str = new StringBuffer("00"); + str.append(Integer.toHexString(a)); + int l = str.length(); + return str.substring(l - 2, l); + } + + public static String bytes2hex(byte[] buf) { + StringBuffer str = new StringBuffer(); + for (int i = 0; i < buf.length; i++) { + str.append(byte2hex(buf[i])); + if (i < buf.length - 1) + str.append(" "); + } + return str.toString(); + } + + //########################################################################## + // filename + + public File getUnderlyingFile() { + return underlyingFile; + } + + /** + * @return the absolute path of the file + */ + public String getAbsolutePath() { + return underlyingFile.getAbsolutePath(); + } + + /** + * @return the name of this file + */ + public String getName() { + return underlyingFile.getName(); + } + + /** + * @return + */ + public String getParent() { + return underlyingFile.getParent(); + } + + /** + * @return the file representing the directory the file belongs to + */ + public File getParentFile() { + return underlyingFile.getParentFile(); + } + + public String toString() { + return getAbsolutePath(); + } + + //########################################################################## + // file pointer manipulation methods + + /** Returns the current position in the file. */ + public int pos() { + return buf.position(); + } + + /** Go to the specified position in the file. */ + public void seek(int pos) { + buf.position(pos); + } + + + /** Align the current position in the file. */ + public void align(int base) { align(base, 0); } + + /** Align the current position in a section starting at offset. */ + public void align(int base, int offset) { + int p = pos() - offset; + seek( offset + ((p % base) == 0 ? p : (p/base + 1) * base)); + } + + /** Computes the position in the file that corresponds to the given RVA. */ + public int fromRVA(int rva) { + int i; + for(i = 0; i < numOfSections; i++) + if(sections[i].virtAddr <= rva && + rva <= (sections[i].virtAddr + sections[i].virtSize)) + return rva - sections[i].virtAddr + sections[i].realAddr; + throw new RuntimeException("RVA 0x" + Integer.toHexString(rva) + + " is not within this file's sections!"); + } + + /** Go to the specified RVA (Relative Virtual Address). */ + public void gotoRVA(int rva) { + seek(fromRVA(rva)); + } + + /** Move the forward in the file by the specified number of bytes. */ + public void skip(int n) { + buf.position(buf.position() + n); + } + + /** + * Returns a memory mapped little-endian buffer + * for the specified region of the file. + */ + public MappedByteBuffer mapBuffer(long offset, int size) { + try { + MappedByteBuffer b = file.getChannel() + .map(FileChannel.MapMode.READ_ONLY, offset, size); + b.order(java.nio.ByteOrder.LITTLE_ENDIAN); + return b; + } catch (IOException e) { throw new RuntimeException(e); } + } + + /** Returns a buffer from the given offset to the end of the file. */ + public ByteBuffer getBuffer(long offset, int size) { + buf.mark(); + buf.position((int)offset); + ByteBuffer bb = buf.slice(); + buf.reset(); + bb.limit(size); + bb.order(java.nio.ByteOrder.LITTLE_ENDIAN); + return bb; + } + + //########################################################################## + // file read methods + + /** + * Read bs.length number of bytes + */ + public void read(byte[] bs) { + buf.get(bs); + } + + /** + * Read 1-byte integer from the current position in the file. + */ + public int readByte() { + return buf.get(); + } + + /** + * Read 2-byte integer from the current position in the file. + */ + public int readShort() { + return buf.getShort(); + } + + /** + * Read 4-byte integer from the current position in the file. + */ + public int readInt() { + return buf.getInt(); + } + + /** + * Read 8-byte integer from the current position in the file. + */ + public long readLong() { + return buf.getLong(); + } + + /** + * @return the size of string indeces for this file. + */ + public int getStringIndexSize() { + return StringIsShort ? 2 : 4; + } + + /** + * @return the size of GUID indeces for this file. + */ + public int getGUIDIndexSize() { + return GUIDIsShort ? 2 : 4; + } + + /** + * @return the size of Blob indeces for this file. + */ + public int getBlobIndexSize() { + return BlobIsShort ? 2 : 4; + } + + /** + * @return the size of the index to tableID for this file; + * @param tableID the ID of the table + */ + public int getTableIndexSize(int tableID) { + return tables[tableID].isShort ? 2 : 4; + } + + /** + * @return the size of the index to a set of tables with the given @param TableSetID + * @param tableSetID the ID of the table set + */ + public int getTableSetIndexSize(int tableSetID) { + return indexSize[tableSetID]; + } + + /** + * Read a String index from the current position in the file. + * @return an index into the String stream + */ + public int readStringIndex() { + return StringIsShort ? readShort() : readInt(); + } + + /** + * Read a GUID index from the current position in the file. + * @return an index in to the GUID stream + */ + public int readGUIDIndex() { + return GUIDIsShort ? readShort() : readInt(); + } + + /** + * Read a Blob index from the current position in the file. + * @return an index into the Blob stream + */ + public int readBlobIndex() { + return BlobIsShort ? readShort() : readInt(); + } + + /** Read an entry interpreted as index into table @param tableID. */ + public int readTableIndex(int tableId) { + return tables[tableId].isShort ? readShort() : readInt(); + } + + /***/ + public int readTableSetIndex(int tableSetId) { + return indexSize[tableSetId] == 2 ? readShort() : readInt(); + } + + /** + * Read a string from the String stream + * @return the string at the given position + * @param pos the position of the string in the String stream + */ + public String getString(int pos) { + String s = Strings.getString(pos); + return s;//.length() == 0 ? null : s; + } + + /** + * Read a string from the US (User Strings) stream + * @return the string at the given position + * @param pos the position of the string in the US stream + */ + public String getUString(int pos) { + return US.getString(pos); + } + + /** + * Read a blob from the Blob Stream + * @return the blob at the given position + * @param pos the position of the blob in the Blob stream + */ + public byte[] getBlob(int pos) { + return Blob.getBlob(pos); + } + + /***/ + public Sig getSignature(int pos) { + //return new Sig(getBlob(pos)); + return Blob.getSignature(pos); + } + + /***/ + public byte[] getGUID(int pos) { + return GUID.getGUID(pos); + } + + /** + * @return the table with the corresponding ID. + */ + public final Table getTable(int tableID) { + return tables[tableID]; + } + + //########################################################################## + + /***/ + void trace(String msg) { + System.out.println("[trace] " + msg); + } + + //########################################################################## + + public Sig newSignature(ByteBuffer buf) { + return new Sig(buf); + } + + /** + */ + public class Sig implements Signature { + + //###################################################################### + // instance members + + protected final ByteBuffer buf; + protected final int pos; + protected final int length; + + public Sig(ByteBuffer buf) { + this.buf = buf; + //int tmpPos = buf.position(); + length = decodeInt(); + this.pos = buf.position(); + } + + public String toString() { + StringBuffer b = new StringBuffer("("); + reset(); + for (int i = 0; i < length; i++) { + b.append(byte2hex(readByte())); + if (i < length - 1) + b.append(" "); + } + return b.append(")").toString(); + } + + public Sig reset() { buf.position(pos); return this; } + + public int pos() { return buf.position() - pos; } + + /** @return the byte at the current position in the signature Blob. + * Stay at the same position + */ + public int getByte() { + return (buf.get(buf.position()) + 0x100) & 0xff; + } + + /** @return the byte at the current position in the signature Blob. + * Move to the next byte. + */ + public int readByte() { return (buf.get() + 0x100) & 0xff; } + + /** Skip the current byte if equal to the given value. */ + public void skipByte(int b) { if (b == getByte()) buf.get(); } + + /** Decodes an integer from the signature Blob. + * @return the decoded integer + */ + public int decodeInt() { + int res = readByte(); + if ((res & 0x80) != 0) { + res = ((res & 0x7f) << 8) | readByte(); + if ((res & 0x4000) != 0) + res = ((res & 0x3fff)<<16) | (readByte()<<8) | readByte(); + } + return res; + } + + /** @return - the type encoded at the current position in the signature + * according to 22.2.12 + */ + public Type decodeType() { + try { return decodeType0(); } + catch (RuntimeException e) { + System.out.println("" + pos() + "@" + this); + throw e; + } + } + + public Type decodeType0() { + Type type = null; + int desc = readByte(); + switch (desc) { + case ELEMENT_TYPE_BOOLEAN:type = Type.GetType("System.Boolean"); break; + case ELEMENT_TYPE_CHAR: type = Type.GetType("System.Char"); break; + case ELEMENT_TYPE_I1: type = Type.GetType("System.SByte"); break; + case ELEMENT_TYPE_U1: type = Type.GetType("System.Byte"); break; + case ELEMENT_TYPE_I2: type = Type.GetType("System.Int16"); break; + case ELEMENT_TYPE_U2: type = Type.GetType("System.UInt16"); break; + case ELEMENT_TYPE_I4: type = Type.GetType("System.Int32"); break; + case ELEMENT_TYPE_U4: type = Type.GetType("System.UInt32"); break; + case ELEMENT_TYPE_I8: type = Type.GetType("System.Int64"); break; + case ELEMENT_TYPE_U8: type = Type.GetType("System.UInt64"); break; + case ELEMENT_TYPE_R4: type = Type.GetType("System.Single"); break; + case ELEMENT_TYPE_R8: type = Type.GetType("System.Double"); break; + case ELEMENT_TYPE_OBJECT: type = Type.GetType("System.Object"); break; + case ELEMENT_TYPE_STRING: type = Type.GetType("System.String"); break; + case ELEMENT_TYPE_I: type = Type.GetType("System.IntPtr"); break; + case ELEMENT_TYPE_U: type = Type.GetType("System.UIntPtr"); break; + case ELEMENT_TYPE_PTR: // Followed by token. + if (getByte() == ELEMENT_TYPE_VOID) { + readByte(); + type = Type.mkPtr(Type.GetType("System.Void")); + } else type = Type.mkPtr(decodeType()); + break; + case ELEMENT_TYPE_BYREF: // Followed by token. + case ELEMENT_TYPE_VALUETYPE: // Followed by token + //System.out.println("Signature.getType(): valuetype"); + //type = pemodule.getTypeDefOrRef(decodeInt()); + case ELEMENT_TYPE_CLASS: + // Followed by token + type = pemodule.getTypeDefOrRef(decodeInt()); + if (type == null) throw new RuntimeException(); + break; + + case ELEMENT_TYPE_SZARRAY: // Single-dim array with 0 lower bound. + skipCustomMods(); + type = Type.mkArray(decodeType(), 1); + break; + case ELEMENT_TYPE_ARRAY: + // ... ... + Type elem = decodeType(); + int rank = decodeInt(); + int numSizes = decodeInt(); + for (int i = 0; i < numSizes; i++) + decodeInt(); + int numLoBounds = decodeInt(); + for (int i = 0; i < numLoBounds; i++) + decodeInt(); + type = Type.mkArray(elem, rank); + break; + + case ELEMENT_TYPE_FNPTR: + // Followed by full method signature. + case ELEMENT_TYPE_END: + // Marks end of a list + case ELEMENT_TYPE_CMOD_REQD: + // Required modifier : followed by a TypeDef or TypeRef token. + case ELEMENT_TYPE_CMOD_OPT: + // Optional modifier : followed by a TypeDef or TypeRef token. + case ELEMENT_TYPE_INTERNAL: + // Implemented within the CLI. + case ELEMENT_TYPE_MODIFIER: + // Or'd with following element types. + case ELEMENT_TYPE_SENTINEL: + // Sentinel for varargs method signature. + case ELEMENT_TYPE_PINNED: + // Denotes a local variable that points at a pinned object. + default: + throw new RuntimeException(byte2hex(desc) + + "@" + pos() + " in " + this); + + } + if (type == null) throw new RuntimeException(); + return type; + } // getType() + + public Type decodeFieldType() { + skipByte(FIELD); + skipCustomMods(); + return decodeType(); + } + + /** decodes the return type of a method signature (22.2.11). */ + public Type decodeRetType() { + skipCustomMods(); + switch (getByte()) { + case ELEMENT_TYPE_VOID: + readByte(); + return Type.GetType("System.Void"); + case ELEMENT_TYPE_TYPEDBYREF: + return Type.GetType("System.TypedReference"); + case ELEMENT_TYPE_BYREF: + skipByte(ELEMENT_TYPE_BYREF); + return decodeType(); + default: + return decodeType(); + } + } + + public Type decodeParamType() { + skipCustomMods(); + switch (getByte()) { + case ELEMENT_TYPE_BYREF: + skipByte(ELEMENT_TYPE_BYREF); + return decodeType(); + case ELEMENT_TYPE_TYPEDBYREF: + return Type.GetType("System.TypedReference"); + default: + return decodeType(); + } + } + + public void skipCustomMods() { + while (getByte() == ELEMENT_TYPE_CMOD_OPT + || getByte() == ELEMENT_TYPE_CMOD_REQD) + { + Type t = decodeType(); + System.err.println("CMOD: " + t); + if (getByte() == ELEMENT_TYPE_CMOD_REQD) + throw new RuntimeException("Reqired CMOD: " + t); + } + } + + //###################################################################### + + } // class Sig + + //########################################################################## + +} // class PEFile diff --git a/src/msil/ch/epfl/lamp/compiler/msil/PEModule.java b/src/msil/ch/epfl/lamp/compiler/msil/PEModule.java new file mode 100644 index 0000000000..a6e7bb31b2 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/PEModule.java @@ -0,0 +1,327 @@ +/* + * System.Reflection-like API for access to .NET assemblies (DLL & EXE) + */ + +// $Id$ + +package ch.epfl.lamp.compiler.msil; + +import ch.epfl.lamp.compiler.msil.PEFile; +import ch.epfl.lamp.compiler.msil.PEFile.Sig; +import ch.epfl.lamp.compiler.msil.util.Table; +import ch.epfl.lamp.compiler.msil.util.Table.*; + +import java.util.Map; +import java.util.HashMap; +import java.util.ArrayList; +import java.util.Iterator; + +/** Represents a module corresponding to a PE/COFF file + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +final class PEModule extends Module { + + //########################################################################## + + protected final PEFile pefile; + + private final int definingRow; + + private Type[] typeRefs = null; + + protected PEModule(PEFile pefile, int definingRow, String scopeName, + Assembly assem) + { + super(pefile.getName(), pefile.getAbsolutePath(), scopeName, assem); + this.pefile = pefile; + this.definingRow = definingRow; + pefile.initModule(this); + pefile.TypeDef.load(); // load into memory + //loadTypes(); + //pefile.FieldDef.load(); + //pefile.MethodDef.load(); + loadGlobals(); + } + + //########################################################################## + + public Type GetType(String typeName) { + initTypes(); + Object o = typesMap.get(typeName); + if (o == null) { + //System.out.println("PEModule.GetType(): Unable to find type " + // + typeName + " int module " + this); + return null; + } + return o instanceof Type ? (Type)o + : getTypeDef(((Integer)o).intValue()); + } + + + /** Load information about the types defined in this module. + */ + protected void loadTypes() { + typeRefs = new Type[pefile.TypeRef.rows]; + final int nbTypes = pefile.TypeDef.rows; + for (int row = 2; row <= nbTypes; row++) { + String name = pefile.TypeDef(row).getFullName(); + typesMap.put(name, new Integer(row)); + } + this.types = new Type[nbTypes - 1]; + for (int row = 2; row <= nbTypes; row++) { + getTypeDef(row); + } + } + + /** Return the type defined at the given row in the TypeDef table. + */ + Type getTypeDef(int row) { + if (this.types[row - 2] != null) + return this.types[row - 2]; + + TypeDef type = pefile.TypeDef(row); + int attrs = type.Flags; + String name = type.getFullName(); + + Type declType = null; + if (TypeAttributes.isNested(attrs)) { + for (int i = 1; i <= pefile.NestedClass.rows; i++) { + pefile.NestedClass.readRow(i); + if (pefile.NestedClass.NestedClass == row) + declType = getTypeDef + (pefile.NestedClass.EnclosingClass); + } + } + Type t = new PEType + (this, attrs, name, declType, Type.AuxAttr.None, pefile, row); + types[row - 2] = t; + addType(t); + return t; + } + + /** + * Load the desription of the module-global fields and methods + */ + protected void loadGlobals() { + //TODO: + } + + protected void loadCustomAttributes(Type attributeType) { + initAttributes(this, 1, Table.ModuleDef.ID, attributeType); + } + + /** Return the type referenced by the given row in the TypeRef table. + */ + Type getTypeRef(int row) { + return getTypeRef(row, null); + } + + /** Return the type referenced by the given row in the TypeRef table + * only if it resides in the given assembly. + * Used by initCustomAttributes to avoid unnecessary loading + * of referenced assemblies. + */ + Type getTypeRef(int row, Assembly inAssembly) { + Type type = typeRefs[row - 1]; + if (type != null) + return type; + + Table.TypeRef tr = pefile.TypeRef; + tr.readRow(row); + int tableId = Table.getTableId(Table._ResolutionScope, + tr.ResolutionScope); + int refRow = tr.ResolutionScope >> Table.NoBits[Table._ResolutionScope]; + String typeName = tr.getFullName(); + pefile.getTable(tableId).readRow(refRow); + switch (tableId) { + case AssemblyRef.ID: + String name = pefile.AssemblyRef.getName(); + if (inAssembly != null && !inAssembly.GetName().Name.equals(name)) + return null; + Assembly assem = getAssembly(name); + type = assem.GetType(typeName); + if (type == null) { + throw new RuntimeException("Failed to locate type " + + typeName + " in assembly " + assem); + } + break; + case ModuleDef.ID: + assert refRow == 1; + type = this.GetType(typeName); + //assert type != null; + break; + case TypeRef.ID: + type = getTypeRef(refRow); + break; + case ModuleRef.ID: + type = getAssembly(pefile.ModuleRef.getName()).GetType(typeName); + default: + throw new RuntimeException(refRow + "@" + pefile.getTable(tableId).getTableName()/* PEFile.byte2hex(tableId)*/); + } + if (typeRefs[row - 1] != null) + System.out.println("TypeRef[" + PEFile.short2hex(row) + "] " + + "changing type " + typeRefs[row - 1] + + " for type " + type); + typeRefs[row - 1] = type; + assert type != null : "Couldn't find type " + typeName; + return type; + } + + private Assembly getAssembly(String name) { + Assembly assem = Assembly.getAssembly(name); + if (assem != null) + return assem; + java.io.File dir = pefile.getParentFile(); + assem = Assembly.LoadFrom(dir, name); + if (assem != null) + return assem; + try { + dir = pefile.getUnderlyingFile().getCanonicalFile().getParentFile(); + } catch (java.io.IOException e) { + throw new RuntimeException(e); + } + assem = Assembly.LoadFrom(dir, name); + if (assem != null) + return assem; + throw new RuntimeException("Cannot find assembly: " + name); + + } + + /** Return the type corresponding to TypeDefOrRef coded index. + * @param index - TypeDefOrRef coded index according to 23.2.6. + */ + public Type getTypeDefOrRef(int index) { + int tableId = Table.getTableId(Table._TypeDefOrRef, index); + int row = index >> Table.NoBits[Table._TypeDefOrRef]; + Type type = null; + switch (tableId) { + case Table.TypeDef.ID: + type = getTypeDef(row); + break; + case Table.TypeRef.ID: + return getTypeRef(row); + case Table.TypeSpec.ID: + throw new RuntimeException("PEModule.getTypeDefOrRef(): TypeSpec"); + default: + throw new RuntimeException("PEModule.getTypeDefOrRef(): oops!"); + } + return type; + } + + /** Returns the method defined at the given row of the MethodDef table + * by looking up the type that defines the method. + */ + MethodBase getMethod(int row) { + for (int i = 0; i < types.length; i++) { + PEType type = (PEType)types[i]; + if ((type.methodListBeg <= row) && (row < type.methodListEnd)) { + type.initMethods(); + return type.methoddefs[row - type.methodListBeg]; + } + } + throw new RuntimeException("In module " + this + + ": cannot find type defining method 0x" + + PEFile.int2hex(row)); + } + + /** Returns the member referenced by the given row of the MemberRef table. + */ + protected MemberInfo getMemberRef(int row) { + return getMemberRef(row, null); + } + + /** Returns the member referenced by the given row of the MemberRef table + * if defined in the given assembly. + * Used by initCustomAttributes to avoid unnecessary loading of + * referenced assemblies + */ + protected MemberInfo getMemberRef(int row, Assembly inAssembly) { + MemberInfo member = null; + MemberRef mref = pefile.MemberRef; + mref.readRow(row); + int mtbl = Table.getTableId(Table._MemberRefParent, mref.Class); + int mind = Table.getTableIndex(Table._MemberRefParent, mref.Class); + switch (mtbl) { + case TypeRef.ID: + Type type = getTypeRef(mind, inAssembly); + if (type == null) + return null; + Sig sig = mref.getSignature(); + int callconv = sig.readByte(); // should be 0x20 + int paramCount = sig.decodeInt(); + //sig.skipByte(Signature.ELEMENT_TYPE_BYREF); //from MethodDef + Type retType = sig.decodeRetType(); + Type[] paramType = new Type[paramCount]; + for (int i = 0; i < paramCount; i++) + paramType[i] = sig.decodeParamType(); + + String memberName = mref.getName(); + if (memberName.equals(ConstructorInfo.CTOR) || + memberName.equals(ConstructorInfo.CCTOR)) + { + member = type.GetConstructor(paramType); + } else { + member = type.GetMethod(memberName, paramType); + } + assert member != null : type + "::" + memberName; + break; + case ModuleRef.ID: + case MethodDef.ID: + case TypeSpec.ID: + throw new RuntimeException("initCustomAttributes: " + + pefile.getTable(mtbl).getTableName()); + } + return member; + } + + protected void initCustomAttributes(Type attributeType) { + initAttributes(this, definingRow, Table.ModuleDef.ID, attributeType); + } + + // explicitly only package-visible + void initAttributes(CustomAttributeProvider cap, int definingRow, + int sourceTableId, Type attributeType) + { + int parentIndex = Table.encodeIndex(definingRow, + Table._HasCustomAttribute, + sourceTableId); + Table.CustomAttribute attrs = pefile.CustomAttribute; + for (int row = 1; row <= attrs.rows; row++) { + ConstructorInfo attrConstr = null; + attrs.readRow(row); + if (attrs.Parent == parentIndex) { + int tableId = Table.getTableId(Table._CustomAttributeType, + attrs.Type); + int ind = Table.getTableIndex(Table._CustomAttributeType, + attrs.Type); + switch (tableId) { + case MethodDef.ID: + attrConstr = (ConstructorInfo)this.getMethod(ind); + break; + case MemberRef.ID: + //System.out.println(PEFile.short2hex(ind) + "@MemberRef"); + Assembly attrAssem = + attributeType == null ? null : attributeType.Assembly(); + MemberInfo mi = this.getMemberRef(ind, attrAssem); + if (mi != null) { + assert mi instanceof ConstructorInfo + : "Expected ConstructorInfo; found " + mi; + attrConstr = (ConstructorInfo)mi; + } + break; + default: + throw new RuntimeException(); + } + if (attrConstr != null + && (attrConstr.DeclaringType == attributeType + || attributeType == null)) + cap.addCustomAttribute(attrConstr, attrs.getValue()); + } + } + } + + //########################################################################## + +} // class PEModule diff --git a/src/msil/ch/epfl/lamp/compiler/msil/PEType.java b/src/msil/ch/epfl/lamp/compiler/msil/PEType.java new file mode 100644 index 0000000000..67686baad2 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/PEType.java @@ -0,0 +1,399 @@ +/* + * System.Reflection-like API for access to .NET assemblies (DLL & EXE) + */ + +// $Id$ + +package ch.epfl.lamp.compiler.msil; + +import ch.epfl.lamp.compiler.msil.PEFile.Sig; + +import ch.epfl.lamp.compiler.msil.util.Table; +import ch.epfl.lamp.compiler.msil.util.Table.*; +import ch.epfl.lamp.compiler.msil.util.Signature; + +import java.util.ArrayList; + +/** + * Represents a type from a .NET assembly + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +final class PEType extends Type implements Signature { + + //########################################################################## + + /** The PEFile that holds the description of the type. */ + final PEFile file; + + /** The number of the row in the TypeDef table defining the type. */ + final int definingRow; + + /** The row of the first method in the MethodDef table. */ + final int methodListBeg; + + /** The row of the last method in the MethodDef table + 1. */ + final int methodListEnd; + + /** @param definingRow - the index in the TypeDef table where + * the type description is. + */ + PEType(PEModule module, + int attributes, + String fullName, + Type declType, + int auxAttr, + PEFile file, + int definingRow) + { + super(module, attributes, fullName, null, null, declType, auxAttr); + this.file = file; + this.definingRow = definingRow; + methodListBeg = file.TypeDef(definingRow).MethodList; + methodListEnd = definingRow < file.TypeDef.rows + ? file.TypeDef(definingRow + 1).MethodList + : file.MethodDef.rows + 1; + } + + //########################################################################## + // lazy type construction methods + + protected void loadBaseType() { + TypeDef type = file.TypeDef(definingRow); + baseType = type.Extends == 0 ? null + : ((PEModule)Module).getTypeDefOrRef(type.Extends); + } + + protected void loadFields() { + // the list of the declared fields starts from the + // FieldList index in the TypeDef table up to the smaller of the: + // - the last row of the FieldDef table + // - the start of the next list of fields determined by the + // FieldList index of the next row in the TypeDef table + final ArrayList fields = new ArrayList(); + int fieldListBeg = file.TypeDef(definingRow).FieldList; + int fieldListEnd = file.FieldDef.rows + 1; + if (definingRow < file.TypeDef.rows) + fieldListEnd = file.TypeDef(definingRow + 1).FieldList; + + for (int row = fieldListBeg; row < fieldListEnd; row++) { + int frow = file.FieldTrans.rows == 0 + ? row : file.FieldTrans(row).Field; + int attrs = file.FieldDef(frow).Flags; + String name = file.FieldDef.getName(); + //System.out.println("\t-->Loading field: " + name); + Sig sig = file.FieldDef.getSignature(); + Type fieldType = sig.decodeFieldType(); + Object val = null; + Table.Constant consts = file.Constant; + for (int i = 1; i <= consts.rows; i++) { + consts.readRow(i); + int tableId = Table.getTableId(Table._HasConstant,consts.Parent); + int refRow = consts.Parent >> Table.NoBits[Table._HasConstant]; + if (tableId == Table.FieldDef.ID && refRow == frow) + val = consts.getValue(); + } + FieldInfo field = + new PEFieldInfo(row, name, attrs, fieldType, val); + if (field.Name.equals("value__") && field.IsSpecialName()) + { + assert underlyingType == null : underlyingType.toString(); + underlyingType = field.FieldType; + } + fields.add(field); + } + this.fields = (FieldInfo[]) + fields.toArray(FieldInfo.EMPTY_ARRAY); + fields.clear(); + } + + protected MethodBase[] methoddefs; + protected MethodInfo getMethod(int n) { + return (MethodInfo)methoddefs[n - methodListBeg]; + } + protected void loadMethods() { + methoddefs = new MethodBase[methodListEnd - methodListBeg]; + + final ArrayList methods = new ArrayList(); + final ArrayList constrs = new ArrayList(); + PEModule pemodule = (PEModule) Module; + for (int row = methodListBeg; row < methodListEnd; row++) { + int mrow = file.MethodTrans.rows == 0 + ? row : file.MethodTrans(row).Method; + int attrs = file.MethodDef(mrow).Flags; + String name = file.MethodDef.getName(); + Sig sig = file.MethodDef.getSignature(); + int callConv = sig.readByte(); + int paramCount = sig.decodeInt(); + sig.skipByte(Signature.ELEMENT_TYPE_BYREF); + Type retType = sig.decodeRetType(); + Type[] paramType = new Type[paramCount]; + for (int i = 0; i < paramCount; i++) + paramType[i] = sig.decodeParamType(); + + ParameterInfo[] params = new ParameterInfo[paramCount]; + int paramListBeg = file.MethodDef.ParamList; + int paramListEnd = file.ParamDef.rows + 1; + // if not the last method + if (file.MethodDef.currentRow() < file.MethodDef.rows) { + paramListEnd = file.MethodDef(mrow + 1).ParamList; + } + for (int i = paramListBeg; i < paramListEnd; i++) { + int pattr = file.ParamDef(i).Flags; + String paramName = file.ParamDef.getName(); + int seq = file.ParamDef.Sequence; + if (seq == 0) { + //System.out.println("Retval attributes 0x" + + // PEFile.short2hex(pattr)); + } else { + params[seq - 1] = new ParameterInfo + (paramName, paramType[seq - 1], pattr, seq - 1); + } + } + for (int i = 0; i < params.length; i++) { + if (params[i] == null) + params[i] = new ParameterInfo(null, paramType[i], 0, 0); + } + MethodBase method = null; + if ((attrs & MethodAttributes.SpecialName) != 0 + && (attrs & MethodAttributes.RTSpecialName) != 0 + && (name.equals(ConstructorInfo.CTOR) + || name.equals(ConstructorInfo.CCTOR))) + method = new PEConstructorInfo(row, attrs, params); + else + method = new PEMethodInfo(row, name, attrs, retType, params); + (method.IsConstructor() ? constrs : methods).add(method); + methoddefs[row - methodListBeg] = method; + } + + this.constructors = (ConstructorInfo[]) + constrs.toArray(ConstructorInfo.EMPTY_ARRAY); + this.methods = (MethodInfo[]) + methods.toArray(MethodInfo.EMPTY_ARRAY); + constrs.clear(); methods.clear(); + } + + protected void loadProperties() { + final PropertyMap pmap = file.PropertyMap; + if (pmap == null) { + properties = PropertyInfo.EMPTY_ARRAY; + return; + } + + final PropertyDef pdef = file.PropertyDef; + int propListBeg = -1; + int propListEnd = pdef.rows + 1; + for (int i = 1; i <= pmap.rows; i++) { + pmap.readRow(i); + if (pmap.Parent == this.definingRow) { + propListBeg = pmap.PropertyList; + if (i < pmap.rows) { + pmap.readRow(i + 1); + propListEnd = pmap.PropertyList; + } + break; + } + } + if (propListBeg < 0) { + properties = PropertyInfo.EMPTY_ARRAY; + return; + } + + final ArrayList properties = new ArrayList(); + for (int i = propListBeg; i < propListEnd; i++) { + pdef.readRow(i); + Sig sig = pdef.getSignature(); + int b = sig.readByte(); + b &= ~HASTHIS; + int paramCount = sig.readByte(); + assert b == PROPERTY; + Type propType = sig.decodeType(); + int index = Table.encodeIndex(i, Table._HasSemantics, + Table.PropertyDef.ID); + MethodSemantics msem = file.MethodSemantics; + MethodInfo getter = null, setter = null; + for (int j = 1; j <= msem.rows; j++) { + msem.readRow(j); + if (msem.Association != index) + continue; + if (msem.isGetter()) + getter = getMethod(msem.Method); + else if (msem.isSetter()) + setter = getMethod(msem.Method); + else + System.err.println("PEType.loadProperties(): !?!"); + } + properties.add + (new PEPropertyInfo(i, pdef.getName(), (short)pdef.Flags, + propType, getter, setter)); + } + this.properties = (PropertyInfo[]) properties + .toArray(PropertyInfo.EMPTY_ARRAY); + } + + protected void loadEvents() { + EventMap emap = file.EventMap; + if (emap == null) { + this.events = EventInfo.EMPTY_ARRAY; + return; + } + + final EventDef edef = file.EventDef; + int eventListBeg = -1; + int eventListEnd = edef.rows + 1; + for (int i = 1; i <= emap.rows; i++) { + emap.readRow(i); + if (emap.Parent == this.definingRow) { + eventListBeg = emap.EventList; + if (i < emap.rows) { + emap.readRow(i + 1); + eventListEnd = emap.EventList; + } + break; + } + } + if (eventListBeg < 0) { + this.events = EventInfo.EMPTY_ARRAY; + return; + } + + final ArrayList events = new ArrayList(); + final MethodSemantics msem = file.MethodSemantics; + for (int i = eventListBeg; i < eventListEnd; i++) { + edef.readRow(i); + final Type handler = + ((PEModule)Module).getTypeDefOrRef(edef.EventType); + int index = + Table.encodeIndex(i, Table._HasSemantics, Table.EventDef.ID); + MethodInfo add = null, remove = null; + for (int j = 1; j <= msem.rows; j++) { + msem.readRow(j); + if (msem.Association != index) + continue; + if (msem.isAddOn()) + add = getMethod(msem.Method); + else if (msem.isRemoveOn()) + remove = getMethod(msem.Method); + else {} + } + events.add(new PEEventInfo(i, edef.getName(), + (short)edef.EventFlags, + handler, add, remove)); + } + this.events = (EventInfo[]) events + .toArray(EventInfo.EMPTY_ARRAY); + } + + protected void loadNestedTypes() { + final ArrayList nested = new ArrayList(); + for (int i = 1; i <= file.NestedClass.rows; i++) { + file.NestedClass.readRow(i); + if (file.NestedClass.EnclosingClass == this.definingRow) + nested.add(((PEModule)Module) + .getTypeDef(file.NestedClass.NestedClass)); + } + this.nestedTypes = (Type[]) nested.toArray(Type.EmptyTypes); + } + + protected void loadInterfaces() { + // get the interfaces implemented by this class + interfaces = Type.EmptyTypes; + int index = file.InterfaceImpl.findType(definingRow); + if (index > 0) { + ArrayList ifaces = new ArrayList(); + for (int i = index; i <= file.InterfaceImpl.rows; i++) { + file.InterfaceImpl.readRow(i); + if (file.InterfaceImpl.Class != definingRow) + break; + ifaces.add(((PEModule)Module) + .getTypeDefOrRef(file.InterfaceImpl.Interface)); + } + interfaces = (Type[]) ifaces.toArray(new Type[ifaces.size()]); + } + } + + protected void loadCustomAttributes(Type attributeType) { + initAttributes(this, definingRow, Table.TypeDef.ID, attributeType); + } + + private void initAttributes(CustomAttributeProvider cap, int definingRow, + int sourceTableId, Type attributeType) + { + ((PEModule)this.Module).initAttributes + (cap, definingRow, sourceTableId, attributeType); + } + + //########################################################################## + + private class PEFieldInfo extends FieldInfo { + private final int definingRow; + public PEFieldInfo(int definingRow, String name, + int attrs, Type fieldType, Object value) + { + super(name, PEType.this, attrs, fieldType, value); + this.definingRow = definingRow; + } + protected void loadCustomAttributes(Type attributeType) { + PEType.this.initAttributes + (this, definingRow, Table.FieldDef.ID, attributeType); + } + } + + private class PEMethodInfo extends MethodInfo { + private final int definingRow; + public PEMethodInfo(int row, String name, + int attrs, Type retType, ParameterInfo[] params) + { + super(name, PEType.this, attrs, retType, params); + this.definingRow = row; + } + protected void loadCustomAttributes(Type attributeType) { + PEType.this.initAttributes + (this, definingRow, Table.MethodDef.ID, attributeType); + } + } + + private class PEConstructorInfo extends ConstructorInfo { + private final int definingRow; + public PEConstructorInfo(int row, int attrs, ParameterInfo[] params) { + super(PEType.this, attrs, params); + this.definingRow = row; + } + protected void loadCustomAttributes(Type attributeType) { + PEType.this.initAttributes + (this, definingRow, Table.MethodDef.ID, attributeType); + } + } + + private class PEPropertyInfo extends PropertyInfo { + private final int definingRow; + public PEPropertyInfo(int row, String name, short attrs, Type propType, + MethodInfo getter, MethodInfo setter) + { + super(name, PEType.this, attrs, propType, getter, setter); + this.definingRow = row; + } + protected void loadCustomAttributes(Type attributeType) { + PEType.this.initAttributes + (this, definingRow, Table.PropertyDef.ID, attributeType); + } + } + + private class PEEventInfo extends EventInfo { + private final int definingRow; + public PEEventInfo(int row, String name, short attrs, Type handler, + MethodInfo add, MethodInfo remove) + { + super(name, PEType.this, attrs, handler, add, remove); + this.definingRow = row; + } + protected void loadCustomAttributes(Type attributeType) { + PEType.this.initAttributes + (this, definingRow, Table.EventDef.ID, attributeType); + } + } + + //########################################################################## + +} // class PEType diff --git a/src/msil/ch/epfl/lamp/compiler/msil/ParameterAttributes.java b/src/msil/ch/epfl/lamp/compiler/msil/ParameterAttributes.java new file mode 100644 index 0000000000..7c48637d9f --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/ParameterAttributes.java @@ -0,0 +1,73 @@ +/* + * System.Reflection-like API for access to .NET assemblies (DLL & EXE) + */ + +// $Id$ + +package ch.epfl.lamp.compiler.msil; + +/** + * Defines the attributes that may be associated with a parameter. + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +public final class ParameterAttributes { + + // just to make the class uninstantiable + private ParameterAttributes() {} + + //########################################################################## + + /** Specifies that there is no parameter attribute. */ + public static final short None = 0x0000; + + /** Specifies that the parameter is an input parameter. */ + public static final short In = 0x0001; + + /** Specifies that the parameter is an output parameter. */ + public static final short Out = 0x0002; + + /** Specifies that the parameter is a locale identifier. */ + public static final short Lcid = 0x0004; + + /** Specifies that the parameter is a return value. */ + public static final short Retval = 0x0008; + + /** Specifies that the parameter is optional. + * Attention: In the specification the value is 0x0004 but + * in mscorlib.dll that it Lcid and Optional is 0x0010 + */ + public static final short Optional = 0x0010; + + /** Specifies that the parameter has a default value. */ + public static final short HasDefault = 0x1000; + + /** Specifies that the parameter has field marshaling information. */ + public static final short HasFieldMarshal = 0x2000; + + /** Reserved. */ + public static final short Reserved3 = 0x4000; + + /** Reserved. */ + public static final short Reserved4 = (short)0x8000; + + /** Specifies that the parameter is reserved. */ + public static final short ReservedMask = (short)0xf000; + + /** Reserved: shall be zero in all conforming implementations. */ + public static final short Unused = (short) 0xcfe0; + + public static final String toString(int attrs) { + StringBuffer s = new StringBuffer(); + if ((attrs & In) != 0) s.append("in "); + if ((attrs & Out) != 0) s.append("out "); + if ((attrs & Optional) != 0) s.append("opt "); + if ((attrs & HasDefault) != 0) s.append("default(???) "); + if ((attrs & HasFieldMarshal) != 0) s.append("marshal(???) "); + return s.toString(); + } + + //########################################################################## + +} // class ParameterAttributes diff --git a/src/msil/ch/epfl/lamp/compiler/msil/ParameterInfo.java b/src/msil/ch/epfl/lamp/compiler/msil/ParameterInfo.java new file mode 100644 index 0000000000..df3b5f96da --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/ParameterInfo.java @@ -0,0 +1,77 @@ +/* + * System.Reflection-like API for access to .NET assemblies (DLL & EXE) + */ + +// $Id$ + +package ch.epfl.lamp.compiler.msil; + +/** + * Discovers the attributes of a parameter and provides access to + * parameter metadata. + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +public class ParameterInfo extends CustomAttributeProvider { + + //########################################################################## + + /** Attributes of the parameter. */ + public final short Attributes; + + /** Name of the parameter. */ + public final String Name; + + /** Type of the parameter. */ + public final Type ParameterType; + + /** Position of the parameter in the parameter list. */ + public final int Position; + + //########################################################################## + + /** Is this an input parameter? */ + public final boolean IsIn() { + return (Attributes & ParameterAttributes.In) != 0; + } + + /** Is this an output parameter? */ + public final boolean IsOut() { + return (Attributes & ParameterAttributes.Out) != 0; + } + + /** Is this an Lcid? */ + public final boolean IsLcid() { + return (Attributes & ParameterAttributes.Lcid) != 0; + } + + /** Is this a return value? */ + public final boolean IsRetval() { + return (Attributes & ParameterAttributes.Retval) != 0; + } + + /** Is this an optional parameter? */ + public final boolean IsOptional() { + return (Attributes & ParameterAttributes.Optional) != 0; + } + + //########################################################################## + // members not part of the public Reflection.ParameterInfo interface + + /** Initializes a new instance of the ParameterInfo class. */ + protected ParameterInfo(String name, Type type, int attr, int pos) { + Name = name; + ParameterType = type; + Attributes = (short)attr; + Position = pos; + } + + public String toString() { + return ParameterAttributes.toString(Attributes) + ParameterType + " " + + Name; + } + + //########################################################################## + +} // class ParameterInfo diff --git a/src/msil/ch/epfl/lamp/compiler/msil/PropertyAttributes.java b/src/msil/ch/epfl/lamp/compiler/msil/PropertyAttributes.java new file mode 100644 index 0000000000..ca137ba99f --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/PropertyAttributes.java @@ -0,0 +1,46 @@ +/* + * System.Reflection-like API for access to .NET assemblies (DLL & EXE) + */ + +// $Id$ + +package ch.epfl.lamp.compiler.msil; + +/** + * Attributes applcicable to properties + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +public final class PropertyAttributes { + + // makes the class uninstantiable + private PropertyAttributes() {} + + //########################################################################## + + /** Specifies that the property is special, with the name describing + * how the property is special. + */ + public static final short SpecialName = 0x0200; + + /** Specifies that the metadata internal APIs check the name encoding. + */ + public static final short RTSpecialName = 0x0400; + + /** Specifies that the property has a default value. + */ + public static final short HasDefault = 0x1000; + + //########################################################################## + + public static String toString(short attrs) { + StringBuffer str = new StringBuffer(); + if ((attrs & SpecialName) != 0) str.append("specialname "); + if ((attrs & RTSpecialName) != 0) str.append("rtspecialname "); + return str.toString(); + } + + //########################################################################## + +} // class PropertyAttributes diff --git a/src/msil/ch/epfl/lamp/compiler/msil/PropertyInfo.java b/src/msil/ch/epfl/lamp/compiler/msil/PropertyInfo.java new file mode 100644 index 0000000000..ba3d67be2e --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/PropertyInfo.java @@ -0,0 +1,105 @@ +/* + * System.Reflection-like API for access to .NET assemblies (DLL & EXE) + */ + +// $Id$ + +package ch.epfl.lamp.compiler.msil; + +/** + * Discovers the attributes of a property + * and provides access to property metadata. + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +public class PropertyInfo extends MemberInfo { + + //########################################################################## + + public final int MemberType() { return MemberTypes.Property; } + + public final short Attributes; + + public final boolean CanRead; + + public final boolean CanWrite; + + public final Type PropertyType; + + /** Returns an array of the public get and set accessors for this property. + */ + public MethodInfo[] GetAccessors() { + return GetAccessors(false); + } + + /** Returns an array of the public or non-public get + * and set accessors for this property. + */ + public MethodInfo[] GetAccessors(boolean nonPublic) { + MethodInfo getter = GetGetMethod(nonPublic); + MethodInfo setter = GetSetMethod(nonPublic); + if (getter == null) + if (setter == null) return MethodInfo.EMPTY_ARRAY; + else return new MethodInfo[]{setter}; + else if (setter == null) return new MethodInfo[] {getter}; + else return new MethodInfo[] {getter, setter}; + } + + /** Returns the public get accessor for this property. + */ + public MethodInfo GetGetMethod() { + return GetGetMethod(false); + } + + /** Returns the public or non-public get accessor for this property. + */ + public MethodInfo GetGetMethod(boolean nonPublic) { + return nonPublic ? getter + : getter == null || getter.IsPublic() ? getter : null; + } + + /** Returns the public set accessor for this property. + */ + public MethodInfo GetSetMethod() { + return GetSetMethod(false); + } + + /** Returns the public or non-public set accessor for this property. + */ + public MethodInfo GetSetMethod(boolean nonPublic) { + return nonPublic ? setter + : setter == null || setter.IsPublic() ? setter : null; + } + + public String toString() { + MethodInfo m = getter != null ? getter : setter; + return MethodAttributes.accessFlagsToString + ((getter != null ? getter : setter).Attributes) + + " " + PropertyAttributes.toString(Attributes) + + DeclaringType + "::" + Name; + } + + //########################################################################## + // protected members + + protected static final PropertyInfo[] EMPTY_ARRAY = new PropertyInfo[0]; + + protected MethodInfo getter; + protected MethodInfo setter; + + protected PropertyInfo(String name, Type declType, short attr, + Type propType, MethodInfo getter, MethodInfo setter) + { + super(name, declType); + Attributes = attr; + PropertyType = propType; + this.getter = getter; + this.setter = setter; + CanRead = getter != null; + CanWrite = setter != null; + } + + //########################################################################## + +} // class PropertyInfo diff --git a/src/msil/ch/epfl/lamp/compiler/msil/Type.java b/src/msil/ch/epfl/lamp/compiler/msil/Type.java new file mode 100644 index 0000000000..55125f0d96 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/Type.java @@ -0,0 +1,1042 @@ +/* + * System.Reflection-like API for access to .NET assemblies (DLL & EXE) + */ + +// $Id$ + +package ch.epfl.lamp.compiler.msil; + +import java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Arrays; + +/** + * Represents type declarations: class types, interface types, array types, + * value types, and enumeration types. + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +public abstract class Type extends MemberInfo { + + //########################################################################## + // public static members + + /** Empty array of type Type. */ + public static final Type[] EmptyTypes = new Type[0]; + + /** Separates names in the namespace of the Type. */ + public static final char Delimiter = '.'; + + //########################################################################## + // public properties + + /** The fully qualified name of the Type. */ + public final String FullName; + + /** The namespace of the Type. */ + public final String Namespace; + + /** The type from which the current Type directly inherits. */ + public final Type BaseType() { + initBaseType(); + return baseType; + } + protected Type baseType; + + /** The attributes associated with the Type. */ + public final int Attributes; + + /** The sssembly that the type is declared in. */ + public final Assembly Assembly() { return Module.Assembly; } + + /** The module (the EXE/DLL) in which the current Type is defined. */ + public final Module Module; + + public final int MemberType() { + return DeclaringType == null + ? MemberTypes.TypeInfo : MemberTypes.NestedType; + } + + //########################################################################## + // internal members + + // Fields declared by this class + protected FieldInfo[] fields; + + // Methods declared by this class + protected MethodInfo[] methods; + + // Constructors of this class + protected ConstructorInfo[] constructors; + + // Properties of the class + protected PropertyInfo[] properties; + + // Events of the class + protected EventInfo[] events; + + // Interfaces implemented by this class + protected Type[] interfaces; + + // Nested types declared by this class + protected Type[] nestedTypes; + + // holds the element type of array, pointer and byref types + private final Type elemType; + + // the underlying type of an enumeration. null if the type is not enum. + protected Type underlyingType; + + private int auxAttr; + + //########################################################################## + // Map with all the types known so far and operations on it + + private static final Map types = new HashMap(); + + protected static Type getType(String name) { + return (Type) types.get(name); + } + + protected static Type addType(Type t) { + Type oldType = (Type) types.put(t.FullName, t); +// if (oldType != null) +// throw new RuntimeException("The type: [" + t.Assembly + "]" + t +// + " replaces the type: [" + +// oldType.Assembly + "]" + oldType); + return t; + } + + //########################################################################## + + /** The main constructor. */ + protected Type(Module module, + int attr, + String fullName, + Type baseType, + Type[] interfaces, + Type declType, + int auxAttr, + Type elemType) + { + super(fullName.lastIndexOf(Delimiter) < 0 ? fullName : + fullName.substring(fullName.lastIndexOf(Delimiter) + 1, + fullName.length()), + declType); + + Module = module; + Attributes = attr; + this.baseType = baseType; + if (DeclaringType == null) { + FullName = fullName; + int i = FullName.lastIndexOf(Delimiter); + Namespace = (i < 0) ? "" : FullName.substring(0,i); + } else { + FullName = declType.FullName + "+" + fullName; + Namespace = DeclaringType.Namespace; + } + + this.interfaces = interfaces; + this.elemType = elemType; + this.auxAttr = auxAttr; + } + + public final boolean IsAbstract() { + return (Attributes & TypeAttributes.Abstract) != 0; + + } + public final boolean IsPublic() { + return (Attributes & TypeAttributes.VisibilityMask) + == TypeAttributes.Public; + } + + public final boolean IsNotPublic() { + return (Attributes & TypeAttributes.VisibilityMask) + == TypeAttributes.NotPublic; + } + + public final boolean IsNestedPublic() { + return (Attributes & TypeAttributes.VisibilityMask) + == TypeAttributes.NestedPublic; + } + + public final boolean IsNestedPrivate() { + return (Attributes & TypeAttributes.VisibilityMask) + == TypeAttributes.NestedPrivate; + } + + public final boolean IsNestedFamily() { + return (Attributes & TypeAttributes.VisibilityMask) + == TypeAttributes.NestedFamily; + } + + public final boolean IsNestedAssembly() { + return (Attributes & TypeAttributes.VisibilityMask) + == TypeAttributes.NestedAssembly; + } + + public final boolean IsNestedFamORAssem() { + return (Attributes & TypeAttributes.VisibilityMask) + == TypeAttributes.NestedFamORAssem; + } + + public final boolean IsNestedFamANDAssem() { + return (Attributes & TypeAttributes.VisibilityMask) + == TypeAttributes.NestedFamANDAssem; + } + + public final boolean IsSealed() { + return (Attributes & TypeAttributes.Sealed) != 0; + } + + public final boolean IsSpecialName() { + return (Attributes & TypeAttributes.SpecialName) != 0; + } + + public final boolean IsClass() { + return (Attributes & TypeAttributes.ClassSemanticsMask) + == TypeAttributes.Class; + } + + public final boolean IsInterface(){ + return (Attributes & TypeAttributes.ClassSemanticsMask) + == TypeAttributes.Interface; + } + + public final boolean IsAutoLayout() { + return (Attributes & TypeAttributes.LayoutMask) + == TypeAttributes.AutoLayout; + } + public final boolean IsExplictitLayout() { + return (Attributes & TypeAttributes.LayoutMask) + == TypeAttributes.ExplicitLayout; + } + public final boolean IsLayoutSequential() { + return (Attributes & TypeAttributes.LayoutMask) + == TypeAttributes.SequentialLayout; + } + + public final boolean IsImport() { + return (Attributes & TypeAttributes.Import) != 0; + } + public final boolean IsSerializable() { + return (Attributes & TypeAttributes.Serializable) != 0; + } + + public final boolean IsAnsiClass() { + return (Attributes & TypeAttributes.StringFormatMask) + == TypeAttributes.AnsiClass; + } + + public final boolean IsUnicodeClass() { + return (Attributes & TypeAttributes.StringFormatMask) + == TypeAttributes.UnicodeClass; + } + public final boolean IsAutoClass() { + return (Attributes & TypeAttributes.StringFormatMask) + == TypeAttributes.AutoClass; + } + + public final boolean IsArray() { + return (auxAttr & AuxAttr.Array) != 0; + } + public final boolean IsByRef() { + return (auxAttr & AuxAttr.ByRef) != 0; + } + public final boolean IsPointer() { + return (auxAttr & AuxAttr.Pointer) != 0; + } + public final boolean IsPrimitive() { + return (auxAttr & AuxAttr.Primitive) != 0; + } + public final boolean IsValueType() { + return BaseType() == VALUE_TYPE() || IsEnum(); + } + public final boolean IsEnum() { + return BaseType() == ENUM(); + } + + public final boolean HasElementType() { + return IsArray() || IsPointer() || IsByRef(); + } + + //public final boolean IsCOMObject; + //public final boolean IsContextful; + //public final boolean IsMarshalByRef; + + protected Type(Module module, + int attr, + String fullName, + Type baseType, + Type[] interfaces, + Type declType, + int auxAttr) + { + this(module, attr, fullName, baseType, interfaces, + declType, auxAttr, null); + } + + //########################################################################## + + static final class PrimitiveType extends Type { + public PrimitiveType(Module module, + int attributes, + String fullName, + Type baseType, + Type[] interfaces, + Type declType, + int auxAttr, + Type elemType) + { + super(module, attributes, fullName, + baseType, interfaces, declType, auxAttr, elemType); + } + } + + protected static final class AuxAttr { + public static final int None = 0x0000; + public static final int Array = 0x0001; + public static final int ByRef = 0x0002; + public static final int Pointer = 0x0008; + public static final int Primitive = 0x0010; + } + + /***/ + public static Type mkArray(Type elemType, int rank) { + StringBuffer arrSig = new StringBuffer("["); + for (int i = 0; i < rank; i++) { + if (i > 0) arrSig.append(','); + } + arrSig.append(']'); + Type array = getType(elemType.FullName + arrSig); + if (array != null) + return array; + array = new PrimitiveType(elemType.Module, + TypeAttributes.Public + | TypeAttributes.Sealed + | TypeAttributes.Serializable, + elemType.FullName + arrSig, + ARRAY(), EmptyTypes, null, + AuxAttr.Array, elemType); + return addType(array); + } + + /***/ + public static Type mkPtr(Type elemType) { + String name = elemType.FullName + "*"; + Type type = getType(name); + if (type != null) return type; + type = new PrimitiveType(elemType.Module, + TypeAttributes.NotPublic, + name, null, EmptyTypes, null, + AuxAttr.Pointer, elemType); + return addType(type); + } + + //########################################################################## + // public methods + + /** + * Return the type with the specified signature parameters. + * For example, the fully qualified name for a class might look like this: + * TopNamespace.SubNameSpace.ContainingClass+NestedClass,MyAssembly + */ + public static Type GetType(String fullName) { + Type type = getType(fullName); + if (type != null) return type; + + // check if it's an array type; TODO: make array type handling more robust + int i = fullName.lastIndexOf('['); + int j = fullName.lastIndexOf(']'); + if (i >= 0) + if (j > i && j == (fullName.length() - 1)) { + String elementTypeName = fullName.substring(0, i); + Type elementType = GetType(elementTypeName); + if (elementType == null) + throw new RuntimeException + ("Unknown element type '" + elementTypeName + + "' for the array type: " + fullName); + int rank = j - i; + for (int k = i + 1; k < j; k++) { + if (fullName.charAt(k) != ',') + throw new RuntimeException + ("Malformed type name: " + fullName); + } + return mkArray(elementType, rank); + } else + throw new RuntimeException("Malformed type name: " + fullName); + + // check if it's a pointer type + if (fullName.charAt(fullName.length() - 1) == '*') + return addType + (mkPtr(GetType(fullName.substring(0, fullName.length()-1)))); + + // check if it's a nested class + i = fullName.lastIndexOf('+'); + if (i > 0) { + if (i == 0 || i == (fullName.length() - 1)) + throw new RuntimeException("malformedTypeName"); + Type enclosing = GetType(fullName.substring(0, i)); + return enclosing == null ? null + : enclosing.GetNestedType(fullName.substring(i + 1)); + } + + //System.out.println("Looking for type: " + fullName + " (" + fullName.length() + ")"); + // try in the assemblies + Iterator assems = ch.epfl.lamp.compiler.msil.Assembly. + assemblies.values().iterator(); + while (type == null && assems.hasNext()) { + Assembly assem = ((Assembly) assems.next()); + type = assem.GetType(fullName); + //System.out.println("\tin assemby " + assem + " -> " + type); + } + + Type type2 = getType(fullName); + if (type == type2) return type; + return type == null ? null : addType(type); + } + + /** + * @return the type of the object encompassed or referenced to + * by the current array, pointer or reference type. + */ + public Type GetElementType() { + return elemType; + } + + /** + * @return the type underlying an enumeration type. + */ + public Type getUnderlyingType() { + if (!IsEnum()) return null; + // this would force the loading of the underlying type from the + // the type of the value__ field of the enumeration + initFields(); + return underlyingType; + } + + //########################################################################## + // GetField/s/ + + /** Searches for the field with the specified name. */ + public FieldInfo GetField(String name) { + initFields(); + for (int i = 0; i < fields.length; i++) + if (fields[i].Name.equals(name) && !fields[i].IsPrivate()) + return fields[i]; + return null; + } + + /** + */ + public FieldInfo GetField(String name, int bindingFlags) { + FieldInfo[] fields = this.GetFields(bindingFlags); + for (int i = 0; i < fields.length; i++) + if (name.equals(fields[i].Name)) + return fields[i]; + return null; + } + + /** Gets the fields of the current Type. */ + public FieldInfo[] GetFields() { + return GetFields(BindingFlags.Instance | BindingFlags.Public); + } + + /** + */ + public FieldInfo[] GetFields(int bindingFlags) { + initFields(); + final FieldInfo[] fields = + getAllFields((bindingFlags & BindingFlags.DeclaredOnly) != 0); + final boolean getInstance = (bindingFlags & BindingFlags.Instance) != 0; + final boolean getStatic = (bindingFlags & BindingFlags.Static) != 0; + final boolean getPublic = (bindingFlags & BindingFlags.Public) != 0; + final boolean getNonPublic = + (bindingFlags & BindingFlags.NonPublic) != 0; + + int cnt = 0; + for (int i = 0; i < fields.length; i++) { + FieldInfo field = fields[i]; + boolean accessible = (getPublic && field.IsPublic()) + || (getNonPublic && !field.IsPublic()); + if (accessible + // strip off the private fields up the hierarchy + && ((field.DeclaringType == this) + || ((field.DeclaringType != this) && !field.IsPrivate())) + && ((getInstance && !field.IsStatic()) + || ((getStatic && field.IsStatic()) && + (field.DeclaringType == this + || (bindingFlags & BindingFlags.FlattenHierarchy) != 0)) + ) + ) + fields[cnt++] = field; + } + FieldInfo [] resFields = new FieldInfo[cnt]; + System.arraycopy(fields, 0, resFields, 0, cnt); + return resFields; + } + + protected FieldInfo[] getAllFields(boolean declaredOnly) { + initFields(); + FieldInfo [] inherited = BaseType() == null || declaredOnly + ? FieldInfo.EMPTY_ARRAY + : BaseType().getAllFields(declaredOnly); + FieldInfo[] allFields = + new FieldInfo[inherited.length + this.fields.length]; + System.arraycopy(inherited, 0, allFields, 0, inherited.length); + System.arraycopy(this.fields, 0, + allFields, inherited.length, this.fields.length); + return allFields; + } + + //########################################################################## + // GetConstructor/s/ + + /** Searches for a public instance constructor whose parameters + * match the types in the specified array. */ + public ConstructorInfo GetConstructor(Type[] paramTypes) { + initMethods(); + for (int i = 0; i < constructors.length; i++) { + if (equalParameters(constructors[i].GetParameters(), paramTypes)) + return constructors[i]; + } + return null; + } + + /** Returns all public instance constructors defined for the current Type.*/ + public ConstructorInfo[] GetConstructors() { + return GetConstructors(BindingFlags.Instance | BindingFlags.Public); + } + + /***/ + public ConstructorInfo[] GetConstructors(int bindingFlags) { + initMethods(); + final boolean getInstance = (bindingFlags & BindingFlags.Instance) != 0; + final boolean getStatic = (bindingFlags & BindingFlags.Static) != 0; + final boolean getPublic = (bindingFlags & BindingFlags.Public) != 0; + final boolean getNonPublic = + (bindingFlags & BindingFlags.NonPublic) != 0; + + ConstructorInfo[] constrs = + new ConstructorInfo[this.constructors.length]; + int cnt = 0; + for (int i = 0; i < this.constructors.length; i++) { + ConstructorInfo constr = this.constructors[i]; + boolean accessible = (getPublic && constr.IsPublic()) + || (getNonPublic && !constr.IsPublic()); + if (accessible + && ((getInstance && !constr.IsStatic()) + || (getStatic && constr.IsStatic()))) + constrs[cnt++] = constr; + } + ConstructorInfo [] resConstrs = new ConstructorInfo[cnt]; + System.arraycopy(constrs, 0, resConstrs, 0, cnt); + return resConstrs; + } + + //########################################################################## + // GetMethod/s/ + + /** Searches for the specified public method whose parameters + * match the specified argument types. */ + public MethodInfo GetMethod(String name, Type[] paramTypes) { + return GetMethod(name, paramTypes, null); + } + + public MethodInfo GetMethod(String name, Type[] paramTypes, Type retType) { + initMethods(); + MethodInfo method = findMethod(methods, name, paramTypes, retType); + if (method != null) + return method; + if (BaseType() != null) { + method = BaseType().GetMethod(name, paramTypes, retType); + if (method != null) + return method; + } +// StringBuffer str = new StringBuffer(name); +// str.append('('); +// for (int i = 0; i < paramTypes.length; i++) { +// if (i > 0) str.append(", "); +// str.append(paramTypes[i]); +// } +// str.append(')'); +// System.out.println("Cannot find method " + str + ":"); +// System.out.println("Methods of class " + this); +// for (int i = 0; i < methods.length; i++) +// System.out.println("\t" + methods[i]); + return null; + } + + /** + */ + protected static MethodInfo findMethod(MethodInfo[] methods, + String name, + Type[] paramTypes, + Type retType) + { + for (int i = 0; i < methods.length; i++) + if (name.equals(methods[i].Name) + && equalParameters(methods[i].GetParameters(), paramTypes) + && (retType == null || methods[i].ReturnType == retType)) + return methods[i]; + return null; + } + + /** + */ + protected static boolean equalParameters(ParameterInfo[] params, + Type[] paramTypes) + { + if (params.length != paramTypes.length) + return false; + for (int i = 0; i < params.length; i++) { +// System.out.println(params[i].ParameterType + " == " + paramTypes[i] +// + " = " + (params[i].ParameterType == paramTypes[i])); + if (params[i].ParameterType != paramTypes[i]) + return false; + } + return true; + } + + /** + */ + public MethodInfo GetMethod(String name, Type[] paramTypes, int bindingFlags) { + MethodInfo[] methods = GetMethods(bindingFlags); + MethodInfo method = findMethod(methods, name, paramTypes, null); + if (method == null) { + StringBuffer str = new StringBuffer(name); + str.append('('); + for (int i = 0; i < paramTypes.length; i++) { + if (i > 0) str.append(", "); + str.append(paramTypes[i]); + } + str.append(')'); + System.out.println("Cannot find method " + str + ":"); + System.out.println("Methods of class " + this); + for (int i = 0; i < methods.length; i++) + System.out.println("\t" + methods[i]); + } + return method; + } + + /** Returns all public methods of the current Type. */ + public MethodInfo[] GetMethods() { + return GetMethods(BindingFlags.Instance | BindingFlags.Public); + } + + /** + */ + public MethodInfo[] GetMethods(int bindingFlags) { + initMethods(); + final MethodInfo[] methods = + getAllMethods((bindingFlags & BindingFlags.DeclaredOnly) != 0); + //System.out.println("" + this + ".GetMethods(int) -> " + methods.length); + final boolean getInstance = (bindingFlags & BindingFlags.Instance) != 0; + final boolean getStatic = (bindingFlags & BindingFlags.Static) != 0; + final boolean getPublic = (bindingFlags & BindingFlags.Public) != 0; + final boolean getNonPublic = + (bindingFlags & BindingFlags.NonPublic) != 0; + + int cnt = 0; + for (int i = 0; i < methods.length; i++) { + MethodInfo method = methods[i]; + boolean accessible = (getPublic && method.IsPublic()) + || (getNonPublic && !method.IsPublic()); + if (accessible + // strip off the private methods up the hierarchy + && ((method.DeclaringType == this) + || ((method.DeclaringType != this) && !method.IsPrivate())) + && ((getInstance && !method.IsStatic()) + || ((getStatic && method.IsStatic()) && + (method.DeclaringType == this + || (bindingFlags & BindingFlags.FlattenHierarchy) != 0)) + ) + ) + methods[cnt++] = method; + } + MethodInfo [] resMethods = new MethodInfo[cnt]; + System.arraycopy(methods, 0, resMethods, 0, cnt); + return resMethods; + } + + protected MethodInfo[] getAllMethods(boolean declaredOnly) { + initMethods(); + MethodInfo[] inherited = BaseType() == null || declaredOnly + ? MethodInfo.EMPTY_ARRAY + : BaseType().getAllMethods(declaredOnly); + MethodInfo[] allMethods = + new MethodInfo[inherited.length + this.methods.length]; + System.arraycopy(inherited, 0, allMethods, 0, inherited.length); + System.arraycopy(this.methods, 0, + allMethods, inherited.length, this.methods.length); + return allMethods; + } + + //########################################################################## + // GetProperty/ies/ + + /** Returns all public properties of the current Type. + */ + public PropertyInfo[] GetProperties() { + initProperties(); + return (PropertyInfo[]) properties.clone(); + } + + /** Returns the properties of the current class + * that satisfy the binding constrints. + */ + public PropertyInfo[] GetProperties(int bindingFlags) { + initProperties(); + return (PropertyInfo[]) properties.clone(); + } + + /** Returns the public property with the given name. + */ + public PropertyInfo GetProperty(String name) { + initProperties(); + for (int i = 0; i < properties.length; i++) + if (name.equals(properties[i].Name)) + return properties[i]; + return null; + } + + /** Returns the property with the given name + * that satisfies the binding constraints. + */ + public PropertyInfo GetProperty(String name, int bindingFlags) { + throw new RuntimeException("Method not implemented yet"); + } + + //########################################################################## + // GetEvent(s) + + public EventInfo[] GetEvents() { + initEvents(); + return (EventInfo[]) events.clone(); + } + + //########################################################################## + // GetNestedType/s/ + + /** Searches for nested type with the specified name. */ + public Type GetNestedType(String name) { + initNestedTypes(); + for (int i = 0; i < nestedTypes.length; i++) + if (nestedTypes[i].Name.equals(name)) + return nestedTypes[i]; + return null; + } + + /** Returns all types nested within the current Type. */ + public Type[] GetNestedTypes() { + initNestedTypes(); + return (Type[]) nestedTypes.clone(); + } + + //########################################################################## + // GetInterface/s/ + + /** Searches for an Interface with the given name implemented by this type + */ + public Type GetInterface(String name) { + return GetInterface(name, false); + } + + /** Searches for the specified interface, + * specifying whether to do a case-sensitive search. + * @param name - the name of the interface to get + * @param ignoreCase true to perform a case-insensitive search for name + * false to perform a case-sensitive search for name + * @return A Type object representing the interface with the specified name, + * implemented or inherited by the current Type, if found; + * otherwise, a null reference + */ + public Type GetInterface(String name, boolean ignoreCase) { + initInterfaces(); + for (int i = 0; i < interfaces.length; i++) { + Type iface = interfaces[i]; + if (ignoreCase) { + if (name.equalsIgnoreCase(iface.Name)) return iface; + if (name.equalsIgnoreCase(iface.FullName)) return iface; + } else { + if (name.equals(iface.Name)) return iface; + if (name.equals(iface.FullName)) return iface; + } + } + return BaseType() == null ? null + : BaseType().GetInterface(name, ignoreCase); + } + + /** Returns the interfaces implemented or inherited by the current Type. */ + public Type[] GetInterfaces() { + initInterfaces(); + if (BaseType() == null) return interfaces; + + Type[] ifaces = interfaces; + int count = 0; + for (int i = 0; i < interfaces.length; i++) { + if (BaseType().GetInterface(interfaces[i].FullName) == null) + ifaces[count++] = ifaces[i]; + } + Type[] baseTypeIfaces = BaseType().GetInterfaces(); + + Type[] res = new Type[baseTypeIfaces.length + count]; + System.arraycopy(baseTypeIfaces, 0, res, 0, baseTypeIfaces.length); + System.arraycopy(ifaces, 0, res, baseTypeIfaces.length, count); + + return res; + } + + + public boolean isSubtypeOf(Type that) { + if (this == that || BaseType() == that || that == OBJECT()) return true; + initInterfaces(); + for (int i = 0; i < interfaces.length; i++) + if (interfaces[i].isSubtypeOf(that)) + return true; + boolean res = BaseType() == null ? false : BaseType().isSubtypeOf(that); +// if (!res) { +// System.out.println(dumpType(this) + " not a subtype of " + +// dumpType(that)); +// } + return res; + } + + private static String formatType(Type t) { + if (t == null) return ""; + String cname = t.getClass().getName(); + int k = cname.lastIndexOf("."); + if (k >= 0) + cname = cname.substring(k + 1); + return "[" + t.Assembly().GetName() + "]" + t + + "(" + cname + "#" + Integer.toHexString(t.hashCode()) + ")"; + } + private static String dumpType(Type t) { + StringBuffer str = new StringBuffer(); + str.append(formatType(t) + " : "); + str.append(formatType(t.BaseType())); + Type[] ifaces = t.GetInterfaces(); + for (int i = 0; i < ifaces.length; i++) + str.append(", " + formatType(ifaces[i])); + return str.toString(); + } + + //########################################################################## + // GetMember/s/ + + protected MemberInfo[] members; + + public MemberInfo[] GetMember(String name) { + aggregateMembers(); + List l = new ArrayList(); + for (int i = 0; i < members.length; i++) { + if (name.equals(members[i].Name)) + l.add(members[i]); + } + return (MemberInfo[])l.toArray(MemberInfo.EMPTY_ARRAY); + } + + protected void aggregateMembers() { + if (members != null) + return; + initFields(); + initMethods(); + initProperties(); + initNestedTypes(); + // the List returned by Arrays.asList doesn't support the addAll method + // so we have to wrap it in ArrayList + List l = new ArrayList(Arrays.asList(fields)); + l.addAll(Arrays.asList(constructors)); + l.addAll(Arrays.asList(methods)); + l.addAll(Arrays.asList(properties)); + l.addAll(Arrays.asList(nestedTypes)); + members = (MemberInfo[]) l.toArray(MemberInfo.EMPTY_ARRAY); + } + + //########################################################################## + // non-standard methods that return only members declared in this type + + /** + * Return only the fields declared in this type. + */ + public FieldInfo[] getFields() { + initFields(); + FieldInfo[] fields = new FieldInfo[this.fields.length]; + System.arraycopy(this.fields, 0, fields, 0, fields.length); + return fields; + } + + /** + * Return only the conrtuctors declared in this type. + */ + public ConstructorInfo[] getConstructors() { + initMethods(); + ConstructorInfo[] ctors = new ConstructorInfo[constructors.length]; + System.arraycopy(constructors, 0, ctors, 0, ctors.length); + return ctors; + } + + /** + * Return only the methods declared in this type. + */ + public MethodInfo[] getMethods() { + initMethods(); + MethodInfo[] methods = new MethodInfo[this.methods.length]; + System.arraycopy(this.methods, 0, methods, 0, methods.length); + return methods; + } + + /** + * Return only the properties declared in this type. + */ + public PropertyInfo[] getProperties() { + initProperties(); + PropertyInfo[] props = new PropertyInfo[properties.length]; + System.arraycopy(properties, 0, props, 0, props.length); + return props; + } + + /** + * Return only the interfaces directly implemented by this type. + */ + public Type[] getInterfaces() { + initInterfaces(); + Type[] ifaces = new Type[interfaces.length]; + System.arraycopy(interfaces, 0, ifaces, 0, ifaces.length); + return ifaces; + } + + /** + * Return the types declared in this type. + */ + public Type[] getNestedTypes() { + initNestedTypes(); + Type[] nested = new Type[nestedTypes.length]; + System.arraycopy(nestedTypes, 0, nested, 0, nested.length); + return nested; + } + + //########################################################################## + + public String toString() { + return FullName; + } + + //########################################################################## + // lazy type construction members + + private boolean initBaseType = true; + protected final void initBaseType() { + if (initBaseType) { + loadBaseType(); + initBaseType = false; + } + } + protected void loadBaseType() {} + + private boolean initInterfaces = true; + protected void initInterfaces() { + if (initInterfaces) { + loadInterfaces(); + initInterfaces = false; + } + assert interfaces != null : "In type " + this; + } + protected void loadInterfaces() {} + + private boolean initNestedTypes = true; + protected void initNestedTypes() { + if (initNestedTypes) { + loadNestedTypes(); + initNestedTypes = false; + } + assert nestedTypes != null : "In type " + this; + } + protected void loadNestedTypes() {} + + private boolean initFields = true; + protected void initFields() { + if (initFields) { + loadFields(); + initFields = false; + } + assert fields != null : "In type " + this; + } + protected void loadFields() {} + + private boolean initMethods = true; + protected void initMethods() { + if (initMethods) { + loadMethods(); + initMethods = false; + } + assert constructors != null : "In type " + this; + assert methods != null : "In type " + this; + } + protected void loadMethods() {} + + private boolean initProperties = true; + protected void initProperties() { + if (initProperties) { + initMethods(); + loadProperties(); + initProperties = false; + } + assert properties != null : "In type " + this; + } + protected void loadProperties() {} + + private boolean initEvents = true; + protected void initEvents() { + if (initEvents) { + initMethods(); + loadEvents(); + initEvents = false; + } + assert events != null : "In type " + this; + } + protected void loadEvents() {} + + //########################################################################## + + //########################################################################## + // static members + + private static Assembly MSCORLIB; + private static Module MSCORLIB_DLL; + + public static Type OBJECT() { return __OBJECT; } + public static Type STRING() { return __STRING; } + public static Type ARRAY() { return __ARRAY; } + public static Type VOID() { return __VOID; } + public static Type ENUM() { return __ENUM; } + public static Type VALUE_TYPE() { return __VALUE_TYPE; } + + private static Type __OBJECT; + private static Type __STRING; + private static Type __ARRAY; + private static Type __VOID; + private static Type __ENUM; + private static Type __VALUE_TYPE; + + public static void initMSCORLIB(Assembly mscorlib) { + if (MSCORLIB != null) + throw new RuntimeException("mscorlib already initialized"); + MSCORLIB = mscorlib; + MSCORLIB_DLL = MSCORLIB.GetModules()[0]; + + __OBJECT = mscorlib.GetType("System.Object"); + __STRING = mscorlib.GetType("System.String"); + __ARRAY = mscorlib.GetType("System.Array"); + __VOID = mscorlib.GetType("System.Void"); + __ENUM = mscorlib.GetType("System.Enum"); + __VALUE_TYPE = mscorlib.GetType("System.ValueType"); + } + + //########################################################################## + +} // class Type diff --git a/src/msil/ch/epfl/lamp/compiler/msil/TypeAttributes.java b/src/msil/ch/epfl/lamp/compiler/msil/TypeAttributes.java new file mode 100644 index 0000000000..45ef487e24 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/TypeAttributes.java @@ -0,0 +1,191 @@ +/* + * System.Reflection-like API for access to .NET assemblies (DLL & EXE) + */ + +// $Id$ + +package ch.epfl.lamp.compiler.msil; + +/** + * Specifies type attributes. + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +public final class TypeAttributes { + + //########################################################################## + // Visibilty attributes + + /** Bitmask used to retrieve visibility information. */ + public static final int VisibilityMask = 0x00000007; + + /** Class has no public scope. */ + public static final int NotPublic = 0x00000000; + + /** Class has public scope. */ + public static final int Public = 0x00000001; + + /** Class is nested with public visibility. */ + public static final int NestedPublic = 0x00000002; + + /** Class is nested with private visibility. */ + public static final int NestedPrivate = 0x00000003; + + /** Class is nested with family visibility, and is thus accessible + * only by methods within its own type and any subtypes. */ + public static final int NestedFamily = 0x00000004; + + /** Class is nested with assembly visibility, and is thus accessible + * only by methods within its assembly. */ + public static final int NestedAssembly = 0x00000005; + + /** Class is nested with assembly and family visibility, and is thus accessible + * only by methods lying in the intersection of its family and assembly. */ + public static final int NestedFamANDAssem = 0x00000006; + + /** Class is nested with family or assembly visibility, and is thus accessible + * only by methods lying in the union of its family and assembly. */ + public static final int NestedFamORAssem = 0x00000007; + + //########################################################################## + // Class layout attributes + + /** Bitmask used to retrieve class layout information. */ + public static final int LayoutMask = 0x00000018; + + /** Class fields are automatically laid out by the CLR. */ + public static final int AutoLayout = 0x00000000; + + /** Class fields are laid out sequentially, in the order that the fields + * were emitted to the metadata. */ + public static final int SequentialLayout = 0x00000008; + + /** Class fields are laid out at the specified offsets. */ + public static final int ExplicitLayout = 0x00000010; + + //########################################################################## + // Class semantics attributes + + /** Bitmask used to retrieve class semantics information. */ + public static final int ClassSemanticsMask = 0x00000020; + + /** Type is a class. */ + public static final int Class = 0x00000000; + + /** Type is an interface. */ + public static final int Interface = 0x00000020; + + //########################################################################## + // Special semantics in addition to class semantics + + /** Class is abstract. */ + public static final int Abstract = 0x00000080; + + /** Class is cannot be extended. */ + public static final int Sealed = 0x00000100; + + /** Class is special in a way denoted by the name. */ + public static final int SpecialName = 0x00000400; + + //########################################################################## + // Implementation attributes + + /** Class/interface is imported from another module. */ + public static final int Import = 0x00001000; + + /** Class can be serialized. */ + public static final int Serializable = 0x00002000; + + //########################################################################## + // String formatting attributes + + /** Bitmask used to retrieve string information for native interop. */ + public static final int StringFormatMask = 0x00030000; + + /** LPTSTR is interpreted as ANSI. */ + public static final int AnsiClass = 0x00000000; + + /** LPTSTR is interpreted as UNICODE. */ + public static final int UnicodeClass = 0x00010000; + + /** LPTSTR is interpreted automatically. */ + public static final int AutoClass = 0x00020000; + + //########################################################################## + // Class initialization attributes + + /** Initialize the class before first static field access. */ + public static final int BeforeFieldInit = 0x00100000; + + //########################################################################## + // Additional flags + + /** CLI provides 'special' behavior, depending upon the name of the type. */ + public static final int RTSpecialName = 0x00000800; + + /** Type has security associate with it. */ + public static final int HasSecurity = 0x00040000; + + //########################################################################## + + public static String accessModsToString(int attrs) { + switch (attrs & VisibilityMask) { + case NotPublic: return "private"; + case Public: return "public"; + case NestedPublic: return "nested public"; + case NestedPrivate: return "nested private"; + case NestedFamily: return "nested family"; + case NestedAssembly: return "nested assembly"; + case NestedFamANDAssem: return "nested famandassem"; + case NestedFamORAssem: return "nested famorassem"; + default: + throw new RuntimeException(); + } + } + + /** Returns a string representation of the given attributes. */ + public static String toString(int attrs) { + StringBuffer str = new StringBuffer(accessModsToString(attrs)); + switch (attrs & LayoutMask) { + case AutoLayout: str.append(" auto"); break; + case SequentialLayout: str.append(" sequential"); break; + case ExplicitLayout: str.append(" explicit"); break; + } + switch (attrs & StringFormatMask) { + case AnsiClass: str.append(" ansi"); break; + case UnicodeClass: str.append(" unicode"); break; + case AutoClass: str.append(" autochar"); break; + } + if ((attrs & Interface) != 0) str.append(" interface"); + if ((attrs & Abstract) != 0) str.append(" abstract"); + if ((attrs & Sealed) != 0) str.append(" sealed"); + if ((attrs & BeforeFieldInit) != 0) str.append(" beforefieldinit"); + if ((attrs & Serializable) != 0) str.append(" serializable"); + if ((attrs & SpecialName) != 0) str.append(" specialname"); + if ((attrs & RTSpecialName) != 0) str.append(" rtspecialname"); + return str.toString(); + } + + /***/ + public static final boolean isNested(int attrs) { + switch (attrs & VisibilityMask) { + case NestedPublic: + case NestedPrivate: + case NestedFamily: + case NestedAssembly: + case NestedFamANDAssem: + case NestedFamORAssem: + return true; + default: return false; + } + } + + //########################################################################## + + // makes the class uninstantiable + private TypeAttributes() {} + + //########################################################################## + +} // class TypeAttributes diff --git a/src/msil/ch/epfl/lamp/compiler/msil/Version.java b/src/msil/ch/epfl/lamp/compiler/msil/Version.java new file mode 100644 index 0000000000..7276498258 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/Version.java @@ -0,0 +1,72 @@ +/* + * System.Reflection-like API for access to .NET assemblies (DLL & EXE) + */ + +// $Id$ + +package ch.epfl.lamp.compiler.msil; + + +/** + * Represents the version number for a common language runtime assembly + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +public final class Version { + + //########################################################################## + // public interface + + /** + * Gets the value of the major component of the version + * number for this instance. + */ + public final int Major; + + /** + * Gets the value of the minor component of the version + * number for this instance. + */ + public final int Minor; + + /** + * Gets the value of the build component of the version + * number for this instance. + */ + public final int Build; + + /** + * Gets the value of the revision component of the version + * number for this instance. + */ + public final int Revision; + + /** + * Initializes a new instance of the Version class. + */ + public Version() { + this(0,0,0,0); + } + + /** + * Initializes a new instance of the Version class with + * the specified major, minor, build, and revision numbers. + */ + public Version(int major, int minor, int build, int revision) { + this.Major = major; + this.Minor = minor; + this.Build = build; + this.Revision = revision; + } + + /** + * Converts the value of this instance to its equivalent String representation + */ + public String toString() { + return "" + Major + "." + Minor + "." + Build + "." + Revision; + } + + //########################################################################## + +} // class Version diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/AssemblyBuilder.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/AssemblyBuilder.scala new file mode 100644 index 0000000000..674c52d6df --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/AssemblyBuilder.scala @@ -0,0 +1,125 @@ +/* + * System.Reflection.Emit-like API for writing .NET assemblies to MSIL + */ + +// $Id: AssemblyBuilder.java 14755 2008-04-22 08:13:32Z lorch $ + +package ch.epfl.lamp.compiler.msil.emit + +import ch.epfl.lamp.compiler.msil._ +import java.util.HashMap +import java.util.HashSet +import java.util.ArrayList +import java.io.IOException + +/** + * Defines and represents a dynamic assembly. + * A dynamic assembly is an assembly that is created using the compiler.msil + * emit APIs. The dynamic modules in the assembly are saved when the dynamic + * assembly is saved using the Save method. To generate an executable, the + * SetEntryPoint method must be called to identify the method that is the + * entry point to the assembly. Assemblies are saved as DLL by default, + * unless SetEntryPoint requests the generation of a console application + * or a Windows-based application. + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +class AssemblyBuilder(name: AssemblyName) + extends Assembly(name) + with ICustomAttributeSetter + with Visitable +{ + //########################################################################## + // public methods + + /** + * Defines a dynamic module with the given name that will be saved + * to the specified file. No symbol information is emitted. + */ + def DefineDynamicModule(name: String, fileName: String): ModuleBuilder = { + val module = new ModuleBuilder(name, fileName, "" + null, this) + addModule(name, module) + return module + } + + /** Returns the dynamic module with the specified name. */ + def GetDynamicModule(name: String): ModuleBuilder = { + return GetModule(name).asInstanceOf[ModuleBuilder] + } + + /** Saves this dynamic assembly to disk. */ + @throws(classOf[IOException]) + def Save(fileName: String) { + generatedFiles = new ArrayList() + ILPrinterVisitor.printAssembly(this, fileName) + } + + @throws(classOf[IOException]) + def Save(destPath: String, sourceFilesPath: String) { + generatedFiles = new ArrayList() + ILPrinterVisitor.printAssembly(this, destPath, sourceFilesPath) + } + + /** Returns the list of generated files from calling Save(). */ + def GetGeneratedFiles(): Array[String] = { + return generatedFiles.toArray(new Array[String](generatedFiles.size())).asInstanceOf[Array[String]] + } + + /** Sets the entry point for this dynamic assembly. */ + def SetEntryPoint(entryMethod: MethodInfo) { + EntryPoint = entryMethod + } + + /** Sets a custom attribute. */ + def SetCustomAttribute(constr: ConstructorInfo, value: Array[byte]) { + addCustomAttribute(constr, value) + } + + //########################################################################## + // protected members + + // the access properties - Save, Run, RunAndSave + private var access : Int = _ + + // all extern assemblies used in this assembly builder + protected var externAssemblies = new HashSet[Assembly]() + + // register an extern assembly + protected def registerExternAssembly(assembly: Assembly) { + externAssemblies.add(assembly) + } + + // get all extern Assemblies used in this Assembly Builder + def getExternAssemblies(): Array[Assembly] = { + externAssemblies = new HashSet[Assembly](Assembly.assemblies.values().asInstanceOf[java.util.Collection[Assembly]]) + externAssemblies.remove(this) + return externAssemblies.toArray(new Array[Assembly](0)).asInstanceOf[Array[Assembly]] + } + + def loadModules() {} + + // contains list of generated .msil files after calling Save() + var generatedFiles: ArrayList[String] = new ArrayList[String]() + + //########################################################################## + //########################################################################## + + /** the apply method for a visitor */ + @throws(classOf[IOException]) + def apply(v: Visitor) { + v.caseAssemblyBuilder(this) + } + + //########################################################################## +} + +object AssemblyBuilderFactory { + /** + * Defines a dynamic assembly with the specified name. + */ + def DefineDynamicAssembly(name: AssemblyName): AssemblyBuilder = { + //Assembly.reset() + return new AssemblyBuilder(name) + } +} diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/ConstructorBuilder.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/ConstructorBuilder.scala new file mode 100644 index 0000000000..6472bf678d --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/ConstructorBuilder.scala @@ -0,0 +1,65 @@ +/* + * System.Reflection.Emit-like API for writing .NET assemblies to MSIL + */ + +// $Id: ConstructorBuilder.java 14655 2008-04-15 09:37:02Z lorch $ + +package ch.epfl.lamp.compiler.msil.emit + +import ch.epfl.lamp.compiler.msil.ConstructorInfo +import ch.epfl.lamp.compiler.msil.Type +import java.io.IOException + +/** + * Defines and represents a constructor of a dynamic class. + * ConstructorBuilder is used to fully describe a constructor in + * Microsoft intermediate language (MSIL), including the name, attributes, + * signature, and constructor body. It is used in conjunction with the + * TypeBuilder class to create classes at run time. Call DefineConstructor + * to get an instance of ConstructorBuilder. + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +class ConstructorBuilder(declType: Type, attrs: int, paramTypes: Array[Type]) + extends ConstructorInfo(declType, attrs, paramTypes) + with ICustomAttributeSetter + with Visitable +{ + + //########################################################################## + // public interface + + /** Defines a parameter of this constructor. */ + def DefineParameter(pos: int, attr: int, name: String): ParameterBuilder = { + val param = new ParameterBuilder(name, params(pos).ParameterType, attr, pos) + params(pos) = param + return param + } + + /** Returns an ILGenerator for this constructor. */ + def GetILGenerator(): ILGenerator = { + return ilGenerator + } + + /** Sets a custom attribute. */ + def SetCustomAttribute(constr: ConstructorInfo, value: Array[Byte]) { + addCustomAttribute(constr, value) + } + + //########################################################################## + + /** The apply method for a visitor. */ + @throws(classOf[IOException]) + def apply(v: Visitor) { + v.caseConstructorBuilder(this) + } + + //########################################################################## + + // the Intermediate Language Generator + // it contains the method's body + protected var ilGenerator: ILGenerator = new ILGenerator(this) + + //########################################################################## +} diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/EmitUtils.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/EmitUtils.scala new file mode 100644 index 0000000000..a2c71df0d7 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/EmitUtils.scala @@ -0,0 +1,55 @@ +/* + * System.Reflection.Emit-like API for writing .NET assemblies to MSIL + */ + +// $Id: EmitUtils.java 168 2005-12-12 14:20:06Z mihaylov $ + +package ch.epfl.lamp.compiler.msil.emit + +import ch.epfl.lamp.compiler.msil.* + +/** + * This class holds some usefull methods or fields which are not in the + * Reflection or Reflection.Emit Namespace (see .NET documentation) + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +object EmitUtils { + + //########################################################################## + + /** + * Defines a dynamic assembly with the specified name. + */ + def DefineDynamicAssembly(name: AssemblyName): AssemblyBuilder = new AssemblyBuilder(name) + + /** + * Helper functions that adds a space only after non-empty string + */ + def append(sb: StringBuffer, str: String): StringBuffer = { + if (sb.length() > 0) { + var last: Char = sb.charAt(sb.length() - 1) + if (last != ' ' && last != '\t' || last != '\n') + sb.append(" ") + } + //return sb.append(str) + return trim(sb.append(str)) + } + + /** + * Helper functions that adds a space only after non-empty string + */ + def append(str: StringBuffer, o: Object): String = append(str, "" + o) + + /** + * Helper function that removes the trailing spaces + */ + def trim(sb: StringBuffer): StringBuffer = { + while ((sb.length() > 0) && (sb.charAt(sb.length() - 1) == ' ')) + sb.deleteCharAt(sb.length() - 1) + return sb + } + + //########################################################################## +} diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/EmitUtils.scala2 b/src/msil/ch/epfl/lamp/compiler/msil/emit/EmitUtils.scala2 new file mode 100644 index 0000000000..c59a4293e8 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/EmitUtils.scala2 @@ -0,0 +1,55 @@ +/* + * System.Reflection.Emit-like API for writing .NET assemblies to MSIL + */ + +// $Id: EmitUtils.java 168 2005-12-12 14:20:06Z mihaylov $ + +package ch.epfl.lamp.compiler.msil.emit + +import ch.epfl.lamp.compiler.msil.* + +/** + * This class holds some usefull methods or fields which are not in the + * Reflection or Reflection.Emit Namespace (see .NET documentation) + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +object EmitUtils { + + //########################################################################## + + /** + * Defines a dynamic assembly with the specified name. + */ + def DefineDynamicAssembly(name: AssemblyName): AssemblyBuilder = new AssemblyBuilder(name) + + /** + * Helper functions that adds a space only after non-empty string + */ + def append(sb: StringBuffer, str: String): StringBuffer = { + if (sb.length() > 0) { + var last: Char = sb.charAt(sb.length() - 1) + if (last != ' ' && last != '\t' || last != '\n') + sb.append(" ") + } + //return sb.append(str) + return trim(sb.append(str)) + } + + /** + * Helper functions that adds a space only after non-empty string + */ + def append(str: StringBuffer, o: Object): String = append(str, "" + o) + + /** + * Helper function that removes the trailing spaces + */ + def trim(sb: StringBuffer): StringBuffer = { + while ((sb.length() > 0) && (sb.charAt(sb.length() - 1) == ' ')) + sb.deleteCharAt(sb.length() - 1) + return sb + } + + //########################################################################## +} diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/EmptyVisitor.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/EmptyVisitor.scala new file mode 100644 index 0000000000..ea1d428db0 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/EmptyVisitor.scala @@ -0,0 +1,83 @@ +/* + * System.Reflection.Emit-like API for writing .NET assemblies to MSIL + */ + +// $Id: EmptyVisitor.java 168 2005-12-12 14:20:06Z mihaylov $ + +package ch.epfl.lamp.compiler.msil.emit + +/** + * Supplies empty method bodies to be overridden by subclasses. + */ +class EmptyVisitor extends Visitor { + + //########################################################################## + + /** + * Visit an AssemblyBuilder + */ + def caseAssemblyBuilder(assemblyBuilder: AssemblyBuilder) { + } + + /** + * Visit a ModuleBuilder + */ + def caseModuleBuilder(moduleBuilder: ModuleBuilder) { + } + + /** + * Visit a TypeBuilder + */ + def caseTypeBuilder(typeBuilder: TypeBuilder) { + } + + /** + * Visit a FieldBuilder + */ + def caseFieldBuilder(fieldBuilder: FieldBuilder) { + } + + /** + * Visit a ConstructorBuilder + */ + def caseConstructorBuilder(constructorBuilder: ConstructorBuilder) { + } + + /** + * Visit a MethodBuilder + */ + def caseMethodBuilder(methodBuilder: MethodBuilder) { + } + + /** + * Visit a ParameterBuilder + */ + def caseParameterBuilder(parameterBuilder: ParameterBuilder) { + } + + /** + * Visit an ILGenerator + */ + def caseILGenerator(iLGenerator: ILGenerator) { + } + + /** + * visit an OpCode + */ + def caseOpCode(opCode: OpCode) { + } + + /** + * Visit a Label + */ + def caseLabel(label: Label) { + } + + /** + * Visit a LocalBuilder + */ + def caseLocalBuilder(localBuilder: LocalBuilder) { + } + + //########################################################################## +} diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/EmptyVisitor.scala2 b/src/msil/ch/epfl/lamp/compiler/msil/emit/EmptyVisitor.scala2 new file mode 100644 index 0000000000..ea1d428db0 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/EmptyVisitor.scala2 @@ -0,0 +1,83 @@ +/* + * System.Reflection.Emit-like API for writing .NET assemblies to MSIL + */ + +// $Id: EmptyVisitor.java 168 2005-12-12 14:20:06Z mihaylov $ + +package ch.epfl.lamp.compiler.msil.emit + +/** + * Supplies empty method bodies to be overridden by subclasses. + */ +class EmptyVisitor extends Visitor { + + //########################################################################## + + /** + * Visit an AssemblyBuilder + */ + def caseAssemblyBuilder(assemblyBuilder: AssemblyBuilder) { + } + + /** + * Visit a ModuleBuilder + */ + def caseModuleBuilder(moduleBuilder: ModuleBuilder) { + } + + /** + * Visit a TypeBuilder + */ + def caseTypeBuilder(typeBuilder: TypeBuilder) { + } + + /** + * Visit a FieldBuilder + */ + def caseFieldBuilder(fieldBuilder: FieldBuilder) { + } + + /** + * Visit a ConstructorBuilder + */ + def caseConstructorBuilder(constructorBuilder: ConstructorBuilder) { + } + + /** + * Visit a MethodBuilder + */ + def caseMethodBuilder(methodBuilder: MethodBuilder) { + } + + /** + * Visit a ParameterBuilder + */ + def caseParameterBuilder(parameterBuilder: ParameterBuilder) { + } + + /** + * Visit an ILGenerator + */ + def caseILGenerator(iLGenerator: ILGenerator) { + } + + /** + * visit an OpCode + */ + def caseOpCode(opCode: OpCode) { + } + + /** + * Visit a Label + */ + def caseLabel(label: Label) { + } + + /** + * Visit a LocalBuilder + */ + def caseLocalBuilder(localBuilder: LocalBuilder) { + } + + //########################################################################## +} diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/FieldBuilder.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/FieldBuilder.scala new file mode 100644 index 0000000000..e8941e7ab8 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/FieldBuilder.scala @@ -0,0 +1,58 @@ +/* + * System.Reflection.Emit-like API for writing .NET assemblies to MSIL + */ + +// $Id: FieldBuilder.java 14655 2008-04-15 09:37:02Z lorch $ + +package ch.epfl.lamp.compiler.msil.emit + +import ch.epfl.lamp.compiler.msil.FieldInfo +import ch.epfl.lamp.compiler.msil.Type +import ch.epfl.lamp.compiler.msil.FieldAttributes +import ch.epfl.lamp.compiler.msil.ConstructorInfo +import java.io.IOException + +/** + * Discovers the attributes of a field and provides access to field metadata. + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +class FieldBuilder(name: String, declType: Type, attrs: int, fieldType: Type) + extends FieldInfo(name, declType, attrs, fieldType) + with ICustomAttributeSetter + with Visitable +{ + + //########################################################################## + // public interface + + /** Sets a custom attribute. */ + def SetCustomAttribute(constr: ConstructorInfo, value: Array[Byte]) { + addCustomAttribute(constr, value) + } + + //########################################################################## + + /** the apply method for a visitor */ + @throws(classOf[IOException]) + def apply(v: Visitor) { + v.caseFieldBuilder(this) + } + + //########################################################################## + + protected var defaultValue: Object = _ + + /** Sets the default value of this field. */ + def SetConstant(defaultValue: Object) { + this.defaultValue = defaultValue + } + + /** Specifies the field layout. */ + def SetOffset(iOffset: Int) { + //this.fieldOffset = FieldAttributes.Offset.Value(iOffset) + } + + //########################################################################## +} diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/ICustomAttributeSetter.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/ICustomAttributeSetter.scala new file mode 100644 index 0000000000..1249223b83 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/ICustomAttributeSetter.scala @@ -0,0 +1,19 @@ +/* + * System.Reflection.Emit-like API for writing .NET assemblies to MSIL + */ + +// $Id: ICustomAttributeSetter.java 168 2005-12-12 14:20:06Z mihaylov $ + +package ch.epfl.lamp.compiler.msil.emit + +import ch.epfl.lamp.compiler.msil.ConstructorInfo + +/** + * Declares the possibility to set a custom attribute for a member + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +trait ICustomAttributeSetter { + def SetCustomAttribute(constr: ConstructorInfo, value: Array[byte]) +} diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/ILGenerator.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/ILGenerator.scala new file mode 100644 index 0000000000..a94259dd2e --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/ILGenerator.scala @@ -0,0 +1,538 @@ +/* + * System.Reflection.Emit-like API for writing .NET assemblies to MSIL + */ + +// $Id: ILGenerator.java 14655 2008-04-15 09:37:02Z lorch $ + +package ch.epfl.lamp.compiler.msil.emit + +import ch.epfl.lamp.compiler.msil._ +import ch.epfl.lamp.compiler.msil.util.Table +import java.util.ArrayList +import java.util.Stack +import java.util.Iterator +import java.util.Map +import java.util.HashMap +import java.io.IOException +import ILGenerator._ + +/** + * Generates Microsoft intermediate language (MSIL) instructions. + * + * @author Nikolay Mihaylov + * @version 1.0 + */ + final class ILGenerator(_owner: MethodBase) extends Visitable { + + //########################################################################## + // public interface + + /** + * Puts the specified instruction onto the stream of instructions. + */ + def Emit(opcode: OpCode) { + // switch opcode + if (opcode == OpCode.Ret) { + emit(opcode, null, 0) + } else { + emit(opcode, null) + } + } + + /** + * Puts the specified instruction and character argument onto + * the Microsoft intermediate language (MSIL) stream of instructions. + */ + def Emit(opcode: OpCode, arg: Char) { + emit(opcode,new Character(arg)) + } + + /** + * Puts the specified instruction and metadata token for the + * specified constructor onto the Microsoft intermediate language + * (MSIL) stream of instructions. + */ + def Emit(opcode: OpCode, arg: ConstructorInfo) { + assert(arg != null) + // newobj + // pop size is the number of parameters + emit(opcode,arg, OpCode.PUSH_size(opcode.CEE_push) - + arg.GetParameters().length) + } + + /** + * Puts the specified instruction onto the Microsoft intermediate language (MSIL) + * stream followed by the index of the given local variable. + */ + def Emit(opcode: OpCode, arg: LocalBuilder) { + assert(arg != null) + // ldarg | ldarg.s | ldarga + // ldarga.s | ldloc | ldloc.s | ldloca + // ldloca.s | starg | starg.s | stloc + // stloc.s + + // + emit(opcode, arg) + } + + + /** + * Puts the specified instruction and numerical argument onto + * the Microsoft intermediate language (MSIL) stream of instructions. + */ + def Emit(opcode: OpCode, arg: Double) { + // ldc.r4 | ldc.r8 + emit(opcode, new java.lang.Double(arg)) + } + + /** + * Puts the specified instruction and metadata token for the + * specified field onto the Microsoft intermediate language (MSIL) + * stream of instructions. + */ + def Emit(opcode: OpCode,arg: FieldInfo) { + assert(arg != null) + // ldfld | ldflda | ldsfld | ldsflda | stfld | stsfld + emit(opcode,arg) + } + + /** + * Puts the specified instruction and numerical argument onto + * the Microsoft intermediate language (MSIL) stream of instructions. + */ + def Emit(opcode: OpCode, arg: Short ) { + emit(opcode, new java.lang.Short(arg)) + } + + /** + * Puts the specified instruction and numerical argument onto + * the Microsoft intermediate language (MSIL) stream of instructions. + */ + def Emit(opcode: OpCode, arg: Int) { + // ldc.i4 | ldc.i4.s | unaligned + emit(opcode, new java.lang.Integer(arg)) + } + + /** + * Puts the specified instruction and numerical argument onto + * the Microsoft intermediate language (MSIL) stream of instructions. + */ + def Emit(opcode: OpCode, arg: Long) { + // ldc.i8 + emit(opcode, new java.lang.Long(arg)) + } + + /** + * Puts the specified instruction onto the Microsoft intermediate + * language (MSIL) stream and leaves space to include a label when + * fixes are done. + */ + def Emit(opcode: OpCode,label: Label) { + assert(label != null) + // beq | beq.s | bge | bge.s | + // bge.un | bge.un.s | bgt | bgt.s | bgt.un | bgt.un.s | + // ble | ble.s | ble.un | ble.un.s | blt | blt.s | + // blt.un | blt.un.s | bne.un | bne.un.s | br | br.s | + // brfalse | brfalse.s | brtrue | brtrue.s | leave | leave.s + + emit(opcode, label) + // is the label initialized ? if true backward jump else forward jump + if (label.isInitialized()) { +// if (arg.stacksize != lastLabel.stacksize) { +// System.err.println("ILGenerator.Emit: Stack depth differs depending on path:"); +// System.err.println("\tmethod = " + owner); +// System.err.println("\tPC = 0x" + Table.short2hex(lastLabel.address)); +// } + //assert arg.stacksize == lastLabel.stacksize; + } + else { + label.setStacksize(lastLabel.getStacksize()) + } + } + + /** + * Puts the specified instruction onto the Microsoft intermediate + * language (MSIL) stream and leaves space to include a label when + * fixes are done. + */ + def Emit(opcode: OpCode, arg: Array[Label] ) { + assert(arg != null) + // switch + + // ::= ( ) + // Examples: + // switch (0x3, -14, Label1) + // switch (5, Label2) + emit(opcode, arg, arg.length) + } + + /** + * Puts the specified instruction onto the Microsoft intermediate + * language (MSIL) stream followed by the metadata token for the + * given method. + */ + def Emit(opcode: OpCode,arg: MethodInfo) { + assert(arg != null) + // call | callvirt | jmp | ldftn | ldvirtftn + // pop size is the number of parameters + // pop 1 more if method is not static ! + // push size is either 0 (void Method) either 1 + assert(arg.ReturnType != null, "No ReturnType: " + arg.DeclaringType + "::" + arg.Name) + + val popush: Int = if (opcode == OpCode.Ldftn || + opcode == OpCode.Ldvirtftn || + opcode == OpCode.Jmp) + { + OpCode.PUSH_size(opcode.CEE_push) - OpCode.POP_size(opcode.CEE_pop) + } else if (opcode == OpCode.Calli || opcode == OpCode.Callvirt) { + (if(arg.ReturnType == VOID) 0 else 1) - arg.GetParameters().length - 1 + } else { + (if(arg.ReturnType == VOID) 0 else 1) - arg.GetParameters().length + } + emit(opcode, arg, popush) + } + + /** + * Puts the specified instruction and numerical argument onto + * the Microsoft intermediate language (MSIL) stream of instructions. + */ + def Emit(opcode: OpCode, arg: Float ) { + emit(opcode, new java.lang.Float(arg)) + } + + /** + * Puts the specified instruction onto the Microsoft intermediate + * language (MSIL) stream followed by the metadata token for the + * given string. + */ + def Emit(opcode: OpCode, arg: String ) { + assert(arg != null) + // ldstr + emit(opcode, arg) + } + + /** + * Puts the specified instruction onto the Microsoft intermediate + * language (MSIL) stream followed by the metadata token for the + * given type. + */ + def Emit(opcode: OpCode, arg: Type) { + assert(arg != null) + // box | castclass | cpobj | initobj | isinst | + // ldelema | ldobj | mkrefany | newarr | refanyval | + // sizeof | stobj | unbox + + emit(opcode, arg) + } + + /** + * Puts a call or callvirt instruction onto the Microsoft intermediate + * language (MSIL) stream. + */ + def EmitCall(opcode: OpCode, arg: MethodInfo, + optionalParameterTypes: Array[Type]) { + assert(arg != null) + // pop size is the number of parameters + // push size is either 0 (void Method) either 1 + //System.out.println(arg.ReturnType.Size + " " + arg.GetParameters().length); + emit(opcode, arg, (if(arg.ReturnType == VOID) 0 else 1) - + arg.GetParameters().length) + } + + /** + * Emits the Microsoft intermediate language (MSIL) necessary to + * call WriteLine with the given field. + */ + def EmitWriteLine(arg: FieldInfo) { + // first load field info + // if static use OpCode.Ldsfld + if (arg.IsStatic()) + Emit(OpCodes.Ldsfld, arg) + else + Emit(OpCodes.Ldfld, arg) + // then call System.Console.WriteLine(arg.Type) + val t: Type = Type.GetType("System.Console") + val argsType: Array[Type] = new Array[Type](1) + argsType(0) = arg.FieldType + val m: MethodInfo = t.GetMethod("WriteLine", argsType) + EmitCall(OpCode.Call, m, null) + } + + /** + * Emits the Microsoft intermediate language (MSIL) necessary + * to call WriteLine with the given local variable. + */ + def EmitWriteLine(arg: LocalBuilder) { + // first load local variable + Emit(OpCodes.Ldloc, arg) + // then call System.Console.WriteLine(arg.Type) + val t: Type = Type.GetType("System.Console") + val argsType: Array[Type] = new Array[Type](1) + argsType(0) = arg.LocalType + val m: MethodInfo = t.GetMethod("WriteLine", argsType) + EmitCall(OpCode.Call, m, null) + } + + /** + * Emits the Microsoft intermediate language (MSIL) to call + * WriteLine with a string. + */ + def EmitWriteLine(arg: String) { + // first load string + Emit(OpCode.Ldstr, arg) + // then call System.Console.WriteLine(string) + val t: Type = Type.GetType("System.Console") + val argsType: Array[Type] = new Array[Type](1) + argsType(0) = Type.GetType("System.String") + val m: MethodInfo = t.GetMethod("WriteLine", argsType) + EmitCall(OpCode.Call, m, null) + } + + /** + * Declares a local variable. + */ + def DeclareLocal(localType: Type): LocalBuilder = { + val l: LocalBuilder = new LocalBuilder(locals, localType) + locals = locals + 1 + localList.add(l) + return l + } + + /** + * Returns a new label that can be used as a token for branching. + * In order to set the position of the label within the stream, you + * must call MarkLabel. This is just a token and does not yet represent + * any particular location within the stream. + */ + def DefineLabel():Label = { + new Label.NormalLabel() + } + + /** + * Marks the Microsoft intermediate language (MSIL) stream's + * current position with the given label. + */ + def MarkLabel(label: Label) { + label.mergeWith(lastLabel) + /* + label.address = lastLabel.address; + //label.stacksize = lastLabel.stacksize; + if (label.stacksize >= 0) + lastLabel.stacksize = label.stacksize; + */ + } + + /** Begins a lexical scope. */ + def BeginScope() { + emitSpecialLabel(Label.NewScope) + } + + /** Ends a lexical scope. */ + def EndScope() { + emitSpecialLabel(Label.EndScope) + } + + /** + * Begins an exception block for a non-filtered exception. + * The label for the end of the block. This will leave you in the correct + * place to execute finally blocks or to finish the try. + */ + def BeginExceptionBlock() { + emitSpecialLabel(Label.Try) + val endExc: Label = new Label.NormalLabel() // new Label(lastLabel) ??? + excStack.push(Label.Try, endExc) + return endExc + } + + /** Begins a catch block. */ + def BeginCatchBlock(exceptionType: Type) { + val kind = excStack.peekKind() + if (kind == Label.Kind.Try || + kind == Label.Kind.Catch) { + /* ok */ + } else { + throw new RuntimeException("Catch should follow either a try or catch") + } + val endExc: Label = excStack.popLabel() + Emit(OpCodes.Leave, endExc) + // the CLI automatically provide the exception object on the evaluation stack + // we adjust the stacksize + lastLabel.incStacksize() + excStack.push(Label.Catch, endExc) + emitSpecialLabel(Label.Catch, exceptionType) + } + + /** Ends an exception block. */ + def EndExceptionBlock() { + val kind = excStack.peekKind() + if (kind == Label.Kind.Try) { + throw new RuntimeException("Try block with neither catch nor finally") + } else if (kind == Label.Kind.Catch) { + Emit(OpCodes.Leave, excStack.peekLabel()) + } else if (kind == Label.Kind.Finally) { + Emit(OpCodes.Endfinally) + } + MarkLabel(excStack.popLabel()) + emitSpecialLabel(Label.EndTry) + } + + /** + * Begins a finally block in the Microsoft intermediate language + * (MSIL) instruction stream. + */ + def BeginFinallyBlock() { + Emit(OpCodes.Leave, excStack.peekLabel()) + emitSpecialLabel(Label.Finally) + } + + /** + * Emits an instruction to throw an exception. + */ + def ThrowException(exceptionType: Type) { + assert(exceptionType != null) + if (!exceptionType.isSubtypeOf(Type.GetType("System.Exception"))) + throw new RuntimeException + (exceptionType + " doesn't extend System.Exception" ) + val ctor: ConstructorInfo = exceptionType.GetConstructor(Type.EmptyTypes) + if (ctor == null) + throw new RuntimeException("Type " + exceptionType + + "doesn't have a default constructor") + Emit(OpCodes.Newobj, ctor) + Emit(OpCodes.Throw) + } + + /** + * sets the line of the source file corresponding to the next instruction + */ + def setPosition(line: Int) { + if (line != 0) + lineNums.put(lastLabel, Integer.toString(line)) + } + + def setPosition(line: Int, filename: String) { + if (line != 0) + lineNums.put(lastLabel, line + " '" + filename + "'") + } + + def getLocals(): Array[LocalBuilder] = { + localList.toArray(new Array[LocalBuilder](0)).asInstanceOf[Array[LocalBuilder]] + } + + def getLabelIterator(): Iterator[Label] = { + labelList.iterator() + } + def getOpcodeIterator(): Iterator[OpCode] = { + opcodeList.iterator() + } + def getArgumentIterator(): Iterator[Object] = { + argumentList.iterator() + } + + //########################################################################## + // private implementation details + + + + // the local variable list + private final val localList: ArrayList[LocalBuilder] = new ArrayList[LocalBuilder]() + + // the label list, the opcode list and the opcode argument list + // labelList is an array of Label + // opcodeList is an array of OpCode + // argumentList is an array of Object (null if no argument) + private final val labelList: ArrayList[Label] = new ArrayList[Label]() + private final val opcodeList: ArrayList[OpCode] = new ArrayList[OpCode]() + private final val argumentList: ArrayList[Object] = new ArrayList[Object]() + + // the program counter (pc) + // also called the stream's current position + private var pc: Int = 0 + + // last label + private var lastLabel: Label = new Label.NormalLabel(pc,0) + + // the maximum size of stack + private var maxstack: Int = 0 + + // the number of the locals + private var locals: Int = 0 + + // stack of label for exception mechanism + private var excStack: ExceptionStack = new ExceptionStack() + + // the method info owner of this ILGenerator + var owner: MethodBase = _owner + + val lineNums: Map[Label, String] = new HashMap[Label, String]() + + + def getMaxStacksize(): Int = { this.maxstack } + + // private emit with Object Argument + private def emit(opcode: OpCode, arg: Object) { + emit(opcode, arg, opcode.CEE_popush) + } + + // private emit with Object Argument and override POPUSH + private def emit(opcode: OpCode, arg: Object, overridePOPUSH: Int) { + // add label, opcode and argument + labelList.add(lastLabel) + opcodeList.add(opcode) + argumentList.add(arg) + // compute new lastLabel (next label) + val stackSize: Int = lastLabel.getStacksize() + overridePOPUSH + if (stackSize < 0) { + throw new RuntimeException + //System.err.println + ("ILGenerator.emit(): Stack underflow in method: " + owner) + } + if (stackSize > maxstack) + maxstack = stackSize + var address: Int = lastLabel.getAddress() + opcode.CEE_length + if (opcode.CEE_opcode == OpCode.CEE_SWITCH) { + address = address + 4*arg.asInstanceOf[Array[Label]].length + } + lastLabel = new Label.NormalLabel(address, stackSize) + pc = pc + 1 + } + + private def emitSpecialLabel(l: Label) { + emitSpecialLabel(l, null) + } + private def emitSpecialLabel(l: Label, catchType: Type) { + labelList.add(l) + opcodeList.add(null) + argumentList.add(catchType) + } + + //########################################################################## + // + @throws(classOf[IOException]) + def apply(v: Visitor) { + v.caseILGenerator(this) + } + + //########################################################################## +} // class ILGenerator + + +object ILGenerator { + + val VOID: Type = Type.GetType("System.Void") + val NO_LABEL: String = "" + + private final class ExceptionStack { + private val labels: Stack[Label] = new Stack[Label]() + private val kinds: Stack[Label] = new Stack[Label]() + def ExceptionStack() {} + def pop() { labels.pop(); kinds.pop() } + def push(kind: Label, label: Label) { + kinds.push(kind); labels.push(label) + } + def peekKind(): Label.Kind = {kinds.peek().asInstanceOf[Label].getKind() } + def peekLabel(): Label = { labels.peek().asInstanceOf[Label] } + def popLabel(): Label = { kinds.pop(); labels.pop().asInstanceOf[Label]} + } + +} + diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/ILPrinterVisitor.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/ILPrinterVisitor.scala new file mode 100644 index 0000000000..e6b7cf4bbe --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/ILPrinterVisitor.scala @@ -0,0 +1,735 @@ +/* + * System.Reflection.Emit-like API for writing .NET assemblies in MSIL + */ + +// $Id: ILPrinterVisitor.java 14755 2008-04-22 08:13:32Z lorch $ + +package ch.epfl.lamp.compiler.msil.emit + +import java.io.File +import java.io.FileWriter +import java.io.BufferedWriter +import java.io.PrintWriter +import java.io.IOException +import java.util.Iterator +import java.util.HashMap +import java.util.Arrays +import java.util.Comparator + +import ch.epfl.lamp.compiler.msil._ +import ch.epfl.lamp.compiler.msil.util.Table + +/** + * The MSIL printer Vistor. It prints a complete + * assembly in a single or multiple files. Then this file can be compiled by ilasm. + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +abstract class ILPrinterVisitor extends Visitor { + + import ILPrinterVisitor._ + import OpCode._ + + //########################################################################## + + protected final val assemblyNameComparator = + new Comparator[Assembly]() { + def compare(o1: Assembly, o2: Assembly): Int = { + val a1 = o1.asInstanceOf[Assembly] + val a2 = o2.asInstanceOf[Assembly] + return a1.GetName().Name.compareTo(a2.GetName().Name) + } + } + + // the output file writer + protected var out: PrintWriter = null + + // the left margin + private var lmargin = 0 + + // indicate a newline + private var newline = true + + // print types without or with members? + protected var nomembers: boolean = false + + // external assemblies + protected var as: Array[Assembly] = null + + private def align() { + if (newline) + padding = lmargin + printPadding() + newline = false + } + private def indent() { + lmargin += TAB + } + private def undent() { + lmargin -= TAB + assert(lmargin >= 0) + } + + private var padding = 0 + private def pad(n: Int) { + assert(n >= 0, "negative padding: " + n) + padding += n + } + private def printPadding() { + if (padding <= 0) + return + while (padding > SPACES_LEN) { + out.print(SPACES) + padding -= SPACES_LEN + } + out.print(SPACES.substring(0, padding)) + padding = 0 + } + + // methods to print code + protected def print(s: String) { align(); out.print(s)} + protected def print(o: Object) { align(); out.print(o) } + protected def print(c: char) { align(); out.print(c) } + protected def print(`val`: int) { align(); out.print(`val`)} + protected def print(`val`: long){ align(); out.print(`val`)} + protected def println() { out.println(); newline = true; padding = 0 } + protected def println(c: char) { print(c); println() } + protected def println(i: int) { print(i); println() } + protected def println(l: long) { print(l); println() } + protected def println(s: String){ print(s); println() } + protected def println(o: Object){ print(o); println() } + protected def printName(name: String) { + var ch = name.charAt(0) + //if (Character.isLetter(ch) && Character.isLowerCase(ch)) { + if (ch != '.') { + print('\''); print(name); print('\'') + } else + print(name) + } + + protected def printAssemblyBoilerplate() { + // print all the external assemblies + for (val j <- 0 until as.length) { + printAssemblySignature(as(j), true) + } + // print assembly declaration + printAssemblySignature(currAssembly, false) + } + + // the entrypoint method + protected var entryPoint: MethodInfo = null + + // current opcode argument + protected var argument: Object = null + + /***/ + @throws(classOf[IOException]) + protected def print(vAble: Visitable) { + if (vAble != null) + vAble.apply(this) + } + + /** + * Visit an AssemblyBuilder + */ + @throws(classOf[IOException]) + def caseAssemblyBuilder(assemblyBuilder: AssemblyBuilder) + + protected var currentModule: Module = null + /** + * Visit a ModuleBuilder + */ + @throws(classOf[IOException]) + def caseModuleBuilder(module: ModuleBuilder) + + protected var currentType: Type = null + /** + * Visit a TypeBuilder + */ + @throws(classOf[IOException]) + def caseTypeBuilder(`type`: TypeBuilder) { + currentType = `type` + if (!`type`.Namespace.equals("") && `type`.DeclaringType == null) { + print(".namespace \'" ); print(`type`.Namespace); println("\'") + println("{"); indent() + } + print(".class ") + // ::= + // * + // [extends ] + // [implements [, ]*] + print(TypeAttributes.toString(`type`.Attributes)) + print(" \'"); print(`type`.Name); print("\'") + if (`type`.BaseType() != null) { + println() + print(" extends ") + printReference(`type`.BaseType()) + } + var ifaces: Array[Type] = `type`.getInterfaces() + if (ifaces.length > 0) { + println() + print(" implements ") + for (val i <- 0 until ifaces.length) { + if (i > 0) { + println(",") + print(" ") + } + printReference(ifaces(i)) + } + } + println() + println("{") + indent() + if (!nomembers && `type`.sourceFilename != null) + println(".line " + `type`.sourceLine + + " '" + `type`.sourceFilename + "'") + if (!nomembers) { + printAttributes(`type`) + } + // print nested classes + val nested = `type`.nestedTypeBuilders.iterator() + while(nested.hasNext()) + print(nested.next().asInstanceOf[TypeBuilder]) + + // print each field + val fields = `type`.fieldBuilders.iterator() + while(fields.hasNext()) + print(fields.next().asInstanceOf[FieldBuilder]) + + // print each constructor + val constrs = `type`.constructorBuilders.iterator() + while (constrs.hasNext()) + print(constrs.next().asInstanceOf[ConstructorBuilder]) + + // print each method + val methods = `type`.methodBuilders.iterator() + while (methods.hasNext()) { + val method = methods.next().asInstanceOf[MethodBuilder] + assert(method.DeclaringType == `type`) + print(method) + } + + undent(); println("}") + if (!`type`.Namespace.equals("") && `type`.DeclaringType == null) { + undent(); println("}") + } + currentType = null + } + + /** + * Visit a FieldBuilder + */ + @throws(classOf[IOException]) + def caseFieldBuilder(field: FieldBuilder) { + if (nomembers) return + // [[int32]] * [= | at ] + print(".field ") + print(FieldAttributes.toString(field.Attributes)) + print(" "); printSignature(field.FieldType) + print(" \'"); print(field.Name); print("\'") + if (field.IsLiteral()) { + print(" = ") + val value = field.getValue() + if (value == null) { + print("nullref") + } else if (value.isInstanceOf[String]) { + print(msilString(value.asInstanceOf[String])) + } else if (value.isInstanceOf[Boolean]) { + print("bool (") + print(if((value.asInstanceOf[Boolean]).booleanValue()) { "true" } else { "false" }) + print(")") + } else if (value.isInstanceOf[Byte]) { + print("int8 (") + print(value) + print(")") + } else if (value.isInstanceOf[java.lang.Short]) { + print("int16 (") + print(value) + print(")") + } else if (value.isInstanceOf[Character]) { + print("char (") + print((value.asInstanceOf[Character]).charValue()) + print(")") + } else if (value.isInstanceOf[Integer]) { + print("int32 (") + print((value.asInstanceOf[Integer]).intValue()) + print(")") + } else if (value.isInstanceOf[Long]) { + print("int64 (") + print((value.asInstanceOf[Long]).longValue()) + print(")") + } else if (value.isInstanceOf[Float]) { + // !!! check if encoding is correct + val bits = java.lang.Float.floatToRawIntBits((value.asInstanceOf[Float]).floatValue()) + // float32(float32(...)) != float32(...) + print("float32 (float32 (") + print(bits) + print("))") + } else if (value.isInstanceOf[Double]) { + // !!! check if encoding is correct + var bits = java.lang.Double.doubleToRawLongBits((value.asInstanceOf[Double]).doubleValue()) + // float64(float64(...)) != float64(...) + print("float64 (float64 (") + print(bits) + print("))") + } else { + throw new Error("ILPrinterVisitor: Illegal default value: " + + value.getClass()) + } + } + println() + printAttributes(field) + } + + /** + * Visit a ConstructorBuilder + */ + @throws(classOf[IOException]) + def caseConstructorBuilder(constr: ConstructorBuilder) { + if (nomembers) return + print(".method "); printHeader(constr, VOID) + println(); println("{"); indent() + printAttributes(constr) + try { + print(constr.GetILGenerator()) + } catch { + case e : RuntimeException => { + System.err.println("In method " + constr) + e.printStackTrace() + } + } + undent(); println("}") + } + + /** + * Visit a MethodBuilder + */ + @throws(classOf[IOException]) + def caseMethodBuilder(method: MethodBuilder) { + if (nomembers) return + print(".method "); printHeader(method, method.ReturnType) + if (method.IsAbstract() + || (method.DeclaringType != null + && method.DeclaringType.IsInterface() + && !method.IsStatic())) + { + println(" {"); indent() + printAttributes(method) + undent(); println("}") + } else { + println(); println("{"); indent() + printAttributes(method) + if (method == entryPoint) + println(".entrypoint") + try { + print(method.GetILGenerator()) + } catch { + case e: RuntimeException => + System.err.println("In method " + method) + e.printStackTrace() + } + undent(); println("}") + } + } + + /** + * Visit a ParameterBuilder + */ + @throws(classOf[IOException]) + def caseParameterBuilder(param: ParameterBuilder) { + print(ParameterAttributes.toString(param.Attributes)) + printSignature(param.ParameterType) + //print(' ') print(marshal) + print(' '); printName(param.Name) + } + + /** + * Visit an ILGenerator + */ + @throws(classOf[IOException]) + def caseILGenerator(code: ILGenerator) { + // print maxstack + println(".maxstack " + code.getMaxStacksize()) + // get the local variables + var locals: Array[LocalBuilder] = code.getLocals() + if (locals.length > 0) { + println(".locals init (") + indent() + for (val i <- 0 until locals.length) { + if (i > 0) println(",") + print(locals(i)) + } // end while + undent() + println(")") + } + // get 3 iterators for the 3 lists + val itL = code.getLabelIterator() + val itO = code.getOpcodeIterator() + val itA = code.getArgumentIterator() + // iterate over each opcode + while (itO.hasNext()) { + // first print label + val label = itL.next().asInstanceOf[Label] + var o = code.lineNums.get(label) + if (o != null) + println(".line " + o) + argument = itA.next().asInstanceOf[Object] + printLabel(label) + val o2 = itO.next() + if (o2 != null) { + print(" ") + print(o2.asInstanceOf[OpCode]) + } + println() + } // end while + } + + /** + * visit an OpCode + */ + @throws(classOf[IOException]) + def caseOpCode(opCode: OpCode) { + var opString = opCode.toString() + print(opString) + pad(12 - opString.length()) + + // switch opcode + if (opCode == OpCode.Ldstr) { + print(msilString(argument.toString())) + } else if(opCode == OpCode.Switch) { + // switch ( ) + print("(") + val targets = argument.asInstanceOf[Array[Label]] + val m = targets.length + for (val i <- 0 until m) { + if (i != 0) print(", ") + print(targets(i)) + } // end for + print(")") + } else if(opCode == OpCode.Call || opCode == OpCode.Callvirt || opCode == OpCode.Jmp || opCode == OpCode.Ldftn || opCode == OpCode.Ldvirtftn) { + // call | callvirt | jmp | ldftn | ldvirtftn + // [ :: ] + printSignature(argument.asInstanceOf[MethodBase]) + } else if (opCode == OpCode.Newobj) { + printSignature(argument.asInstanceOf[ConstructorInfo]) + // ldfld | ldflda | ldsfld | ldsflda | stfld | stsfld + } else if (opCode == OpCode.Ldfld || opCode == OpCode.Ldflda || opCode == OpCode.Ldsfld || opCode == OpCode.Ldsflda || opCode == OpCode.Stfld || opCode == OpCode.Stsfld) { + printSignature(argument.asInstanceOf[FieldInfo]) + } else if (opCode == OpCode.Castclass || opCode == OpCode.Isinst || opCode == OpCode.Ldobj || opCode == OpCode.Newarr) { + printSignature(argument.asInstanceOf[Type]) + } else if (opCode == OpCode.Box || opCode == OpCode.Unbox || opCode == OpCode.Ldtoken) { + printReference(argument.asInstanceOf[Type]) + } else if (opCode == OpCode.Ldloc || opCode == OpCode.Ldloc_S || opCode == OpCode.Ldloca || opCode == OpCode.Ldloca_S || opCode == OpCode.Stloc || opCode == OpCode.Stloc_S) { + val loc = argument.asInstanceOf[LocalBuilder] + print(loc.slot); print("\t// "); printSignature(loc.LocalType) + print(" \'"); print(loc.name); print("\'") + //print("'") print(((LocalBuilder)argument).name) print("'") + } else { + // by default print toString argument if any + if (argument != null) + print(argument) + } // end switch + } + + /** + * Visit a Label + */ + def printLabel(label: Label) { + val kind = label.getKind() + if (kind == Label.Kind.Normal) { + print(label+ ": ") + } else if (kind == Label.Kind.NewScope) { + print("{"); indent() + } else if (kind == Label.Kind.EndScope) { + undent(); print("}") + } else if (kind == Label.Kind.Try) { + print(".try {"); indent() + } else if (kind == Label.Kind.Catch) { + undent() + println("}") + print("catch ") + printReference(argument.asInstanceOf[Type]) + print(" {") + indent() + } else if (kind == Label.Kind.Filter) { + undent() + println("}") + print("filter {") + indent() + } else if (kind == Label.Kind.EndFilter) { + print("endfilter") + undent() + println("}") + } else if (kind == Label.Kind.Finally) { + undent() + println("}") + print("finally {") + indent() + } else if (kind == Label.Kind.EndTry) { + undent() + print("}") + } + } + + /** + * Visit a LocalBuilder + */ + @throws(classOf[IOException]) + def caseLocalBuilder(localBuilder: LocalBuilder) { + // print type + printSignature(localBuilder.LocalType) + // space + print(" \'") + // print name + print(localBuilder.name) + print("\'") + } + + + //########################################################################## + + def printAssemblySignature(assem: Assembly, extern: boolean) { + print(".assembly ") + if (extern) + print("extern ") + val an = assem.GetName() + printName(an.Name); println() + println("{") + if (!extern) + printAttributes(assem) + val v = an.Version + if (v != null) { + print(" .ver "); print(v.Major); print(':'); print(v.Minor) + print(':'); print(v.Build); print(':') + print(v.Revision); println() + } + var key = an.GetPublicKeyToken() + if (key != null) { + print(" .publickeytoken = ("); print(PEFile.bytes2hex(key)) + println(")") + } else { + key = an.GetPublicKey() + if (key != null) { + print(" .publickey = ("); print(PEFile.bytes2hex(key)) + println(")") + } + } + println("}") + } + + + def printSignature(field: FieldInfo) { + printSignature(field.FieldType) + //print(' ') print(owner) + print(' ') + //if (field.IsStatic && field.DeclaringType != currentType) { + printReference(field.DeclaringType) + print("::") + //} + printName(field.Name) + } + + // print method head + @throws(classOf[IOException]) + def printHeader(method: MethodBase, returnType: Type) { + print(MethodAttributes.toString(method.Attributes)) + print(' '); print(CallingConventions.toString(method.CallingConvention)) + print(' '); printSignature(returnType) + //print(' ') print(marshal) + print(' '); printName(method.Name) + val params = method.GetParameters() + print('(') + for (val i <- 0 until params.length) { + if (i > 0) print(", ") + print(params(i).asInstanceOf[ParameterBuilder]) + } + print(") ") + + print(MethodImplAttributes + .toString(method.GetMethodImplementationFlags())) + } + + + def printSignature(method: MethodBase) { + var returnType: Type = null + if (method.isInstanceOf[MethodInfo]) + returnType = (method.asInstanceOf[MethodInfo]).ReturnType + else if (method.isInstanceOf[ConstructorInfo]) + returnType = VOID + else + throw new RuntimeException() + + val s = CallingConventions.toString(method.CallingConvention) + print(s) + if (s.length() > 0) print(' ') + printSignature(returnType) + //print(' ') print(owner) + print(' '); printReference(method.DeclaringType) + print("::"); printName(method.Name) + + var params = method.GetParameters() + print("(") + for (val i <- 0 until params.length) { + if (i > 0) print(", ") + printSignature(params(i).ParameterType) + } + print(")") + } + + def printSignature(`type`: Type) { + val sig : Object = primitive.get(`type`) + if (sig != null) { + print(sig) + return + } + + if (`type`.HasElementType()) { + printSignature(`type`.GetElementType()) + if (`type`.IsArray()) + print("[]") + else if (`type`.IsPointer()) + print('*') + else if (`type`.IsByRef()) + print('&') + } else { + print(if(`type`.IsValueType()) "valuetype " else "class ") + printReference(`type`) + } + } + + def printReference(`type`: Type) { + if (`type`.Assembly() != currentModule.Assembly) { + print('['); print(`type`.Assembly().GetName().Name); print("]") + } else if (`type`.Module != currentModule) { + print("[.module "); print(`type`.Module.Name); print("]") + } + printTypeName(`type`) + } + + def printTypeName(`type`: Type) { + if (`type`.DeclaringType != null) { + printTypeName(`type`.DeclaringType) + print('/') + printName(`type`.Name) + } else { + printName(`type`.FullName) + } + } + + def printAttributes(icap: ICustomAttributeProvider) { + var attrs = icap.GetCustomAttributes(false) + for (val i <- 0 until attrs.length) { + print(".custom ") + printSignature((attrs(i).asInstanceOf[Attribute]).getConstructor()) + print(" = (") + print(PEFile.bytes2hex((attrs(i).asInstanceOf[Attribute]).getValue())) + println(")") + } + } + + //########################################################################## + +} // class ILPrinterVisitor + +object ILPrinterVisitor { + final val VOID: Type = Type.GetType("System.Void") + protected final val TAB = 4 + + protected final val SPACES = " " + protected final val SPACES_LEN = SPACES.length() + + def hasControlChars(str: String): Boolean = { + for(val i <- 0 until str.length()) { + var ch = str.charAt(i) + ch match { + case '\b' => + case '\t' => + case '\n' => + case '\f' => + case '\r' => + case _ => if(Character.isISOControl(ch)) return true + } + } + return false + } + + final val EMPTY: String = "" + def msilString(s: String): String = { + if (hasControlChars(s)) { + try { + return "bytearray (" + PEFile.bytes2hex(s.getBytes("UTF-16LE")) + ")" + } catch { + case e : java.io.UnsupportedEncodingException => throw new RuntimeException(e) + } + } + var str = new StringBuffer(s) + var ss = EMPTY + var i = 0 + while(i < str.length()) { + ss = EMPTY + val c = str.charAt(i) + c match { + case '\b' => ss = "\\b" + case '\t' => ss = "\\t" + case '\n' => ss = "\\n" + case '\f' => ss = "\\f" + case '\r' => ss = "\\r" + case '\"' => ss = "\\\"" + case '\'' => ss = "\\\'" + case '\\' => ss = "\\\\" + case _ => if (Character.isISOControl(c)) + ss = "\\u" + PEFile.int2hex(Character.getNumericValue(c)) + } + if (ss != EMPTY) { + str.replace(i, i + 1, ss) + i = i + ss.length() - 1 + } + i = i + 1 + } + return "\"" + str.toString() + "\"" + } + + /** + * the main printer method + */ + @throws(classOf[IOException]) + def printAssembly(assemblyBuilder: AssemblyBuilder, fileName: String) { + assemblyBuilder.apply(new SingleFileILPrinterVisitor(fileName)) + } + + @throws(classOf[IOException]) + def printAssembly(assemblyBuilder: AssemblyBuilder, destPath: String, sourceFilesPath: String) { + assemblyBuilder.apply(new MultipleFilesILPrinterVisitor(destPath, sourceFilesPath)) + } + + /** The current assembly */ + var currAssembly: Assembly = _ + + final var primitive = new HashMap[Type, String]() + def addPrimitive(name: String, sig: String) { + var `type` = + Type.GetType(name) + assert(`type` != null, "Cannot lookup primitive type " + `type`) + primitive.put(`type`, sig) + } + + addPrimitive("System.Object", "object") + addPrimitive("System.String", "string") + addPrimitive("System.Void", "void") + addPrimitive("System.Boolean", "bool") + addPrimitive("System.Char", "char") + addPrimitive("System.SByte", "int8") + addPrimitive("System.Byte", "unsigned int8") + addPrimitive("System.Int16", "int16") + addPrimitive("System.UInt16", "unsigned int16") + addPrimitive("System.Int32", "int32") + addPrimitive("System.UInt32", "unsigned int32") + addPrimitive("System.Int64", "int64") + addPrimitive("System.UInt64", "unsigned int64") + addPrimitive("System.IntPtr", "native int") + addPrimitive("System.UIntPtr", "unsigned native int") + addPrimitive("System.Single", "float32") + addPrimitive("System.Double", "float64") + addPrimitive("System.TypedReference", "typedref") +} diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/Label.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/Label.scala new file mode 100644 index 0000000000..e6ec60576f --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/Label.scala @@ -0,0 +1,149 @@ +/* + * System.Reflection.Emit-like API for writing .NET assemblies to MSIL + */ + +// $Id: Label.java 8550 2006-08-31 16:15:26Z mihaylov $ + +package ch.epfl.lamp.compiler.msil.emit + +import ch.epfl.lamp.compiler.msil.Type + +/** + * Represents a label in the instruction stream. Label is used in conjunction + * with the ILGenerator class. + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +abstract class Label protected { + import Label._ + def isInitialized(): Boolean + def getKind(): Kind + def getAddress(): Int + def getStacksize(): Int + def setStacksize(stacksize: Int): Unit + def incStacksize(): Unit + def mergeWith(that: Label): Unit +} + +object Label { + final val DUMMY: Int = -((1<<31)-1) + + //########################################################################## + + final class NormalLabel(_address: Int, _stacksize: Int) extends Label { + + //########################################################################## + // protected constructors + + //the position of the label + private var address: Int = _address + + //the stacksize at the label + private var stacksize: Int = _stacksize + + def this() { + this(-1, DUMMY) + } + + def this(that: NormalLabel) { + this(that.getAddress(), that.getStacksize()) + } + + //########################################################################## + // instrumental methods only used by ILGenerator + + def isInitialized() = (getAddress() != -1) || (stacksize != DUMMY) + + def getAddress() = address + + def getStacksize() = stacksize + + def setStacksize(stacksize: Int) { + assert(stacksize >= 0) + this.stacksize = stacksize + } + + def incStacksize() { + stacksize = stacksize + 1 + } + + def getKind(): Kind = Kind.Normal + + def mergeWith(that: Label) { + //assert address < 0 : "this.address = " + address + " that.address = " + that.address + address = that.getAddress() + + // assert stacksize == that.stacksize + // : "this.stacksize = " + stacksize + " that.stacksize = " + // + that.stacksize + // stacksize = that.stacksize + val ss: Int = Math.max(stacksize, that.getStacksize()) + stacksize = ss + that.setStacksize(ss) + } + + //########################################################################## + // + + /** + * the toString Method return the label name + * it's "IL" + address + */ + override def toString(): String = { + var pad: String = "" + if (address < 16) pad = "000" + else if (address < 256) pad = "00" + else if (address < 4096) pad = "0" + return "IL_" + pad + Integer.toHexString(address) + } + + def getString(): String = { + val name = super.toString() + val i: Int = name.lastIndexOf('.') + return name.substring(i+1, name.length()) + } + } + + //######################################################################## + // Special Labels + + final class SpecialLabel(_kind: Label.Kind) extends Label { + private final var kind: Label.Kind = _kind + def isInitialized() = true + def getAddress(): Int = { throw new RuntimeException("" + kind.toString()) } + def getStacksize(): Int = { throw new RuntimeException("" + kind.toString()) } + def setStacksize(stacksize: Int) { throw new RuntimeException(kind.toString()) } + def incStacksize() { throw new RuntimeException(kind.toString()) } + def getKind(): Kind = kind + def mergeWith(that: Label) { throw new RuntimeException(kind.toString()) } + override def toString(): String = "Label(" + kind.toString() + ")" + } + + final val NewScope: Label = new SpecialLabel(Kind.NewScope) + final val EndScope: Label = new SpecialLabel(Kind.EndScope) + final val Try: Label = new SpecialLabel(Kind.Try) + final val Catch: Label = new SpecialLabel(Kind.Catch) + final val Filter: Label = new SpecialLabel(Kind.Filter) + final val EndFilter: Label = new SpecialLabel(Kind.EndFilter) + final val Finally: Label = new SpecialLabel(Kind.Finally) + final val EndTry: Label = new SpecialLabel(Kind.EndTry) + + final class Kind() {} + + final object Kind { + final val Normal: Kind = new Kind() + + final val NewScope: Kind = new Kind() + final val EndScope: Kind = new Kind() + + final val Try: Kind = new Kind() + final val Catch: Kind = new Kind() + final val Filter: Kind = new Kind() + final val EndFilter: Kind = new Kind() + final val Finally: Kind = new Kind() + final val EndTry: Kind = new Kind() + } + + //########################################################################## +} diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/LocalBuilder.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/LocalBuilder.scala new file mode 100644 index 0000000000..aabea9ba4e --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/LocalBuilder.scala @@ -0,0 +1,45 @@ +/** + * System.Reflection.Emit-like API for writing .NET assemblies to MSIL + */ + +// $Id: LocalBuilder.java 168 2005-12-12 14:20:06Z mihaylov $ + +package ch.epfl.lamp.compiler.msil.emit + +import ch.epfl.lamp.compiler.msil.Type + +/** + * Represents a local variable within a method or constructor. + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +class LocalBuilder(_slot : Int, localType : Type) extends Visitable { + + /** + * the type of the local variable. + */ + var LocalType : Type = localType + + // the name of the local variable + var name : String = "L_" + slot + + // the slot occupied by this local in the corresponding ILGenerator + var slot : Int = _slot + + /** + * Sets the name of this local variable. + */ + def SetLocalSymInfo(name : String) { + this.name = name + } + + override def toString() : String = name + + /** + * the apply method for a visitor + */ + def apply(v : Visitor) { + v.caseLocalBuilder(this) + } +} diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/MethodBuilder.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/MethodBuilder.scala new file mode 100644 index 0000000000..da5da79d53 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/MethodBuilder.scala @@ -0,0 +1,71 @@ +/* + * System.Reflection.Emit-like API for writing .NET assemblies to MSIL + */ + +// $Id: MethodBuilder.java 14655 2008-04-15 09:37:02Z lorch $ + +package ch.epfl.lamp.compiler.msil.emit + +import ch.epfl.lamp.compiler.msil.MethodInfo +import ch.epfl.lamp.compiler.msil.ParameterInfo +import ch.epfl.lamp.compiler.msil.Type +import ch.epfl.lamp.compiler.msil.ConstructorInfo +import java.io.IOException + +/** + * Defines and represents a method of a dynamic class. + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +class MethodBuilder(name: String, declType: Type, attrs: Int, returnType: Type, paramTypes: Array[Type]) + extends MethodInfo(name, declType, attrs, returnType, paramTypes) + with ICustomAttributeSetter + with Visitable +{ + + //########################################################################## + // public interface + + /** Defines a parameter of this method. TODO: Parameters are indexed staring + * from number 1 for the first parameter + */ + def DefineParameter(pos: Int, attr: Int, name: String): ParameterBuilder = { + val param = new ParameterBuilder(name, params(pos).ParameterType, attr, pos) + params(pos) = param + return param + } + + /** Returns an ILGenerator for this method. */ + def GetILGenerator(): ILGenerator = { + if (ilGenerator == null) + throw new RuntimeException + ("No code generator avaiable for this method: " + this) + return ilGenerator + } + + /** Sets a custom attribute. */ + def SetCustomAttribute(constr: ConstructorInfo, value: Array[byte]) { + addCustomAttribute(constr, value) + } + + //########################################################################## + + /** The apply method for a visitor. */ + @throws(classOf[IOException]) + def apply(v: Visitor) { + v.caseMethodBuilder(this) + } + + //########################################################################## + + // the Intermediate Language Generator + // it contains the method's body + protected final val ilGenerator : ILGenerator = + if (DeclaringType == null // global method + || !DeclaringType.IsInterface()) + new ILGenerator(this) + else null + + //########################################################################## +} diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/ModuleBuilder.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/ModuleBuilder.scala new file mode 100644 index 0000000000..211a965d69 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/ModuleBuilder.scala @@ -0,0 +1,134 @@ +/* + * System.Reflection.Emit-like API for writing .NET assemblies to MSIL + */ + +// $Id: ModuleBuilder.java 14655 2008-04-15 09:37:02Z lorch $ + +package ch.epfl.lamp.compiler.msil.emit + +import ch.epfl.lamp.compiler.msil._ +import java.util.HashMap +import java.util.ArrayList +import java.io.IOException + +/** + * Defines and represents a module. Get an instance of ModuleBuilder + * by calling DefineDynamicModule + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +class ModuleBuilder(name: String, fullname: String, scopeName: String, assembly: Assembly) + extends Module(name, fullname, scopeName, assembly) + with ICustomAttributeSetter + with Visitable +{ + + //########################################################################## + // public interface + + /** + * Complete the global function definitions for this dynamic module. + * This method should be called when the user is done with defining + * all of the global functions within this dynamic module. After calling + * this function, no more new global functions or new global data are + * allowed. + */ + def CreateGlobalFunctions() { + if (globalsCreated) + throw new RuntimeException("Global functions are already created") + this.fields = fieldBuilders.toArray(fields).asInstanceOf[Array[FieldInfo]] + this.methods = methodBuilders.toArray(methods).asInstanceOf[Array[MethodInfo]] + globalsCreated = true + } + + /** + * Constructs a TypeBuilder for a type with the specified name + */ + def DefineType(typeName: String): TypeBuilder = { + return DefineType(typeName, 0, null, Type.EmptyTypes) + } + + /** + * Constructs a TypeBuilder for a type with the specified name + * and specified attributes + */ + def DefineType(typeName: String, attributes: Int): TypeBuilder = { + return DefineType(typeName, attributes, null, Type.EmptyTypes) + } + + /** + * Constructs a TypeBuilder given type name, its attributes, + * and the type that the defined type extends. + */ + def DefineType(typeName: String, attributes: Int, + baseType: Type): TypeBuilder = { + return DefineType(typeName, attributes, baseType, Type.EmptyTypes) + } + + /** + * Constructs a TypeBuilder given the Full specification of a type, + * Given the type name, attributes, the type that the defined type + * extends, and the interfaces that the defined type implements. + */ + def DefineType(typeName: String, + attributes: Int, + baseType: Type, + interfaces: Array[Type]): TypeBuilder = + { + var t: Type = GetType(typeName) // Module.GetType(String) + if (t != null) + throw new RuntimeException + ("Type [" + Assembly + "]" + typeName + "' already exists!") + val `type` = + new TypeBuilder(this, attributes, typeName, baseType, interfaces, null) + addType(`type`) + return `type` + } + + /** + * Defines a global method given its name, attributes, return type, and + * parameter types. + */ + def DefineGlobalMethod(name: String, attributes: Int, + returnType: Type, paramTypes: Array[Type]): MethodBuilder = + { + val method = + new MethodBuilder(name, null, attributes, returnType, paramTypes) + methodBuilders.add(method) + return method + } + + + override def GetTypes(): Array[Type] = { + return typesMap.values().toArray(Type.EmptyTypes).asInstanceOf[Array[Type]] + } + + /** Sets a custom attribute. */ + def SetCustomAttribute(constr: ConstructorInfo, value: Array[byte]) { + addCustomAttribute(constr, value) + } + + //########################################################################## + // internal members + + var globalsCreated = false + protected var fieldBuilders = new ArrayList[FieldInfo]() + protected var methodBuilders = new ArrayList[MethodInfo]() + + override def addType(t: Type): Type = { + return super.addType(t) + } + + //########################################################################## + + /** + * the apply method for a visitor + */ + @throws(classOf[IOException]) + def apply(v: Visitor) { + v.caseModuleBuilder(this) + } + + //########################################################################## +} diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/MultipleFilesILPrinterVisitor.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/MultipleFilesILPrinterVisitor.scala new file mode 100644 index 0000000000..63028f1f90 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/MultipleFilesILPrinterVisitor.scala @@ -0,0 +1,139 @@ +/* + * System.Reflection.Emit-like API for writing .NET assemblies in MSIL + */ + +// $Id: ILPrinterVisitor.java 8664 2006-09-12 16:48:03Z mihaylov $ + +package ch.epfl.lamp.compiler.msil.emit + +import java.io.File +import java.io.FileWriter +import java.io.BufferedWriter +import java.io.PrintWriter +import java.io.IOException +import java.util.Iterator +import java.util.HashMap +import java.util.Arrays + +import ch.epfl.lamp.compiler.msil._ +import ch.epfl.lamp.compiler.msil.emit +import ch.epfl.lamp.compiler.msil.util.Table + +/** + * The MSIL printer Vistor. It prints a complete + * assembly into seperate files. Then these files can be compiled by ilasm. + * + * @author Nikolay Mihaylov + * @author Daniel Lorch + * @version 1.0 + */ +final class MultipleFilesILPrinterVisitor(destPath: String, sourceFilesPath: String) extends ILPrinterVisitor { + /** + * Visit an AssemblyBuilder + */ + @throws(classOf[IOException]) + def caseAssemblyBuilder(assemblyBuilder: AssemblyBuilder) { + ILPrinterVisitor.currAssembly = assemblyBuilder + + // first get the entryPoint + this.entryPoint = assemblyBuilder.EntryPoint + + // all external assemblies + as = assemblyBuilder.getExternAssemblies() + Arrays.sort(as, assemblyNameComparator) + + // print each module + var m: Array[Module] = assemblyBuilder.GetModules() + nomembers = true + for(val i <- 0 until m.length) { + print(m(i).asInstanceOf[ModuleBuilder]) + } + + nomembers = false + for(val i <- 0 until m.length) { + print(m(i).asInstanceOf[ModuleBuilder]) + } + ILPrinterVisitor.currAssembly = null + } + + /** + * Visit a ModuleBuilder + */ + @throws(classOf[IOException]) + def caseModuleBuilder(module: ModuleBuilder) { + val assemblyBuilder = ILPrinterVisitor.currAssembly.asInstanceOf[AssemblyBuilder] + + // print module declaration + currentModule = module + + // global methods typically contain the main method + if (!module.globalsCreated) + module.CreateGlobalFunctions() + + var m: Array[MethodInfo] = module.GetMethods() + + // "Types" contain all the classes + var t: Array[Type] = module.GetTypes() + for(val i <- 0 until t.length) { + val tBuilder = t(i).asInstanceOf[TypeBuilder] + val sourceFilename = tBuilder.sourceFilename + val sourceFilepath = new File(tBuilder.sourceFilepath).getCanonicalPath + val sourcePath = new File(sourceFilesPath).getCanonicalPath + var append = false + + if(!sourceFilepath.startsWith(sourcePath)) { + throw new IOException("Source file " + sourceFilename + " must lie inside sourcepath " + sourcePath) + } + + assert(sourceFilepath.endsWith(".scala"), "Source file doesn't end with .scala") + val relativeFilename = sourceFilepath.substring(sourcePath.length, sourceFilepath.length() - 6) + ".msil" + val fileName = new File(destPath, relativeFilename) + if(assemblyBuilder.generatedFiles.contains(fileName.getPath)) { + append = true + } else { + fileName.getParentFile().mkdirs() + assemblyBuilder.generatedFiles.add(fileName.getPath) + } + + out = new PrintWriter(new BufferedWriter(new FileWriter(fileName, append))) + // only write assembly boilerplate and class prototypes + if (!append && nomembers) { + printAssemblyBoilerplate() + + print(".module \'"); print(module.Name); println("\'") + printAttributes(module) + } + + print(t(i).asInstanceOf[TypeBuilder]) + out.close() + } + + // now write the global methods (typically contains the "main" method) + if(!nomembers) { + var globalMethods: File = new File(destPath, ILPrinterVisitor.currAssembly.GetName().Name + ".msil") + val append = assemblyBuilder.generatedFiles.contains(globalMethods.getPath) + + out = new PrintWriter(new BufferedWriter(new FileWriter(globalMethods, append))) + + // make sure we're the first in the list (ilasm uses the first file name to guess the output file name) + assemblyBuilder.generatedFiles.add(0, globalMethods.getPath) + + // if this file hasn't been created by one of the classes, write boilerplate + if(!append) { + printAssemblyBoilerplate() + + print(".module \'"); print(module.Name); println("\'") + printAttributes(module) + } + + for(val i <- 0 until m.length) { + print(m(i).asInstanceOf[MethodBuilder]) + } + + out.close() + } + + currentModule = null + } + +} // class MultipleFilesILPrinterVisitor diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/OpCode.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/OpCode.scala new file mode 100644 index 0000000000..c6ff59ba66 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/OpCode.scala @@ -0,0 +1,1935 @@ +/* + * System.Reflection.Emit-like API for writing .NET assemblies to MSIL + */ + +// $Id: OpCode.java 14655 2008-04-15 09:37:02Z lorch $ + +package ch.epfl.lamp.compiler.msil.emit + +import java.io.IOException + +/** Describes a Microsoft intermediate language (MSIL) instruction. + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +class OpCode extends Visitable { + import OpCode._ + + /** The Operation Code of Microsoft intermediate language (MSIL) instruction. */ + var CEE_opcode : Int = _ + + /** The name of the Microsoft intermediate language (MSIL) instruction. */ + var CEE_string: String = _ + + /** The type of Microsoft intermediate language (MSIL) instruction. */ + var CEE_code: short = _ + + /** How the Microsoft intermediate language (MSIL) instruction pops the stack. */ + var CEE_pop: byte = _ + + /** How the Microsoft intermediate language (MSIL) instruction pushes operand onto the stack. */ + var CEE_push: byte = _ + + /** Describes the type of flow control. */ + var CEE_flow: byte = _ + + /** ????? */ + var CEE_inline: byte = _ + + var CEE_length: byte = _ + + var CEE_popush: byte = _ + + /** + * the apply method for a visitor + */ + @throws(classOf[IOException]) + def apply(v: Visitor) { + v.caseOpCode(this) + } + + protected def length(): byte = { + val code = OpCode.length(CEE_code) + val inline = OpCode.INLINE_length(CEE_inline) + return if(inline < 0) { -1 } else { (code + inline).asInstanceOf[byte] } + } + + protected def popush(): byte = { + val pop = OpCode.POP_size(CEE_pop) + val push = OpCode.PUSH_size(CEE_push) + return if(pop < 0 || push < 0) { OpCode.POPUSH_SPECIAL } else { (push - pop).asInstanceOf[byte] } + } + + override def toString(): String = { + return CEE_string + } +} + +object OpCode { + + //######################################################################## + // Common Execution Environment opcodes + + final val CEE_NOP : Int = 0x0000 + final val CEE_BREAK : Int = 0x0001 + final val CEE_LDARG_0 : Int = 0x0002 + final val CEE_LDARG_1 : Int = 0x0003 + final val CEE_LDARG_2 : Int = 0x0004 + final val CEE_LDARG_3 : Int = 0x0005 + final val CEE_LDLOC_0 : Int = 0x0006 + final val CEE_LDLOC_1 : Int = 0x0007 + final val CEE_LDLOC_2 : Int = 0x0008 + final val CEE_LDLOC_3 : Int = 0x0009 + final val CEE_STLOC_0 : Int = 0x000A + final val CEE_STLOC_1 : Int = 0x000B + final val CEE_STLOC_2 : Int = 0x000C + final val CEE_STLOC_3 : Int = 0x000D + final val CEE_LDARG_S : Int = 0x000E + final val CEE_LDARGA_S : Int = 0x000F + final val CEE_STARG_S : Int = 0x0010 + final val CEE_LDLOC_S : Int = 0x0011 + final val CEE_LDLOCA_S : Int = 0x0012 + final val CEE_STLOC_S : Int = 0x0013 + final val CEE_LDNULL : Int = 0x0014 + final val CEE_LDC_I4_M1 : Int = 0x0015 + final val CEE_LDC_I4_0 : Int = 0x0016 + final val CEE_LDC_I4_1 : Int = 0x0017 + final val CEE_LDC_I4_2 : Int = 0x0018 + final val CEE_LDC_I4_3 : Int = 0x0019 + final val CEE_LDC_I4_4 : Int = 0x001A + final val CEE_LDC_I4_5 : Int = 0x001B + final val CEE_LDC_I4_6 : Int = 0x001C + final val CEE_LDC_I4_7 : Int = 0x001D + final val CEE_LDC_I4_8 : Int = 0x001E + final val CEE_LDC_I4_S : Int = 0x001F + final val CEE_LDC_I4 : Int = 0x0020 + final val CEE_LDC_I8 : Int = 0x0021 + final val CEE_LDC_R4 : Int = 0x0022 + final val CEE_LDC_R8 : Int = 0x0023 + final val CEE_UNUSED49 : Int = 0x0024 + final val CEE_DUP : Int = 0x0025 + final val CEE_POP : Int = 0x0026 + final val CEE_JMP : Int = 0x0027 + final val CEE_CALL : Int = 0x0028 + final val CEE_CALLI : Int = 0x0029 + final val CEE_RET : Int = 0x002A + final val CEE_BR_S : Int = 0x002B + final val CEE_BRFALSE_S : Int = 0x002C + final val CEE_BRTRUE_S : Int = 0x002D + final val CEE_BEQ_S : Int = 0x002E + final val CEE_BGE_S : Int = 0x002F + final val CEE_BGT_S : Int = 0x0030 + final val CEE_BLE_S : Int = 0x0031 + final val CEE_BLT_S : Int = 0x0032 + final val CEE_BNE_UN_S : Int = 0x0033 + final val CEE_BGE_UN_S : Int = 0x0034 + final val CEE_BGT_UN_S : Int = 0x0035 + final val CEE_BLE_UN_S : Int = 0x0036 + final val CEE_BLT_UN_S : Int = 0x0037 + final val CEE_BR : Int = 0x0038 + final val CEE_BRFALSE : Int = 0x0039 + final val CEE_BRTRUE : Int = 0x003A + final val CEE_BEQ : Int = 0x003B + final val CEE_BGE : Int = 0x003C + final val CEE_BGT : Int = 0x003D + final val CEE_BLE : Int = 0x003E + final val CEE_BLT : Int = 0x003F + final val CEE_BNE_UN : Int = 0x0040 + final val CEE_BGE_UN : Int = 0x0041 + final val CEE_BGT_UN : Int = 0x0042 + final val CEE_BLE_UN : Int = 0x0043 + final val CEE_BLT_UN : Int = 0x0044 + final val CEE_SWITCH : Int = 0x0045 + final val CEE_LDIND_I1 : Int = 0x0046 + final val CEE_LDIND_U1 : Int = 0x0047 + final val CEE_LDIND_I2 : Int = 0x0048 + final val CEE_LDIND_U2 : Int = 0x0049 + final val CEE_LDIND_I4 : Int = 0x004A + final val CEE_LDIND_U4 : Int = 0x004B + final val CEE_LDIND_I8 : Int = 0x004C + final val CEE_LDIND_I : Int = 0x004D + final val CEE_LDIND_R4 : Int = 0x004E + final val CEE_LDIND_R8 : Int = 0x004F + final val CEE_LDIND_REF : Int = 0x0050 + final val CEE_STIND_REF : Int = 0x0051 + final val CEE_STIND_I1 : Int = 0x0052 + final val CEE_STIND_I2 : Int = 0x0053 + final val CEE_STIND_I4 : Int = 0x0054 + final val CEE_STIND_I8 : Int = 0x0055 + final val CEE_STIND_R4 : Int = 0x0056 + final val CEE_STIND_R8 : Int = 0x0057 + final val CEE_ADD : Int = 0x0058 + final val CEE_SUB : Int = 0x0059 + final val CEE_MUL : Int = 0x005A + final val CEE_DIV : Int = 0x005B + final val CEE_DIV_UN : Int = 0x005C + final val CEE_REM : Int = 0x005D + final val CEE_REM_UN : Int = 0x005E + final val CEE_AND : Int = 0x005F + final val CEE_OR : Int = 0x0060 + final val CEE_XOR : Int = 0x0061 + final val CEE_SHL : Int = 0x0062 + final val CEE_SHR : Int = 0x0063 + final val CEE_SHR_UN : Int = 0x0064 + final val CEE_NEG : Int = 0x0065 + final val CEE_NOT : Int = 0x0066 + final val CEE_CONV_I1 : Int = 0x0067 + final val CEE_CONV_I2 : Int = 0x0068 + final val CEE_CONV_I4 : Int = 0x0069 + final val CEE_CONV_I8 : Int = 0x006A + final val CEE_CONV_R4 : Int = 0x006B + final val CEE_CONV_R8 : Int = 0x006C + final val CEE_CONV_U4 : Int = 0x006D + final val CEE_CONV_U8 : Int = 0x006E + final val CEE_CALLVIRT : Int = 0x006F + final val CEE_CPOBJ : Int = 0x0070 + final val CEE_LDOBJ : Int = 0x0071 + final val CEE_LDSTR : Int = 0x0072 + final val CEE_NEWOBJ : Int = 0x0073 + final val CEE_CASTCLASS : Int = 0x0074 + final val CEE_ISINST : Int = 0x0075 + final val CEE_CONV_R_UN : Int = 0x0076 + final val CEE_UNUSED58 : Int = 0x0077 + final val CEE_UNUSED1 : Int = 0x0078 + final val CEE_UNBOX : Int = 0x0079 + final val CEE_THROW : Int = 0x007A + final val CEE_LDFLD : Int = 0x007B + final val CEE_LDFLDA : Int = 0x007C + final val CEE_STFLD : Int = 0x007D + final val CEE_LDSFLD : Int = 0x007E + final val CEE_LDSFLDA : Int = 0x007F + final val CEE_STSFLD : Int = 0x0080 + final val CEE_STOBJ : Int = 0x0081 + final val CEE_CONV_OVF_I1_UN : Int = 0x0082 + final val CEE_CONV_OVF_I2_UN : Int = 0x0083 + final val CEE_CONV_OVF_I4_UN : Int = 0x0084 + final val CEE_CONV_OVF_I8_UN : Int = 0x0085 + final val CEE_CONV_OVF_U1_UN : Int = 0x0086 + final val CEE_CONV_OVF_U2_UN : Int = 0x0087 + final val CEE_CONV_OVF_U4_UN : Int = 0x0088 + final val CEE_CONV_OVF_U8_UN : Int = 0x0089 + final val CEE_CONV_OVF_I_UN : Int = 0x008A + final val CEE_CONV_OVF_U_UN : Int = 0x008B + final val CEE_BOX : Int = 0x008C + final val CEE_NEWARR : Int = 0x008D + final val CEE_LDLEN : Int = 0x008E + final val CEE_LDELEMA : Int = 0x008F + final val CEE_LDELEM_I1 : Int = 0x0090 + final val CEE_LDELEM_U1 : Int = 0x0091 + final val CEE_LDELEM_I2 : Int = 0x0092 + final val CEE_LDELEM_U2 : Int = 0x0093 + final val CEE_LDELEM_I4 : Int = 0x0094 + final val CEE_LDELEM_U4 : Int = 0x0095 + final val CEE_LDELEM_I8 : Int = 0x0096 + final val CEE_LDELEM_I : Int = 0x0097 + final val CEE_LDELEM_R4 : Int = 0x0098 + final val CEE_LDELEM_R8 : Int = 0x0099 + final val CEE_LDELEM_REF : Int = 0x009A + final val CEE_STELEM_I : Int = 0x009B + final val CEE_STELEM_I1 : Int = 0x009C + final val CEE_STELEM_I2 : Int = 0x009D + final val CEE_STELEM_I4 : Int = 0x009E + final val CEE_STELEM_I8 : Int = 0x009F + final val CEE_STELEM_R4 : Int = 0x00A0 + final val CEE_STELEM_R8 : Int = 0x00A1 + final val CEE_STELEM_REF : Int = 0x00A2 + final val CEE_UNUSED2 : Int = 0x00A3 + final val CEE_UNUSED3 : Int = 0x00A4 + final val CEE_UNUSED4 : Int = 0x00A5 + final val CEE_UNUSED5 : Int = 0x00A6 + final val CEE_UNUSED6 : Int = 0x00A7 + final val CEE_UNUSED7 : Int = 0x00A8 + final val CEE_UNUSED8 : Int = 0x00A9 + final val CEE_UNUSED9 : Int = 0x00AA + final val CEE_UNUSED10 : Int = 0x00AB + final val CEE_UNUSED11 : Int = 0x00AC + final val CEE_UNUSED12 : Int = 0x00AD + final val CEE_UNUSED13 : Int = 0x00AE + final val CEE_UNUSED14 : Int = 0x00AF + final val CEE_UNUSED15 : Int = 0x00B0 + final val CEE_UNUSED16 : Int = 0x00B1 + final val CEE_UNUSED17 : Int = 0x00B2 + final val CEE_CONV_OVF_I1 : Int = 0x00B3 + final val CEE_CONV_OVF_U1 : Int = 0x00B4 + final val CEE_CONV_OVF_I2 : Int = 0x00B5 + final val CEE_CONV_OVF_U2 : Int = 0x00B6 + final val CEE_CONV_OVF_I4 : Int = 0x00B7 + final val CEE_CONV_OVF_U4 : Int = 0x00B8 + final val CEE_CONV_OVF_I8 : Int = 0x00B9 + final val CEE_CONV_OVF_U8 : Int = 0x00BA + final val CEE_UNUSED50 : Int = 0x00BB + final val CEE_UNUSED18 : Int = 0x00BC + final val CEE_UNUSED19 : Int = 0x00BD + final val CEE_UNUSED20 : Int = 0x00BE + final val CEE_UNUSED21 : Int = 0x00BF + final val CEE_UNUSED22 : Int = 0x00C0 + final val CEE_UNUSED23 : Int = 0x00C1 + final val CEE_REFANYVAL : Int = 0x00C2 + final val CEE_CKFINITE : Int = 0x00C3 + final val CEE_UNUSED24 : Int = 0x00C4 + final val CEE_UNUSED25 : Int = 0x00C5 + final val CEE_MKREFANY : Int = 0x00C6 + final val CEE_UNUSED59 : Int = 0x00C7 + final val CEE_UNUSED60 : Int = 0x00C8 + final val CEE_UNUSED61 : Int = 0x00C9 + final val CEE_UNUSED62 : Int = 0x00CA + final val CEE_UNUSED63 : Int = 0x00CB + final val CEE_UNUSED64 : Int = 0x00CC + final val CEE_UNUSED65 : Int = 0x00CD + final val CEE_UNUSED66 : Int = 0x00CE + final val CEE_UNUSED67 : Int = 0x00CF + final val CEE_LDTOKEN : Int = 0x00D0 + final val CEE_CONV_U2 : Int = 0x00D1 + final val CEE_CONV_U1 : Int = 0x00D2 + final val CEE_CONV_I : Int = 0x00D3 + final val CEE_CONV_OVF_I : Int = 0x00D4 + final val CEE_CONV_OVF_U : Int = 0x00D5 + final val CEE_ADD_OVF : Int = 0x00D6 + final val CEE_ADD_OVF_UN : Int = 0x00D7 + final val CEE_MUL_OVF : Int = 0x00D8 + final val CEE_MUL_OVF_UN : Int = 0x00D9 + final val CEE_SUB_OVF : Int = 0x00DA + final val CEE_SUB_OVF_UN : Int = 0x00DB + final val CEE_ENDFINALLY : Int = 0x00DC + final val CEE_LEAVE : Int = 0x00DD + final val CEE_LEAVE_S : Int = 0x00DE + final val CEE_STIND_I : Int = 0x00DF + final val CEE_CONV_U : Int = 0x00E0 + final val CEE_UNUSED26 : Int = 0x00E1 + final val CEE_UNUSED27 : Int = 0x00E2 + final val CEE_UNUSED28 : Int = 0x00E3 + final val CEE_UNUSED29 : Int = 0x00E4 + final val CEE_UNUSED30 : Int = 0x00E5 + final val CEE_UNUSED31 : Int = 0x00E6 + final val CEE_UNUSED32 : Int = 0x00E7 + final val CEE_UNUSED33 : Int = 0x00E8 + final val CEE_UNUSED34 : Int = 0x00E9 + final val CEE_UNUSED35 : Int = 0x00EA + final val CEE_UNUSED36 : Int = 0x00EB + final val CEE_UNUSED37 : Int = 0x00EC + final val CEE_UNUSED38 : Int = 0x00ED + final val CEE_UNUSED39 : Int = 0x00EE + final val CEE_UNUSED40 : Int = 0x00EF + final val CEE_UNUSED41 : Int = 0x00F0 + final val CEE_UNUSED42 : Int = 0x00F1 + final val CEE_UNUSED43 : Int = 0x00F2 + final val CEE_UNUSED44 : Int = 0x00F3 + final val CEE_UNUSED45 : Int = 0x00F4 + final val CEE_UNUSED46 : Int = 0x00F5 + final val CEE_UNUSED47 : Int = 0x00F6 + final val CEE_UNUSED48 : Int = 0x00F7 + final val CEE_PREFIX7 : Int = 0x00F8 + final val CEE_PREFIX6 : Int = 0x00F9 + final val CEE_PREFIX5 : Int = 0x00FA + final val CEE_PREFIX4 : Int = 0x00FB + final val CEE_PREFIX3 : Int = 0x00FC + final val CEE_PREFIX2 : Int = 0x00FD + final val CEE_PREFIX1 : Int = 0x00FE + final val CEE_PREFIXREF : Int = 0x00FF + + final val CEE_ARGLIST : Int = 0x0100 + final val CEE_CEQ : Int = 0x0101 + final val CEE_CGT : Int = 0x0102 + final val CEE_CGT_UN : Int = 0x0103 + final val CEE_CLT : Int = 0x0104 + final val CEE_CLT_UN : Int = 0x0105 + final val CEE_LDFTN : Int = 0x0106 + final val CEE_LDVIRTFTN : Int = 0x0107 + final val CEE_UNUSED56 : Int = 0x0108 + final val CEE_LDARG : Int = 0x0109 + final val CEE_LDARGA : Int = 0x010A + final val CEE_STARG : Int = 0x010B + final val CEE_LDLOC : Int = 0x010C + final val CEE_LDLOCA : Int = 0x010D + final val CEE_STLOC : Int = 0x010E + final val CEE_LOCALLOC : Int = 0x010F + final val CEE_UNUSED57 : Int = 0x0110 + final val CEE_ENDFILTER : Int = 0x0111 + final val CEE_UNALIGNED : Int = 0x0112 + final val CEE_VOLATILE : Int = 0x0113 + final val CEE_TAILCALL : Int = 0x0114 + final val CEE_INITOBJ : Int = 0x0115 + final val CEE_UNUSED68 : Int = 0x0116 + final val CEE_CPBLK : Int = 0x0117 + final val CEE_INITBLK : Int = 0x0118 + final val CEE_UNUSED69 : Int = 0x0119 + final val CEE_RETHROW : Int = 0x011A + final val CEE_UNUSED51 : Int = 0x011B + final val CEE_SIZEOF : Int = 0x011C + final val CEE_REFANYTYPE : Int = 0x011D + final val CEE_UNUSED52 : Int = 0x011E + final val CEE_UNUSED53 : Int = 0x011F + final val CEE_UNUSED54 : Int = 0x0120 + final val CEE_UNUSED55 : Int = 0x0121 + final val CEE_UNUSED70 : Int = 0x0122 + + final val CEE_ILLEGAL : Int = 0x0140 + final val CEE_MACRO_END : Int = 0x0141 + + final val CEE_BRNULL : Int = 0x0180 // CEE_BRFALSE + final val CEE_BRNULL_S : Int = 0x0181 // CEE_BRFALSE_S + final val CEE_BRZERO : Int = 0x0182 // CEE_BRFALSE + final val CEE_BRZERO_S : Int = 0x0183 // CEE_BRFALSE_S + final val CEE_BRINST : Int = 0x0184 // CEE_BRTRUE + final val CEE_BRINST_S : Int = 0x0185 // CEE_BRTRUE_S + final val CEE_LDIND_U8 : Int = 0x0186 // CEE_LDIND_I8 + final val CEE_LDELEM_U8 : Int = 0x0187 // CEE_LDELEM_I8 + final val CEE_LDC_I4_M1x : Int = 0x0188 // CEE_LDC_I4_M1 + final val CEE_ENDFAULT : Int = 0x0189 // CEE_ENDFINALLY + + final val CEE_BRNONZERO : Int = 0x01C0 // CEE_BRTRUE + final val CEE_BRNONZERO_S : Int = 0x01C1 // CEE_BRTRUE_S + + final val CEE_BRNOT : Int = 0x01C2 + final val CEE_BRNOT_S : Int = 0x01C3 + final val CEE_NOCODE : Int = 0x01C4 + + final val CEE_count : Int = 0x0200 + + + //######################################################################## + // Opcode's amount and type of poped data + + final val POP_NONE : byte = 0x00 + final val POP_1 : byte = 0x01 + final val POP_1_1 : byte = 0x02 + final val POP_I : byte = 0x03 + final val POP_I_1 : byte = 0x04 + final val POP_I_I : byte = 0x05 + final val POP_I_I8 : byte = 0x06 + final val POP_I_R4 : byte = 0x07 + final val POP_I_R8 : byte = 0x08 + final val POP_I_I_I : byte = 0x09 + final val POP_REF : byte = 0x0A + final val POP_REF_1 : byte = 0x0B + final val POP_REF_I : byte = 0x0C + final val POP_REF_I_I : byte = 0x0D + final val POP_REF_I_I8 : byte = 0x0E + final val POP_REF_I_R4 : byte = 0x0F + final val POP_REF_I_R8 : byte = 0x10 + final val POP_REF_I_REF : byte = 0x11 + final val POP_SPECIAL : byte = 0x12 + final val POP_count : Int = 0x13 + final val POP_size : Array[byte] = new Array[byte](POP_count) + + POP_size(POP_NONE) = 0 + POP_size(POP_1) = 1 + POP_size(POP_1_1) = 2 + POP_size(POP_I) = 1 + POP_size(POP_I_1) = 2 + POP_size(POP_I_I) = 2 + POP_size(POP_I_I8) = 2 + POP_size(POP_I_R4) = 2 + POP_size(POP_I_R8) = 2 + POP_size(POP_I_I_I) = 3 + POP_size(POP_REF) = 1 + POP_size(POP_REF_1) = 2 + POP_size(POP_REF_I) = 2 + POP_size(POP_REF_I_I) = 3 + POP_size(POP_REF_I_I8) = 3 + POP_size(POP_REF_I_R4) = 3 + POP_size(POP_REF_I_R8) = 3 + POP_size(POP_REF_I_REF) = 3 + POP_size(POP_SPECIAL) = -1 + + //######################################################################## + // Opcode's amount and type of pushed data + + final val PUSH_NONE : byte = 0x00 + final val PUSH_1 : byte = 0x01 + final val PUSH_1_1 : byte = 0x02 + final val PUSH_I : byte = 0x03 + final val PUSH_I8 : byte = 0x04 + final val PUSH_R4 : byte = 0x05 + final val PUSH_R8 : byte = 0x06 + final val PUSH_REF : byte = 0x07 + final val PUSH_SPECIAL : byte = 0x08 + final val PUSH_count : Int = 0x09 + final val PUSH_size : Array[byte] = new Array[byte](PUSH_count) + + PUSH_size(PUSH_NONE) = 0 + PUSH_size(PUSH_1) = 1 + PUSH_size(PUSH_1_1) = 2 + PUSH_size(PUSH_I) = 1 + PUSH_size(PUSH_I8) = 1 + PUSH_size(PUSH_R4) = 1 + PUSH_size(PUSH_R8) = 1 + PUSH_size(PUSH_REF) = 1 + PUSH_size(PUSH_SPECIAL) = -1 + + //######################################################################## + // Opcode's amount of moved data + + final val POPUSH_SPECIAL : byte = -128 + + //######################################################################## + // Opcode's inline argument types + + final val INLINE_NONE : byte = 0x00 + final val INLINE_VARIABLE_S : byte = 0x01 + final val INLINE_TARGET_S : byte = 0x02 + final val INLINE_I_S : byte = 0x03 + final val INLINE_VARIABLE : byte = 0x04 + final val INLINE_TARGET : byte = 0x05 + final val INLINE_I : byte = 0x06 + final val INLINE_I8 : byte = 0x07 + final val INLINE_R : byte = 0x08 + final val INLINE_R8 : byte = 0x09 + final val INLINE_STRING : byte = 0x0A + final val INLINE_TYPE : byte = 0x0B + final val INLINE_FIELD : byte = 0x0C + final val INLINE_METHOD : byte = 0x0D + final val INLINE_SIGNATURE : byte = 0x0E + final val INLINE_TOKEN : byte = 0x0F + final val INLINE_SWITCH : byte = 0x10 + final val INLINE_count : Int = 0x11 + final val INLINE_length : Array[byte] = new Array[byte](INLINE_count) + + INLINE_length(INLINE_NONE) = 0 + INLINE_length(INLINE_VARIABLE_S) = 1 + INLINE_length(INLINE_TARGET_S) = 1 + INLINE_length(INLINE_I_S) = 1 + INLINE_length(INLINE_VARIABLE) = 2 + INLINE_length(INLINE_TARGET) = 4 + INLINE_length(INLINE_I) = 4 + INLINE_length(INLINE_I8) = 8 + INLINE_length(INLINE_R) = 4 + INLINE_length(INLINE_R8) = 8 + INLINE_length(INLINE_STRING) = 4 + INLINE_length(INLINE_TYPE) = 4 + INLINE_length(INLINE_FIELD) = 4 + INLINE_length(INLINE_METHOD) = 4 + INLINE_length(INLINE_SIGNATURE) = 4 + INLINE_length(INLINE_SWITCH) = 4 + INLINE_length(INLINE_TOKEN) = 4 + + //######################################################################## + // Opcode's control flow implications + + final val FLOW_META : byte = 0x00 + final val FLOW_NEXT : byte = 0x01 + final val FLOW_BRANCH : byte = 0x02 + final val FLOW_COND_BRANCH : byte = 0x03 + final val FLOW_BREAK : byte = 0x04 + final val FLOW_CALL : byte = 0x05 + final val FLOW_RETURN : byte = 0x06 + final val FLOW_THROW : byte = 0x07 + final val FLOW_count : Int = 0x08 + + //######################################################################## + // Init methods for Opcode + + def opcode(that: OpCode, opcode: int, string: String, code: Int, + pop: byte, push: byte, inline: byte, flow: byte) { + that.CEE_opcode = opcode + that.CEE_string = string + that.CEE_code = code.asInstanceOf[short] + that.CEE_pop = pop + that.CEE_push = push + that.CEE_inline = inline + that.CEE_flow = flow + that.CEE_length = that.length() + that.CEE_popush = that.popush() + } + + def length(code: Int): byte = { + if ((code & 0xFFFFFF00) == 0xFFFFFF00) return 1 + if ((code & 0xFFFFFF00) == 0xFFFFFE00) return 2 + return 0 + } + + //######################################################################## + // case OpCode + + /** + * Adds two values and pushes the result onto the evaluation stack. + */ + final val Add = new OpCode() + opcode(Add, CEE_ADD, "add", 0xFFFFFF58, POP_1_1, PUSH_1, INLINE_NONE, FLOW_NEXT) + + /** + * Fills space if bytecodes are patched. No meaningful operation is performed + * although a processing cycle can be consumed. + */ + final val Nop = new OpCode() + opcode(Nop, CEE_NOP, "nop", 0xFFFFFF00, POP_NONE, PUSH_NONE, INLINE_NONE , FLOW_NEXT) + + /** + * Signals the Common Language Infrastructure (CLI) to inform the debugger that + * a break point has been tripped. + */ + final val Break = new OpCode() + opcode(Break, CEE_BREAK, "break" , 0xFFFFFF01, POP_NONE, PUSH_NONE , INLINE_NONE , FLOW_BREAK) + + /** + * Loads the argument at index 0 onto the evaluation stack. + */ + final val Ldarg_0 = new OpCode() + opcode(Ldarg_0, CEE_LDARG_0 , "ldarg.0" , 0xFFFFFF02, POP_NONE, PUSH_1 , INLINE_NONE , FLOW_NEXT) + + /** + * Loads the argument at index 1 onto the evaluation stack. + */ + final val Ldarg_1 = new OpCode() + opcode(Ldarg_1, CEE_LDARG_1 , "ldarg.1" , 0xFFFFFF03, POP_NONE, PUSH_1 , INLINE_NONE , FLOW_NEXT) + + /** + * Loads the argument at index 2 onto the evaluation stack. + */ + final val Ldarg_2 = new OpCode() + opcode(Ldarg_2, CEE_LDARG_2 , "ldarg.2" , 0xFFFFFF04, POP_NONE, PUSH_1 , INLINE_NONE , FLOW_NEXT) + + /** + * Loads the argument at index 3 onto the evaluation stack. + */ + final val Ldarg_3 = new OpCode() + opcode(Ldarg_3, CEE_LDARG_3 , "ldarg.3" , 0xFFFFFF05, POP_NONE, PUSH_1 , INLINE_NONE , FLOW_NEXT) + + /** + * Loads the local variable at index 0 onto the evaluation stack. + */ + final val Ldloc_0 = new OpCode() + opcode(Ldloc_0, CEE_LDLOC_0 , "ldloc.0" , 0xFFFFFF06, POP_NONE, PUSH_1 , INLINE_NONE , FLOW_NEXT) + + /** + * Loads the local variable at index 1 onto the evaluation stack. + */ + final val Ldloc_1 = new OpCode() + opcode(Ldloc_1, CEE_LDLOC_1 , "ldloc.1" , 0xFFFFFF07, POP_NONE, PUSH_1 , INLINE_NONE , FLOW_NEXT) + + /** + * Loads the local variable at index 2 onto the evaluation stack. + */ + final val Ldloc_2 = new OpCode() + opcode(Ldloc_2, CEE_LDLOC_2 , "ldloc.2" , 0xFFFFFF08, POP_NONE, PUSH_1 , INLINE_NONE , FLOW_NEXT) + + /** + * Loads the local variable at index 3 onto the evaluation stack. + */ + final val Ldloc_3 = new OpCode() + opcode(Ldloc_3, CEE_LDLOC_3 , "ldloc.3" , 0xFFFFFF09, POP_NONE, PUSH_1 , INLINE_NONE , FLOW_NEXT) + + /** + * Pops the current value from the top of the evaluation stack and + * stores it in a the local variable list at index 0. + */ + final val Stloc_0 = new OpCode() + opcode(Stloc_0, CEE_STLOC_0 , "stloc.0" , 0xFFFFFF0A, POP_1 , PUSH_NONE, INLINE_NONE , FLOW_NEXT) + + /** + * Pops the current value from the top of the evaluation stack and + * stores it in a the local variable list at index 1. + */ + final val Stloc_1 = new OpCode() + opcode(Stloc_1, CEE_STLOC_1 , "stloc.1" , 0xFFFFFF0B, POP_1 , PUSH_NONE, INLINE_NONE , FLOW_NEXT) + + /** + * Pops the current value from the top of the evaluation stack and + * stores it in a the local variable list at index 2. + */ + final val Stloc_2 = new OpCode() + opcode(Stloc_2, CEE_STLOC_2 , "stloc.2" , 0xFFFFFF0C, POP_1 , PUSH_NONE, INLINE_NONE , FLOW_NEXT) + + /** + * Pops the current value from the top of the evaluation stack and + * stores it in a the local variable list at index 3. + */ + final val Stloc_3 = new OpCode() + opcode(Stloc_3, CEE_STLOC_3 , "stloc.3" , 0xFFFFFF0D, POP_1 , PUSH_NONE, INLINE_NONE , FLOW_NEXT) + + /** + * Loads the argument (referenced by a specified short form index) + * onto the evaluation stack. + */ + final val Ldarg_S = new OpCode() + opcode(Ldarg_S, CEE_LDARG_S , "ldarg.s" , 0xFFFFFF0E, POP_NONE, PUSH_1 , INLINE_VARIABLE_S, FLOW_NEXT) + + /** + * Load an argument address, in short form, onto the evaluation stack. + */ + final val Ldarga_S = new OpCode() + opcode(Ldarga_S, CEE_LDARGA_S , "ldarga.s" , 0xFFFFFF0F, POP_NONE, PUSH_I , INLINE_VARIABLE_S, FLOW_NEXT) + + /** + * Loads the local variable at a specific index onto the evaluation stack, + * short form. + */ + final val Ldloc_S = new OpCode() + opcode(Ldloc_S, CEE_LDLOC_S , "ldloc.s" , 0xFFFFFF11, POP_NONE, PUSH_1 , INLINE_VARIABLE_S, FLOW_NEXT) + + /** + * Loads the address of the local variable at a specific index onto + * the evaluation stack, short form. + */ + final val Ldloca_S = new OpCode() + opcode(Ldloca_S, CEE_LDLOCA_S , "ldloca.s" , 0xFFFFFF12, POP_NONE, PUSH_I , INLINE_VARIABLE_S, FLOW_NEXT) + + /** + * Stores the value on top of the evaluation stack in the argument slot + * at a specified index, short form. + */ + final val Starg_S = new OpCode() + opcode(Starg_S, CEE_STARG_S , "starg.s" , 0xFFFFFF10, POP_1 , PUSH_NONE , INLINE_VARIABLE_S, FLOW_NEXT) + + /** + * Pops the current value from the top of the evaluation stack and stores it + * in a the local variable list at index (short form). + */ + final val Stloc_S = new OpCode() + opcode(Stloc_S, CEE_STLOC_S , "stloc.s" , 0xFFFFFF13, POP_1 , PUSH_NONE, INLINE_VARIABLE_S, FLOW_NEXT) + + /** + * Pushes a null reference (type O) onto the evaluation stack. + */ + final val Ldnull = new OpCode() + opcode(Ldnull, CEE_LDNULL , "ldnull" , 0xFFFFFF14, POP_NONE, PUSH_REF , INLINE_NONE, FLOW_NEXT) + + /** + * Pushes the integer value of -1 onto the evaluation stack as an int32. + */ + final val Ldc_I4_M1 = new OpCode() + opcode(Ldc_I4_M1, CEE_LDC_I4_M1, "ldc.i4.m1", 0xFFFFFF15, POP_NONE, PUSH_I, INLINE_NONE, FLOW_NEXT) + + /** + * Pushes the integer value of 0 onto the evaluation stack as an int32. + */ + final val Ldc_I4_0 = new OpCode() + opcode(Ldc_I4_0, CEE_LDC_I4_0 , "ldc.i4.0" , 0xFFFFFF16, POP_NONE, PUSH_I, INLINE_NONE, FLOW_NEXT) + + /** + * Pushes the integer value of 1 onto the evaluation stack as an int32. + */ + final val Ldc_I4_1 = new OpCode() + opcode(Ldc_I4_1, CEE_LDC_I4_1 , "ldc.i4.1" , 0xFFFFFF17, POP_NONE, PUSH_I, INLINE_NONE, FLOW_NEXT) + + /** + * Pushes the integer value of 2 onto the evaluation stack as an int32. + */ + final val Ldc_I4_2 = new OpCode() + opcode(Ldc_I4_2, CEE_LDC_I4_2 , "ldc.i4.2" , 0xFFFFFF18, POP_NONE, PUSH_I, INLINE_NONE, FLOW_NEXT) + + /** + * Pushes the integer value of 3 onto the evaluation stack as an int32. + */ + final val Ldc_I4_3 = new OpCode() + opcode(Ldc_I4_3, CEE_LDC_I4_3 , "ldc.i4.3" , 0xFFFFFF19, POP_NONE, PUSH_I, INLINE_NONE, FLOW_NEXT) + + /** + * Pushes the integer value of 4 onto the evaluation stack as an int32. + */ + final val Ldc_I4_4 = new OpCode() + opcode(Ldc_I4_4, CEE_LDC_I4_4 , "ldc.i4.4" , 0xFFFFFF1A, POP_NONE, PUSH_I, INLINE_NONE, FLOW_NEXT) + + /** + * Pushes the integer value of 5 onto the evaluation stack as an int32. + */ + final val Ldc_I4_5 = new OpCode() + opcode(Ldc_I4_5, CEE_LDC_I4_5 , "ldc.i4.5" , 0xFFFFFF1B, POP_NONE, PUSH_I, INLINE_NONE, FLOW_NEXT) + + /** + * Pushes the integer value of 6 onto the evaluation stack as an int32. + */ + final val Ldc_I4_6 = new OpCode() + opcode(Ldc_I4_6, CEE_LDC_I4_6 , "ldc.i4.6", 0xFFFFFF1C, POP_NONE, PUSH_I, INLINE_NONE, FLOW_NEXT) + + /** + * Pushes the integer value of 7 onto the evaluation stack as an int32. + */ + final val Ldc_I4_7 = new OpCode() + opcode(Ldc_I4_7, CEE_LDC_I4_7 , "ldc.i4.7", 0xFFFFFF1D, POP_NONE , PUSH_I, INLINE_NONE, FLOW_NEXT) + + /** + * Pushes the integer value of 8 onto the evaluation stack as an int32. + */ + final val Ldc_I4_8 = new OpCode() + opcode(Ldc_I4_8, CEE_LDC_I4_8 , "ldc.i4.8", 0xFFFFFF1E, POP_NONE , PUSH_I, INLINE_NONE, FLOW_NEXT) + + /** + * Pushes the supplied int8 value onto the evaluation stack as an int32, short form. + */ + final val Ldc_I4_S = new OpCode() + opcode(Ldc_I4_S, CEE_LDC_I4_S , "ldc.i4.s", 0xFFFFFF1F, POP_NONE , PUSH_I, INLINE_I_S, FLOW_NEXT) + + /** + * Pushes a supplied value of type int32 onto the evaluation stack as an int32. + */ + final val Ldc_I4 = new OpCode() + opcode(Ldc_I4, CEE_LDC_I4, "ldc.i4" , 0xFFFFFF20, POP_NONE , PUSH_I, INLINE_I , FLOW_NEXT) + + /** + * Pushes a supplied value of type int64 onto the evaluation stack as an int64. + */ + final val Ldc_I8 = new OpCode() + opcode(Ldc_I8, CEE_LDC_I8, "ldc.i8" , 0xFFFFFF21, POP_NONE , PUSH_I8, INLINE_I8 , FLOW_NEXT) + + /** + * Pushes a supplied value of type float32 onto the evaluation stack as type F (float). + */ + final val Ldc_R4 = new OpCode() + opcode(Ldc_R4, CEE_LDC_R4, "ldc.r4" , 0xFFFFFF22, POP_NONE , PUSH_R4, INLINE_R , FLOW_NEXT) + + /** + * Pushes a supplied value of type float64 onto the evaluation stack as type F (float). + */ + final val Ldc_R8 = new OpCode() + opcode(Ldc_R8, CEE_LDC_R8, "ldc.r8" , 0xFFFFFF23, POP_NONE , PUSH_R8, INLINE_R8 , FLOW_NEXT) + + /** + * Copies the current topmost value on the evaluation stack, and then pushes the copy + * onto the evaluation stack. + */ + final val Dup = new OpCode() + opcode(Dup, CEE_DUP , "dup" , 0xFFFFFF25, POP_1 , PUSH_1_1 , INLINE_NONE , FLOW_NEXT) + + /** + * Removes the value currently on top of the evaluation stack. + */ + final val Pop = new OpCode() + opcode(Pop, CEE_POP , "pop" , 0xFFFFFF26, POP_1 , PUSH_NONE , INLINE_NONE , FLOW_NEXT) + + /** + * Exits current method and jumps to specified method. + */ + final val Jmp = new OpCode() + opcode(Jmp, CEE_JMP , "jmp" , 0xFFFFFF27, POP_NONE , PUSH_NONE , INLINE_METHOD, FLOW_CALL) + + /** + * Calls the method indicated by the passed method descriptor. + */ + final val Call = new OpCode() + opcode(Call, CEE_CALL , "call" , 0xFFFFFF28, POP_SPECIAL, PUSH_SPECIAL, INLINE_METHOD , FLOW_CALL) + + /** + * Calls the method indicated on the evaluation stack (as a pointer to an entry point) + * with arguments described by a calling convention. + */ + final val Calli = new OpCode() + opcode(Calli, CEE_CALLI, "calli" , 0xFFFFFF29, POP_SPECIAL, PUSH_SPECIAL, INLINE_SIGNATURE , FLOW_CALL) + + /** + * Returns from the current method, pushing a return value (if present) from the caller's + * evaluation stack onto the callee's evaluation stack. + */ + final val Ret = new OpCode() + opcode(Ret, CEE_RET , "ret" , 0xFFFFFF2A, POP_SPECIAL, PUSH_NONE, INLINE_NONE , FLOW_RETURN) + + /** + * Unconditionally transfers control to a target instruction (short form). + */ + final val Br_S = new OpCode() + opcode(Br_S, CEE_BR_S , "br.s" , 0xFFFFFF2B, POP_NONE, PUSH_NONE, INLINE_TARGET_S , FLOW_BRANCH) + + /** + * Transfers control to a target instruction if value is false, a null reference, or zero. + */ + final val Brfalse_S = new OpCode() + opcode(Brfalse_S, CEE_BRFALSE_S,"brfalse.s", 0xFFFFFF2C, POP_I, PUSH_NONE, INLINE_TARGET_S, FLOW_COND_BRANCH) + + /** + * Transfers control to a target instruction (short form) if value is true, not null, or non-zero. + */ + final val Brtrue_S = new OpCode() + opcode(Brtrue_S, CEE_BRTRUE_S , "brtrue.s", 0xFFFFFF2D, POP_I, PUSH_NONE, INLINE_TARGET_S, FLOW_COND_BRANCH) + + /** + * Transfers control to a target instruction (short form) if two values are equal. + */ + final val Beq_S = new OpCode() + opcode(Beq_S, CEE_BEQ_S, "beq.s", 0xFFFFFF2E, POP_1_1 , PUSH_NONE, INLINE_TARGET_S , FLOW_COND_BRANCH) + + /** + * Transfers control to a target instruction (short form) if the first value is greater than + * or equal to the second value. + */ + final val Bge_S = new OpCode() + opcode(Bge_S, CEE_BGE_S, "bge.s", 0xFFFFFF2F, POP_1_1 , PUSH_NONE, INLINE_TARGET_S, FLOW_COND_BRANCH) + + /** + * Transfers control to a target instruction (short form) if the first value is greater than + * the second value. + */ + final val Bgt_S = new OpCode() + opcode(Bgt_S, CEE_BGT_S, "bgt.s" , 0xFFFFFF30, POP_1_1 , PUSH_NONE, INLINE_TARGET_S , FLOW_COND_BRANCH) + + /** + * Transfers control to a target instruction (short form) if the first value is less than + * or equal to the second value. + */ + final val Ble_S = new OpCode() + opcode(Ble_S, CEE_BLE_S, "ble.s" , 0xFFFFFF31, POP_1_1 , PUSH_NONE, INLINE_TARGET_S , FLOW_COND_BRANCH) + + /** + * Transfers control to a target instruction (short form) if the first value is less than + * the second value. + */ + final val Blt_S = new OpCode() + opcode(Blt_S, CEE_BLT_S, "blt.s", 0xFFFFFF32, POP_1_1, PUSH_NONE, INLINE_TARGET_S, FLOW_COND_BRANCH) + + /** + * Transfers control to a target instruction (short form) when two unsigned integer values + * or unordered float values are not equal. + */ + final val Bne_Un_S = new OpCode() + opcode(Bne_Un_S, CEE_BNE_UN_S, "bne.un.s", 0xFFFFFF33, POP_1_1 , PUSH_NONE, INLINE_TARGET_S, FLOW_COND_BRANCH) + + /** + * Transfers control to a target instruction (short form) if if the the first value is greather + * than the second value, when comparing unsigned integer values or unordered float values. + */ + final val Bge_Un_S = new OpCode() + opcode(Bge_Un_S, CEE_BGE_UN_S, "bge.un.s", 0xFFFFFF34, POP_1_1, PUSH_NONE, INLINE_TARGET_S, FLOW_COND_BRANCH) + + /** + * Transfers control to a target instruction (short form) if the first value is greater than + * the second value, when comparing unsigned integer values or unordered float values. + */ + final val Bgt_Un_S = new OpCode() + opcode(Bgt_Un_S, CEE_BGT_UN_S, "bgt.un.s", 0xFFFFFF35, POP_1_1, PUSH_NONE, INLINE_TARGET_S, FLOW_COND_BRANCH) + + /** + * Transfers control to a target instruction (short form) if the first value is less than + * or equal to the second value, when comparing unsigned integer values or unordered float values. + */ + final val Ble_Un_S = new OpCode() + opcode(Ble_Un_S, CEE_BLE_UN_S , "ble.un.s", 0xFFFFFF36, POP_1_1, PUSH_NONE, INLINE_TARGET_S, FLOW_COND_BRANCH) + + /** + * Transfers control to a target instruction (short form) if the first value is less than + * the second value, when comparing unsigned integer values or unordered float values. + */ + final val Blt_Un_S = new OpCode() + opcode(Blt_Un_S, CEE_BLT_UN_S, "blt.un.s", 0xFFFFFF37, POP_1_1, PUSH_NONE, INLINE_TARGET_S, FLOW_COND_BRANCH) + + /** + * Unconditionally transfers control to a target instruction. + */ + final val Br = new OpCode() + opcode(Br, CEE_BR , "br" , 0xFFFFFF38, POP_NONE, PUSH_NONE, INLINE_TARGET, FLOW_BRANCH) + + /** + * Transfers control to a target instruction if value is false, a null reference + * (Nothing in Visual Basic), or zero. + */ + final val Brfalse = new OpCode() + opcode(Brfalse, CEE_BRFALSE, "brfalse", 0xFFFFFF39, POP_I, PUSH_NONE, INLINE_TARGET, FLOW_COND_BRANCH) + + /** + * Transfers control to a target instruction if value is true, not null, or non-zero. + */ + final val Brtrue = new OpCode() + opcode(Brtrue, CEE_BRTRUE , "brtrue", 0xFFFFFF3A, POP_I , PUSH_NONE, INLINE_TARGET, FLOW_COND_BRANCH) + + /** + * Transfers control to a target instruction if two values are equal. + */ + final val Beq = new OpCode() + opcode(Beq, CEE_BEQ, "beq", 0xFFFFFF3B, POP_1_1 , PUSH_NONE, INLINE_TARGET, FLOW_COND_BRANCH) + + /** + * Transfers control to a target instruction if the first value is greater than or + * equal to the second value. + */ + final val Bge = new OpCode() + opcode(Bge, CEE_BGE, "bge", 0xFFFFFF3C, POP_1_1 , PUSH_NONE, INLINE_TARGET, FLOW_COND_BRANCH) + + /** + * Transfers control to a target instruction if the first value is greater than the second value. + */ + final val Bgt = new OpCode() + opcode(Bgt, CEE_BGT, "bgt", 0xFFFFFF3D, POP_1_1 , PUSH_NONE, INLINE_TARGET, FLOW_COND_BRANCH) + + /** + * Transfers control to a target instruction if the first value is less than or equal + * to the second value. + */ + final val Ble = new OpCode() + opcode(Ble, CEE_BLE, "ble", 0xFFFFFF3E, POP_1_1 , PUSH_NONE, INLINE_TARGET, FLOW_COND_BRANCH) + + /** + * Transfers control to a target instruction if the first value is less than the second value. + */ + final val Blt = new OpCode() + opcode(Blt, CEE_BLT, "blt", 0xFFFFFF3F, POP_1_1 , PUSH_NONE, INLINE_TARGET, FLOW_COND_BRANCH) + + /** + * Transfers control to a target instruction when two unsigned integer values or + * unordered float values are not equal. + */ + final val Bne_Un = new OpCode() + opcode(Bne_Un, CEE_BNE_UN , "bne.un", 0xFFFFFF40, POP_1_1 , PUSH_NONE, INLINE_TARGET, FLOW_COND_BRANCH) + + /** + * Transfers control to a target instruction if the the first value is greather than + * the second value, when comparing unsigned integer values or unordered float values. + */ + final val Bge_Un = new OpCode() + opcode(Bge_Un, CEE_BGE_UN , "bge.un", 0xFFFFFF41, POP_1_1 , PUSH_NONE, INLINE_TARGET, FLOW_COND_BRANCH) + + /** + * Transfers control to a target instruction if the first value is greater than the + * second value, when comparing unsigned integer values or unordered float values. + */ + final val Bgt_Un = new OpCode() + opcode(Bgt_Un, CEE_BGT_UN , "bgt.un", 0xFFFFFF42, POP_1_1 , PUSH_NONE, INLINE_TARGET, FLOW_COND_BRANCH) + + /** + * Transfers control to a target instruction if the first value is less than or equal to + * the second value, when comparing unsigned integer values or unordered float values. + */ + final val Ble_Un = new OpCode() + opcode(Ble_Un, CEE_BLE_UN , "ble.un" , 0xFFFFFF43, POP_1_1 , PUSH_NONE, INLINE_TARGET, FLOW_COND_BRANCH) + + /** + * Transfers control to a target instruction if the first value is less than the second value, + * when comparing unsigned integer values or unordered float values. + */ + final val Blt_Un = new OpCode() + opcode(Blt_Un, CEE_BLT_UN , "blt.un", 0xFFFFFF44, POP_1_1 , PUSH_NONE, INLINE_TARGET, FLOW_COND_BRANCH) + + /** + * Implements a jump table. + */ + final val Switch = new OpCode() + opcode(Switch, CEE_SWITCH , "switch", 0xFFFFFF45, POP_I , PUSH_NONE, INLINE_SWITCH, FLOW_COND_BRANCH) + + /** + * Loads a value of type int8 as an int32 onto the evaluation stack indirectly. + */ + final val Ldind_I1 = new OpCode() + opcode(Ldind_I1, CEE_LDIND_I1 , "ldind.i1" , 0xFFFFFF46, POP_I , PUSH_I , INLINE_NONE, FLOW_NEXT) + + /** + * Loads a value of type int16 as an int32 onto the evaluation stack indirectly. + */ + final val Ldind_I2 = new OpCode() + opcode(Ldind_I2, CEE_LDIND_I2 , "ldind.i2" , 0xFFFFFF48, POP_I , PUSH_I , INLINE_NONE, FLOW_NEXT) + + /** + * Loads a value of type int32 as an int32 onto the evaluation stack indirectly. + */ + final val Ldind_I4 = new OpCode() + opcode(Ldind_I4, CEE_LDIND_I4 , "ldind.i4" , 0xFFFFFF4A, POP_I , PUSH_I , INLINE_NONE, FLOW_NEXT) + + /** + * Loads a value of type int64 as an int64 onto the evaluation stack indirectly. + */ + final val Ldind_I8 = new OpCode() + opcode(Ldind_I8, CEE_LDIND_I8 , "ldind.i8" , 0xFFFFFF4C, POP_I , PUSH_I8 , INLINE_NONE, FLOW_NEXT) + + /** + * Loads a value of type natural int as a natural int onto the evaluation stack indirectly. + */ + final val Ldind_I = new OpCode() + opcode(Ldind_I, CEE_LDIND_I , "ldind.i" , 0xFFFFFF4D, POP_I , PUSH_I , INLINE_NONE, FLOW_NEXT) + + /** + * Loads a value of type float32 as a type F (float) onto the evaluation stack indirectly. + */ + final val Ldind_R4 = new OpCode() + opcode(Ldind_R4, CEE_LDIND_R4 , "ldind.r4" , 0xFFFFFF4E, POP_I , PUSH_R4 , INLINE_NONE, FLOW_NEXT) + + /** + * Loads a value of type float64 as a type F (float) onto the evaluation stack indirectly. + */ + final val Ldind_R8 = new OpCode() + opcode(Ldind_R8, CEE_LDIND_R8 , "ldind.r8" , 0xFFFFFF4F, POP_I , PUSH_R8 , INLINE_NONE, FLOW_NEXT) + + /** + * Loads an object reference as a type O (object reference) onto the evaluation stack indirectly. + */ + final val Ldind_Ref = new OpCode() + opcode(Ldind_Ref, CEE_LDIND_REF, "ldind.ref", 0xFFFFFF50, POP_I , PUSH_REF, INLINE_NONE, FLOW_NEXT) + + /** + * Loads a value of type unsigned int8 as an int32 onto the evaluation stack indirectly. + */ + final val Ldind_U1 = new OpCode() + opcode(Ldind_U1, CEE_LDIND_U1 , "ldind.u1" , 0xFFFFFF47, POP_I , PUSH_I , INLINE_NONE, FLOW_NEXT) + + /** + * Loads a value of type unsigned int16 as an int32 onto the evaluation stack indirectly. + */ + final val Ldind_U2 = new OpCode() + opcode(Ldind_U2, CEE_LDIND_U2 , "ldind.u2" , 0xFFFFFF49, POP_I , PUSH_I , INLINE_NONE, FLOW_NEXT) + + /** + * Loads a value of type unsigned int32 as an int32 onto the evaluation stack indirectly. + */ + final val Ldind_U4 = new OpCode() + opcode(Ldind_U4, CEE_LDIND_U4 , "ldind.u4" , 0xFFFFFF4B, POP_I , PUSH_I , INLINE_NONE, FLOW_NEXT) + + /** + * Stores a object reference value at a supplied address. + */ + final val Stind_Ref = new OpCode() + opcode(Stind_Ref, CEE_STIND_REF, "stind.ref", 0xFFFFFF51, POP_I_I , PUSH_NONE, INLINE_NONE, FLOW_NEXT) + + /** + * Stores a value of type int8 at a supplied address. + */ + final val Stind_I1 = new OpCode() + opcode(Stind_I1, CEE_STIND_I1 , "stind.i1", 0xFFFFFF52, POP_I_I , PUSH_NONE, INLINE_NONE, FLOW_NEXT) + + /** + * Stores a value of type int16 at a supplied address. + */ + final val Stind_I2 = new OpCode() + opcode(Stind_I2, CEE_STIND_I2 , "stind.i2", 0xFFFFFF53, POP_I_I , PUSH_NONE, INLINE_NONE, FLOW_NEXT) + + /** + * Stores a value of type int32 at a supplied address. + */ + final val Stind_I4 = new OpCode() + opcode(Stind_I4, CEE_STIND_I4 , "stind.i4", 0xFFFFFF54, POP_I_I , PUSH_NONE, INLINE_NONE, FLOW_NEXT) + + /** + * Stores a value of type int64 at a supplied address. + */ + final val Stind_I8 = new OpCode() + opcode(Stind_I8, CEE_STIND_I8 , "stind.i8", 0xFFFFFF55, POP_I_I8, PUSH_NONE, INLINE_NONE, FLOW_NEXT) + + /** + * Stores a value of type float32 at a supplied address. + */ + final val Stind_R4 = new OpCode() + opcode(Stind_R4, CEE_STIND_R4 , "stind.r4", 0xFFFFFF56, POP_I_R4, PUSH_NONE, INLINE_NONE, FLOW_NEXT) + + /** + * Stores a value of type float64 at a supplied address. + */ + final val Stind_R8 = new OpCode() + opcode(Stind_R8, CEE_STIND_R8 , "stind.r8", 0xFFFFFF57, POP_I_R8, PUSH_NONE, INLINE_NONE, FLOW_NEXT) + + /** + * Subtracts one value from another and pushes the result onto the evaluation stack. + */ + final val Sub = new OpCode() + opcode(Sub, CEE_SUB, "sub" , 0xFFFFFF59, POP_1_1, PUSH_1 , INLINE_NONE, FLOW_NEXT) + + /** + * Multiplies two values and pushes the result on the evaluation stack. + */ + final val Mul = new OpCode() + opcode(Mul, CEE_MUL, "mul" , 0xFFFFFF5A, POP_1_1, PUSH_1 , INLINE_NONE, FLOW_NEXT) + + /** + * Divides two values and pushes the result as a floating-point (type F) or + * quotient (type int32) onto the evaluation stack. + */ + final val Div = new OpCode() + opcode(Div, CEE_DIV, "div" , 0xFFFFFF5B, POP_1_1, PUSH_1 , INLINE_NONE, FLOW_NEXT) + + /** + * Divides two unsigned integer values and pushes the result (int32) onto the evaluation stack. + */ + final val Div_Un = new OpCode() + opcode(Div_Un, CEE_DIV_UN, "div.un" , 0xFFFFFF5C, POP_1_1, PUSH_1 , INLINE_NONE, FLOW_NEXT) + + /** + * Divides two values and pushes the remainder onto the evaluation stack. + */ + final val Rem = new OpCode() + opcode(Rem, CEE_REM , "rem" , 0xFFFFFF5D, POP_1_1, PUSH_1 , INLINE_NONE, FLOW_NEXT) + + /** + * Divides two unsigned values and pushes the remainder onto the evaluation stack. + */ + final val Rem_Un = new OpCode() + opcode(Rem_Un, CEE_REM_UN, "rem.un" , 0xFFFFFF5E, POP_1_1, PUSH_1 , INLINE_NONE, FLOW_NEXT) + + /** + * Computes the bitwise AND of two values and pushes the result onto the evalution stack. + */ + final val And = new OpCode() + opcode(And, CEE_AND, "and" , 0xFFFFFF5F, POP_1_1, PUSH_1 , INLINE_NONE, FLOW_NEXT) + + /** + * Compute the bitwise complement of the two integer values on top of the stack and + * pushes the result onto the evaluation stack. + */ + final val Or = new OpCode() + opcode(Or, CEE_OR , "or" , 0xFFFFFF60, POP_1_1, PUSH_1 , INLINE_NONE, FLOW_NEXT) + + /** + * Computes the bitwise XOR of the top two values on the evaluation stack, + * pushing the result onto the evaluation stack. + */ + final val Xor = new OpCode() + opcode(Xor, CEE_XOR, "xor" , 0xFFFFFF61, POP_1_1, PUSH_1 , INLINE_NONE, FLOW_NEXT) + + /** + * Shifts an integer value to the left (in zeroes) by a specified number of bits, + * pushing the result onto the evaluation stack. + */ + final val Shl = new OpCode() + opcode(Shl, CEE_SHL, "shl" , 0xFFFFFF62, POP_1_1, PUSH_1 , INLINE_NONE, FLOW_NEXT) + + /** + * Shifts an integer value (in sign) to the right by a specified number of bits, + * pushing the result onto the evaluation stack. + */ + final val Shr = new OpCode() + opcode(Shr, CEE_SHR, "shr" , 0xFFFFFF63, POP_1_1, PUSH_1 , INLINE_NONE, FLOW_NEXT) + + /** + * Shifts an unsigned integer value (in zeroes) to the right by a specified number of bits, + * pushing the result onto the evaluation stack. + */ + final val Shr_Un = new OpCode() + opcode(Shr_Un, CEE_SHR_UN, "shr.un" , 0xFFFFFF64, POP_1_1, PUSH_1 , INLINE_NONE, FLOW_NEXT) + + /** + * Negates a value and pushes the result onto the evaluation stack. + */ + final val Neg = new OpCode() + opcode(Neg, CEE_NEG , "neg" , 0xFFFFFF65, POP_1 , PUSH_1 , INLINE_NONE, FLOW_NEXT) + + /** + * Computes the bitwise complement of the integer value on top of the stack and pushes + * the result onto the evaluation stack as the same type. + */ + final val Not = new OpCode() + opcode(Not, CEE_NOT , "not" , 0xFFFFFF66, POP_1 , PUSH_1 , INLINE_NONE, FLOW_NEXT) + + /** + * Converts the value on top of the evaluation stack to int8, then extends (pads) it to int32. + */ + final val Conv_I1 = new OpCode() + opcode(Conv_I1, CEE_CONV_I1, "conv.i1", 0xFFFFFF67, POP_1 , PUSH_I , INLINE_NONE, FLOW_NEXT) + + /** + * Converts the value on top of the evaluation stack to int16, then extends (pads) it to int32. + */ + final val Conv_I2 = new OpCode() + opcode(Conv_I2, CEE_CONV_I2, "conv.i2", 0xFFFFFF68, POP_1 , PUSH_I , INLINE_NONE, FLOW_NEXT) + + /** + * Converts the value on top of the evaluation stack to int32. + */ + final val Conv_I4 = new OpCode() + opcode(Conv_I4, CEE_CONV_I4, "conv.i4", 0xFFFFFF69, POP_1 , PUSH_I , INLINE_NONE, FLOW_NEXT) + + /** + * Converts the value on top of the evaluation stack to int64. + */ + final val Conv_I8 = new OpCode() + opcode(Conv_I8, CEE_CONV_I8, "conv.i8", 0xFFFFFF6A, POP_1 , PUSH_I8, INLINE_NONE, FLOW_NEXT) + + /** + * Converts the value on top of the evaluation stack to float32. + */ + final val Conv_R4 = new OpCode() + opcode(Conv_R4, CEE_CONV_R4, "conv.r4", 0xFFFFFF6B, POP_1 , PUSH_R4, INLINE_NONE, FLOW_NEXT) + + /** + * Converts the value on top of the evaluation stack to float64. + */ + final val Conv_R8 = new OpCode() + opcode(Conv_R8, CEE_CONV_R8, "conv.r8", 0xFFFFFF6C, POP_1 , PUSH_R8, INLINE_NONE, FLOW_NEXT) + + /** + * Converts the value on top of the evaluation stack to unsigned int32, and extends it to int32. + */ + final val Conv_U4 = new OpCode() + opcode(Conv_U4, CEE_CONV_U4, "conv.u4", 0xFFFFFF6D, POP_1 , PUSH_I , INLINE_NONE, FLOW_NEXT) + + /** + * Converts the value on top of the evaluation stack to unsigned int64, and extends it to int64. + */ + final val Conv_U8 = new OpCode() + opcode(Conv_U8, CEE_CONV_U8, "conv.u8", 0xFFFFFF6E, POP_1 , PUSH_I8, INLINE_NONE, FLOW_NEXT) + + /** + * Calls a late-bound method on an object, pushing the return value onto the evaluation stack. + */ + final val Callvirt = new OpCode() + opcode(Callvirt, CEE_CALLVIRT, "callvirt", 0xFFFFFF6F,POP_SPECIAL,PUSH_SPECIAL,INLINE_METHOD,FLOW_CALL) + + /** + * Copies the value type located at the address of an object (type &, * or natural int) + * to the address of the destination object (type &, * or natural int). + */ + final val Cpobj = new OpCode() + opcode(Cpobj, CEE_CPOBJ , "cpobj" , 0xFFFFFF70, POP_I_I , PUSH_NONE, INLINE_TYPE , FLOW_NEXT) + + /** + * Copies the value type object pointed to by an address to the top of the evaluation stack. + */ + final val Ldobj = new OpCode() + opcode(Ldobj, CEE_LDOBJ , "ldobj" , 0xFFFFFF71, POP_I , PUSH_1 , INLINE_TYPE , FLOW_NEXT) + + /** + * Pushes a new object reference to a string literal stored in the metadata. + */ + final val Ldstr = new OpCode() + opcode(Ldstr, CEE_LDSTR , "ldstr" , 0xFFFFFF72, POP_NONE , PUSH_REF , INLINE_STRING, FLOW_NEXT) + + /** + * Creates a new object or a new instance of a value type, pushing an object reference + * (type O) onto the evaluation stack. + */ + final val Newobj = new OpCode() + opcode(Newobj, CEE_NEWOBJ, "newobj", 0xFFFFFF73, POP_SPECIAL , PUSH_REF , INLINE_METHOD, FLOW_CALL) + + /** + * Attempts to cast an object passed by reference to the specified class. + */ + final val Castclass = new OpCode() + opcode(Castclass, CEE_CASTCLASS, "castclass", 0xFFFFFF74, POP_REF , PUSH_REF , INLINE_TYPE , FLOW_NEXT) + + /** + * Tests whether an object reference (type O) is an instance of a particular class. + */ + final val Isinst = new OpCode() + opcode(Isinst, CEE_ISINST , "isinst" , 0xFFFFFF75, POP_REF , PUSH_I , INLINE_TYPE , FLOW_NEXT) + + /** + * Converts the unsigned integer value on top of the evaluation stack to float32. + */ + final val Conv_R_Un = new OpCode() + opcode(Conv_R_Un, CEE_CONV_R_UN, "conv.r.un", 0xFFFFFF76, POP_1 , PUSH_R8 , INLINE_NONE , FLOW_NEXT) + + /** + * Converts the boxed representation of a value type to its unboxed form. + */ + final val Unbox = new OpCode() + opcode(Unbox, CEE_UNBOX , "unbox" , 0xFFFFFF79, POP_REF , PUSH_I , INLINE_TYPE , FLOW_NEXT) + + /** + * Throws the exception object currently on the evaluation stack. + */ + final val Throw = new OpCode() + opcode(Throw, CEE_THROW , "throw" , 0xFFFFFF7A, POP_REF , PUSH_NONE, INLINE_NONE , FLOW_THROW) + + /** + * Finds the value of a field in the object whose reference is currently + * on the evaluation stack. + */ + final val Ldfld = new OpCode() + opcode(Ldfld, CEE_LDFLD , "ldfld" , 0xFFFFFF7B, POP_REF , PUSH_1 , INLINE_FIELD , FLOW_NEXT) + + /** + * Finds the address of a field in the object whose reference is currently + * on the evaluation stack. + */ + final val Ldflda = new OpCode() + opcode(Ldflda, CEE_LDFLDA , "ldflda" , 0xFFFFFF7C, POP_REF , PUSH_I , INLINE_FIELD , FLOW_NEXT) + + /** + * Pushes the value of a static field onto the evaluation stack. + */ + final val Ldsfld = new OpCode() + opcode(Ldsfld, CEE_LDSFLD , "ldsfld" , 0xFFFFFF7E, POP_NONE , PUSH_1 , INLINE_FIELD , FLOW_NEXT) + + /** + * Pushes the address of a static field onto the evaluation stack. + */ + final val Ldsflda = new OpCode() + opcode(Ldsflda, CEE_LDSFLDA, "ldsflda", 0xFFFFFF7F, POP_NONE , PUSH_I , INLINE_FIELD , FLOW_NEXT) + + /** + * Replaces the value stored in the field of an object reference or pointer with a new value. + */ + final val Stfld = new OpCode() + opcode(Stfld, CEE_STFLD , "stfld" , 0xFFFFFF7D, POP_REF_1, PUSH_NONE, INLINE_FIELD , FLOW_NEXT) + + /** + * Replaces the value of a static field with a value from the evaluation stack. + */ + final val Stsfld = new OpCode() + opcode(Stsfld, CEE_STSFLD , "stsfld" , 0xFFFFFF80, POP_1 , PUSH_NONE, INLINE_FIELD , FLOW_NEXT) + + /** + * Copies a value of a specified type from the evaluation stack into a supplied memory address. + */ + final val Stobj = new OpCode() + opcode(Stobj, CEE_STOBJ , "stobj" , 0xFFFFFF81, POP_I_1, PUSH_NONE, INLINE_TYPE , FLOW_NEXT) + + /** + * Converts the unsigned value on top of the evaluation stack to signed int8 and + * extends it to int32, throwing OverflowException on overflow. + */ + final val Conv_Ovf_I1_Un = new OpCode() + opcode(Conv_Ovf_I1_Un, CEE_CONV_OVF_I1_UN, "conv.ovf.i1.un", 0xFFFFFF82, POP_1,PUSH_I,INLINE_NONE, FLOW_NEXT) + + /** + * Converts the unsigned value on top of the evaluation stack to signed int16 and + * extends it to int32, throwing OverflowException on overflow. + */ + final val Conv_Ovf_I2_Un = new OpCode() + opcode(Conv_Ovf_I2_Un, CEE_CONV_OVF_I2_UN, "conv.ovf.i2.un", 0xFFFFFF83,POP_1,PUSH_I, INLINE_NONE, FLOW_NEXT) + + /** + * Converts the unsigned value on top of the evaluation stack to signed int32, + * throwing OverflowException on overflow. + */ + final val Conv_Ovf_I4_Un = new OpCode() + opcode(Conv_Ovf_I4_Un, CEE_CONV_OVF_I4_UN, "conv.ovf.i4.un", 0xFFFFFF84,POP_1,PUSH_I, INLINE_NONE, FLOW_NEXT) + + /** + * Converts the unsigned value on top of the evaluation stack to signed int64, + * throwing OverflowException on overflow. + */ + final val Conv_Ovf_I8_Un = new OpCode() + opcode(Conv_Ovf_I8_Un, CEE_CONV_OVF_I8_UN, "conv.ovf.i8.un", 0xFFFFFF85,POP_1,PUSH_I8, INLINE_NONE, FLOW_NEXT) + + /** + * Converts the unsigned value on top of the evaluation stack to signed natural int, + * throwing OverflowException on overflow. + */ + final val Conv_Ovf_I_Un = new OpCode() + opcode(Conv_Ovf_I_Un, CEE_CONV_OVF_I_UN , "conv.ovf.i.un" , 0xFFFFFF8A,POP_1,PUSH_I, INLINE_NONE, FLOW_NEXT) + + /** + * Converts the unsigned value on top of the evaluation stack to unsigned int8 and + * extends it to int32, throwing OverflowException on overflow. + */ + final val Conv_Ovf_U1_Un = new OpCode() + opcode(Conv_Ovf_U1_Un, CEE_CONV_OVF_U1_UN, "conv.ovf.u1.un", 0xFFFFFF86,POP_1,PUSH_I, INLINE_NONE, FLOW_NEXT) + + /** + * Converts the unsigned value on top of the evaluation stack to unsigned int16 and + * extends it to int32, throwing OverflowException on overflow. + */ + final val Conv_Ovf_U2_Un = new OpCode() + opcode(Conv_Ovf_U2_Un, CEE_CONV_OVF_U2_UN, "conv.ovf.u2.un", 0xFFFFFF87,POP_1,PUSH_I, INLINE_NONE, FLOW_NEXT) + + /** + * Converts the unsigned value on top of the evaluation stack to unsigned int32, + * throwing OverflowException on overflow. + */ + final val Conv_Ovf_U4_Un = new OpCode() + opcode(Conv_Ovf_U4_Un, CEE_CONV_OVF_U4_UN, "conv.ovf.u4.un", 0xFFFFFF88,POP_1,PUSH_I, INLINE_NONE, FLOW_NEXT) + + /** + * Converts the unsigned value on top of the evaluation stack to unsigned int64, + * throwing OverflowException on overflow. + */ + final val Conv_Ovf_U8_Un = new OpCode() + opcode(Conv_Ovf_U8_Un, CEE_CONV_OVF_U8_UN, "conv.ovf.u8.un", 0xFFFFFF89,POP_1,PUSH_I8, INLINE_NONE, FLOW_NEXT) + + /** + * Converts the unsigned value on top of the evaluation stack to unsigned natural int, + * throwing OverflowException on overflow. + */ + final val Conv_Ovf_U_Un = new OpCode() + opcode(Conv_Ovf_U_Un, CEE_CONV_OVF_U_UN , "conv.ovf.u.un" , 0xFFFFFF8B,POP_1,PUSH_I, INLINE_NONE, FLOW_NEXT) + + /** + * Converts a value type to an object reference (type O). + */ + final val Box = new OpCode() + opcode(Box, CEE_BOX , "box" , 0xFFFFFF8C, POP_1 , PUSH_REF , INLINE_TYPE , FLOW_NEXT) + + /** + * Pushes an object reference to a new zero-based, one-dimensional array whose elements + * are of a specific type onto the evaluation stack. + */ + final val Newarr = new OpCode() + opcode(Newarr, CEE_NEWARR, "newarr" , 0xFFFFFF8D, POP_I , PUSH_REF , INLINE_TYPE , FLOW_NEXT) + + /** + * Pushes the number of elements of a zero-based, one-dimensional array + * onto the evaluation stack. + */ + final val Ldlen = new OpCode() + opcode(Ldlen, CEE_LDLEN, "ldlen", 0xFFFFFF8E, POP_REF, PUSH_I,INLINE_NONE , FLOW_NEXT) + + /** + * Loads the address of the array element at a specified array index onto + * the top of the evaluation stack as type & (managed pointer). + */ + final val Ldelema = new OpCode() + opcode(Ldelema, CEE_LDELEMA, "ldelema" , 0xFFFFFF8F, POP_REF_I, PUSH_I, INLINE_TYPE , FLOW_NEXT) + + /** + * Loads the element with type natural int at a specified array index onto the top + * of the evaluation stack as a natural int. + */ + final val Ldelem_I = new OpCode() + opcode(Ldelem_I, CEE_LDELEM_I, "ldelem.i" , 0xFFFFFF97, POP_REF_I, PUSH_I, INLINE_NONE , FLOW_NEXT) + + /** + * Loads the element with type int8 at a specified array index onto the top of the + * evaluation stack as an int32. + */ + final val Ldelem_I1 = new OpCode() + opcode(Ldelem_I1, CEE_LDELEM_I1, "ldelem.i1" , 0xFFFFFF90, POP_REF_I, PUSH_I, INLINE_NONE , FLOW_NEXT) + + /** + * Loads the element with type int16 at a specified array index onto the top of + * the evaluation stack as an int32. + */ + final val Ldelem_I2 = new OpCode() + opcode(Ldelem_I2, CEE_LDELEM_I2, "ldelem.i2" , 0xFFFFFF92, POP_REF_I, PUSH_I, INLINE_NONE , FLOW_NEXT) + + /** + * Loads the element with type int32 at a specified array index onto the top of the + * evaluation stack as an int32. + */ + final val Ldelem_I4 = new OpCode() + opcode(Ldelem_I4, CEE_LDELEM_I4, "ldelem.i4" , 0xFFFFFF94, POP_REF_I, PUSH_I, INLINE_NONE , FLOW_NEXT) + + /** + * Loads the element with type int64 at a specified array index onto the top of the + * evaluation stack as an int64. + */ + final val Ldelem_I8 = new OpCode() + opcode(Ldelem_I8, CEE_LDELEM_I8, "ldelem.i8" , 0xFFFFFF96, POP_REF_I, PUSH_I8, INLINE_NONE , FLOW_NEXT) + + /** + * Loads the element with type float32 at a specified array index onto the top of the + * evaluation stack as type F (float) + */ + final val Ldelem_R4 = new OpCode() + opcode(Ldelem_R4, CEE_LDELEM_R4, "ldelem.r4" , 0xFFFFFF98, POP_REF_I, PUSH_R4, INLINE_NONE , FLOW_NEXT) + + /** + * Loads the element with type float64 at a specified array index onto the top of the + * evaluation stack as type F (float) . + */ + final val Ldelem_R8 = new OpCode() + opcode(Ldelem_R8, CEE_LDELEM_R8, "ldelem.r8" , 0xFFFFFF99, POP_REF_I, PUSH_R8, INLINE_NONE , FLOW_NEXT) + + /** + * Loads the element containing an object reference at a specified array index onto + * the top of the evaluation stack as type O (object reference). + */ + final val Ldelem_Ref = new OpCode() + opcode(Ldelem_Ref, CEE_LDELEM_REF, "ldelem.ref", 0xFFFFFF9A, POP_REF_I, PUSH_REF, INLINE_NONE , FLOW_NEXT) + + /** + * Loads the element with type unsigned int8 at a specified array index onto the top + * of the evaluation stack as an int32. + */ + final val Ldelem_U1 = new OpCode() + opcode(Ldelem_U1, CEE_LDELEM_U1, "ldelem.u1" , 0xFFFFFF91, POP_REF_I, PUSH_I, INLINE_NONE , FLOW_NEXT) + + /** + * Loads the element with type unsigned int16 at a specified array index onto the top + * of the evaluation stack as an int32. + */ + final val Ldelem_U2 = new OpCode() + opcode(Ldelem_U2, CEE_LDELEM_U2, "ldelem.u2" , 0xFFFFFF93, POP_REF_I, PUSH_I, INLINE_NONE , FLOW_NEXT) + + /** + * Loads the element with type unsigned int32 at a specified array index onto the top + * of the evaluation stack as an int32. + */ + final val Ldelem_U4 = new OpCode() + opcode(Ldelem_U4, CEE_LDELEM_U4, "ldelem.u4" , 0xFFFFFF95, POP_REF_I, PUSH_I, INLINE_NONE , FLOW_NEXT) + + /** + * Replaces the array element at a given index with the natural int value on + * the evaluation stack. + */ + final val Stelem_I = new OpCode() + opcode(Stelem_I, CEE_STELEM_I, "stelem.i", 0xFFFFFF9B, POP_REF_I_I, PUSH_NONE, INLINE_NONE , FLOW_NEXT) + + /** + * Replaces the array element at a given index with the int8 value on the evaluation stack. + */ + final val Stelem_I1 = new OpCode() + opcode(Stelem_I1, CEE_STELEM_I1, "stelem.i1", 0xFFFFFF9C, POP_REF_I_I, PUSH_NONE, INLINE_NONE, FLOW_NEXT) + + /** + * Replaces the array element at a given index with the int16 value on the evaluation stack. + */ + final val Stelem_I2 = new OpCode() + opcode(Stelem_I2, CEE_STELEM_I2, "stelem.i2", 0xFFFFFF9D, POP_REF_I_I, PUSH_NONE, INLINE_NONE, FLOW_NEXT) + + /** + * Replaces the array element at a given index with the int32 value on the evaluation stack. + */ + final val Stelem_I4 = new OpCode() + opcode(Stelem_I4, CEE_STELEM_I4, "stelem.i4", 0xFFFFFF9E, POP_REF_I_I, PUSH_NONE, INLINE_NONE, FLOW_NEXT) + + /** + * Replaces the array element at a given index with the int64 value on the evaluation stack. + */ + final val Stelem_I8 = new OpCode() + opcode(Stelem_I8, CEE_STELEM_I8,"stelem.i8", 0xFFFFFF9F, POP_REF_I_I8, PUSH_NONE, INLINE_NONE, FLOW_NEXT) + + /** + * Replaces the array element at a given index with the float32 value on the evaluation stack. + */ + final val Stelem_R4 = new OpCode() + opcode(Stelem_R4, CEE_STELEM_R4,"stelem.r4", 0xFFFFFFA0, POP_REF_I_R4, PUSH_NONE, INLINE_NONE, FLOW_NEXT) + + /** + * Replaces the array element at a given index with the float64 value on the evaluation stack. + */ + final val Stelem_R8 = new OpCode() + opcode(Stelem_R8, CEE_STELEM_R8,"stelem.r8", 0xFFFFFFA1, POP_REF_I_R8, PUSH_NONE, INLINE_NONE, FLOW_NEXT) + + /** + * Replaces the array element at a given index with the object ref value (type O) + * on the evaluation stack. + */ + final val Stelem_Ref = new OpCode() + opcode(Stelem_Ref, CEE_STELEM_REF,"stelem.ref",0xFFFFFFA2,POP_REF_I_REF,PUSH_NONE, INLINE_NONE, FLOW_NEXT) + + /** + * Converts the signed value on top of the evaluation stack to signed int8 and + * extends it to int32, throwing OverflowException on overflow. + */ + final val Conv_Ovf_I1 = new OpCode() + opcode(Conv_Ovf_I1, CEE_CONV_OVF_I1, "conv.ovf.i1", 0xFFFFFFB3, POP_1, PUSH_I , INLINE_NONE , FLOW_NEXT) + + /** + * Converts the signed value on top of the evaluation stack to signed int16 and + * extending it to int32, throwing OverflowException on overflow. + */ + final val Conv_Ovf_I2 = new OpCode() + opcode(Conv_Ovf_I2, CEE_CONV_OVF_I2, "conv.ovf.i2", 0xFFFFFFB5, POP_1, PUSH_I , INLINE_NONE , FLOW_NEXT) + + /** + * Converts the signed value on top of the sevaluation tack to signed int32, + * throwing OverflowException on overflow. + */ + final val Conv_Ovf_I4 = new OpCode() + opcode(Conv_Ovf_I4, CEE_CONV_OVF_I4, "conv.ovf.i4", 0xFFFFFFB7, POP_1, PUSH_I , INLINE_NONE , FLOW_NEXT) + + /** + * Converts the signed value on top of the evaluation stack to signed int64, + * throwing OverflowException on overflow. + */ + final val Conv_Ovf_I8 = new OpCode() + opcode(Conv_Ovf_I8, CEE_CONV_OVF_I8, "conv.ovf.i8", 0xFFFFFFB9, POP_1, PUSH_I8, INLINE_NONE , FLOW_NEXT) + + /** + * Converts the signed value on top of the evaluation stack to unsigned int8 and + * extends it to int32, throwing OverflowException on overflow. + */ + final val Conv_Ovf_U1 = new OpCode() + opcode(Conv_Ovf_U1, CEE_CONV_OVF_U1, "conv.ovf.u1", 0xFFFFFFB4, POP_1, PUSH_I , INLINE_NONE , FLOW_NEXT) + + /** + * Converts the signed value on top of the evaluation stack to unsigned int16 and + * extends it to int32, throwing OverflowException on overflow. + */ + final val Conv_Ovf_U2 = new OpCode() + opcode(Conv_Ovf_U2, CEE_CONV_OVF_U2, "conv.ovf.u2", 0xFFFFFFB6, POP_1, PUSH_I , INLINE_NONE , FLOW_NEXT) + + /** + * Converts the signed value on top of the evaluation stack to unsigned int32, + * throwing OverflowException on overflow. + */ + final val Conv_Ovf_U4 = new OpCode() + opcode(Conv_Ovf_U4, CEE_CONV_OVF_U4, "conv.ovf.u4", 0xFFFFFFB8, POP_1, PUSH_I , INLINE_NONE , FLOW_NEXT) + + /** + * Converts the signed value on top of the evaluation stack to unsigned int64, + * throwing OverflowException on overflow. + */ + final val Conv_Ovf_U8 = new OpCode() + opcode(Conv_Ovf_U8, CEE_CONV_OVF_U8, "conv.ovf.u8", 0xFFFFFFBA, POP_1, PUSH_I8, INLINE_NONE , FLOW_NEXT) + + /** + * Retrieves the address (type &) embedded in a typed reference. + */ + final val Refanyval = new OpCode() + opcode(Refanyval, CEE_REFANYVAL, "refanyval", 0xFFFFFFC2, POP_1, PUSH_I , INLINE_TYPE , FLOW_NEXT) + + /** + * Retrieves the type token embedded in a typed reference . + */ + final val Refanytype = new OpCode() + opcode(Refanytype, CEE_REFANYTYPE, "refanytype", 0xFFFFFE1D, POP_1 , PUSH_I , INLINE_NONE, FLOW_NEXT) + + /** + * Throws ArithmeticException if value is not a finite number. + */ + final val Ckfinite = new OpCode() + opcode(Ckfinite, CEE_CKFINITE, "ckfinite" , 0xFFFFFFC3, POP_1, PUSH_R8 , INLINE_NONE , FLOW_NEXT) + + /** + * Pushes a typed reference to an instance of a specific type onto the evaluation stack. + */ + final val Mkrefany = new OpCode() + opcode(Mkrefany, CEE_MKREFANY, "mkrefany" , 0xFFFFFFC6, POP_I, PUSH_1 , INLINE_TYPE , FLOW_NEXT) + + /** + * Converts a metadata token to its runtime representation, pushing it onto the evaluation stack. + */ + final val Ldtoken = new OpCode() + opcode(Ldtoken, CEE_LDTOKEN , "ldtoken" , 0xFFFFFFD0, POP_NONE, PUSH_I, INLINE_TOKEN , FLOW_NEXT) + + /** + * Converts the value on top of the evaluation stack to unsigned int8, and extends it to int32. + */ + final val Conv_U1 = new OpCode() + opcode(Conv_U1, CEE_CONV_U1 , "conv.u1" , 0xFFFFFFD2, POP_1, PUSH_I, INLINE_NONE , FLOW_NEXT) + + /** + * Converts the value on top of the evaluation stack to unsigned int16, and extends it to int32. + */ + final val Conv_U2 = new OpCode() + opcode(Conv_U2, CEE_CONV_U2 , "conv.u2" , 0xFFFFFFD1, POP_1, PUSH_I, INLINE_NONE , FLOW_NEXT) + + /** + * Converts the value on top of the evaluation stack to natural int. + */ + final val Conv_I = new OpCode() + opcode(Conv_I, CEE_CONV_I , "conv.i" , 0xFFFFFFD3, POP_1, PUSH_I, INLINE_NONE , FLOW_NEXT) + + /** + * Converts the signed value on top of the evaluation stack to signed natural int, + * throwing OverflowException on overflow. + */ + final val Conv_Ovf_I = new OpCode() + opcode(Conv_Ovf_I, CEE_CONV_OVF_I , "conv.ovf.i", 0xFFFFFFD4, POP_1, PUSH_I, INLINE_NONE , FLOW_NEXT) + + /** + * Converts the signed value on top of the evaluation stack to unsigned natural int, + * throwing OverflowException on overflow. + */ + final val Conv_Ovf_U = new OpCode() + opcode(Conv_Ovf_U, CEE_CONV_OVF_U , "conv.ovf.u", 0xFFFFFFD5, POP_1, PUSH_I, INLINE_NONE , FLOW_NEXT) + + /** + * Adds two integers, performs an overflow check, and pushes the result + * onto the evaluation stack. + */ + final val Add_Ovf = new OpCode() + opcode(Add_Ovf, CEE_ADD_OVF , "add.ovf" , 0xFFFFFFD6, POP_1_1, PUSH_1, INLINE_NONE , FLOW_NEXT) + + /** + * Adds two unsigned integer values, performs an overflow check, and pushes the result + * onto the evaluation stack. + */ + final val Add_Ovf_Un = new OpCode() + opcode(Add_Ovf_Un, CEE_ADD_OVF_UN , "add.ovf.un", 0xFFFFFFD7, POP_1_1, PUSH_1, INLINE_NONE , FLOW_NEXT) + + /** + * Multiplies two integer values, performs an overflow check, and pushes the result + * onto the evaluation stack. + */ + final val Mul_Ovf = new OpCode() + opcode(Mul_Ovf, CEE_MUL_OVF , "mul.ovf" , 0xFFFFFFD8, POP_1_1, PUSH_1, INLINE_NONE , FLOW_NEXT) + + /** + * Multiplies two unsigned integer values , performs an overflow check , + * and pushes the result onto the evaluation stack. + */ + final val Mul_Ovf_Un = new OpCode() + opcode(Mul_Ovf_Un, CEE_MUL_OVF_UN , "mul.ovf.un", 0xFFFFFFD9, POP_1_1, PUSH_1, INLINE_NONE , FLOW_NEXT) + + /** + * Subtracts one integer value from another, performs an overflow check, + * and pushes the result onto the evaluation stack. + */ + final val Sub_Ovf = new OpCode() + opcode(Sub_Ovf, CEE_SUB_OVF , "sub.ovf" , 0xFFFFFFDA, POP_1_1, PUSH_1, INLINE_NONE , FLOW_NEXT) + + /** + * Subtracts one unsigned integer value from another, performs an overflow check, + * and pushes the result onto the evaluation stack. + */ + final val Sub_Ovf_Un = new OpCode() + opcode(Sub_Ovf_Un, CEE_SUB_OVF_UN, "sub.ovf.un", 0xFFFFFFDB, POP_1_1, PUSH_1, INLINE_NONE , FLOW_NEXT) + + /** + * Transfers control from the fault or finally clause of an exception block back to + * the Common Language Infrastructure (CLI) exception handler. + */ + final val Endfinally = new OpCode() + opcode(Endfinally, CEE_ENDFINALLY, "endfinally", 0xFFFFFFDC, POP_NONE, PUSH_NONE, INLINE_NONE, FLOW_RETURN) + + /** + * Exits a protected region of code, unconditionally tranferring control + * to a specific target instruction. + */ + final val Leave = new OpCode() + opcode(Leave, CEE_LEAVE, "leave", 0xFFFFFFDD, POP_NONE, PUSH_NONE, INLINE_TARGET, FLOW_BRANCH) + + /** + * Exits a protected region of code, unconditionally tranferring control + * to a target instruction (short form). + */ + final val Leave_S = new OpCode() + opcode(Leave_S, CEE_LEAVE_S, "leave.s", 0xFFFFFFDE, POP_NONE, PUSH_NONE, INLINE_TARGET_S, FLOW_BRANCH) + + /** + * Stores a value of type natural int at a supplied address. + */ + final val Stind_I = new OpCode() + opcode(Stind_I, CEE_STIND_I, "stind.i", 0xFFFFFFDF, POP_I_I , PUSH_NONE, INLINE_NONE, FLOW_NEXT) + + /** + * Converts the value on top of the evaluation stack to unsigned natural int, + * and extends it to natural int. + */ + final val Conv_U = new OpCode() + opcode(Conv_U, CEE_CONV_U, "conv.u", 0xFFFFFFE0, POP_1 , PUSH_I , INLINE_NONE, FLOW_NEXT) + + /** + * Returns an unmanaged pointer to the argument list of the current method. + */ + final val Arglist = new OpCode() + opcode(Arglist, CEE_ARGLIST, "arglist" , 0xFFFFFE00, POP_NONE, PUSH_I , INLINE_NONE, FLOW_NEXT) + + /** + * Compares two values. If they are equal, the integer value 1 (int32) is pushed + * onto the evaluation stack otherwise 0 (int32) is pushed onto the evaluation stack. + */ + final val Ceq = new OpCode() + opcode(Ceq, CEE_CEQ, "ceq", 0xFFFFFE01, POP_1_1 , PUSH_I, INLINE_NONE, FLOW_NEXT) + + /** + * Compares two values. If the first value is greater than the second, + * the integer value 1 (int32) is pushed onto the evaluation stack + * otherwise 0 (int32) is pushed onto the evaluation stack. + */ + final val Cgt = new OpCode() + opcode(Cgt, CEE_CGT, "cgt", 0xFFFFFE02, POP_1_1 , PUSH_I, INLINE_NONE, FLOW_NEXT) + + /** + * Compares two unsigned or unordered values. If the first value is greater than + * the second, the integer value 1 (int32) is pushed onto the evaluation stack + * otherwise 0 (int32) is pushed onto the evaluation stack. + */ + final val Cgt_Un = new OpCode() + opcode(Cgt_Un, CEE_CGT_UN, "cgt.un", 0xFFFFFE03, POP_1_1 , PUSH_I, INLINE_NONE, FLOW_NEXT) + + /** + * Compares two values. If the first value is less than the second, + * the integer value 1 (int32) is pushed onto the evaluation stack + * otherwise 0 (int32) is pushed onto the evaluation stack. + */ + final val Clt = new OpCode() + opcode(Clt, CEE_CLT, "clt" , 0xFFFFFE04, POP_1_1 , PUSH_I , INLINE_NONE, FLOW_NEXT) + + /** + * Compares the unsigned or unordered values value1 and value2. If value1 is + * less than value2, then the integer value 1 (int32) is pushed onto the + * evaluation stack otherwise 0 (int32) is pushed onto the evaluation stack. + */ + final val Clt_Un = new OpCode() + opcode(Clt_Un, CEE_CLT_UN , "clt.un" , 0xFFFFFE05, POP_1_1 , PUSH_I , INLINE_NONE, FLOW_NEXT) + + /** + * Pushes an unmanaged pointer (type natural int) to the native code implementing + * a specific method onto the evaluation stack. + */ + final val Ldftn = new OpCode() + opcode(Ldftn, CEE_LDFTN , "ldftn" , 0xFFFFFE06, POP_NONE, PUSH_I , INLINE_METHOD, FLOW_NEXT) + + /** + * Pushes an unmanaged pointer (type natural int) to the native code implementing + * a particular virtual method associated with a specified object onto the evaluation stack. + */ + final val Ldvirtftn = new OpCode() + opcode(Ldvirtftn, CEE_LDVIRTFTN, "ldvirtftn", 0xFFFFFE07, POP_REF , PUSH_I , INLINE_METHOD, FLOW_NEXT) + + /** + * Loads an argument (referenced by a specified index value) onto the stack. + */ + final val Ldarg = new OpCode() + opcode(Ldarg, CEE_LDARG , "ldarg" , 0xFFFFFE09, POP_NONE, PUSH_1 , INLINE_VARIABLE , FLOW_NEXT) + + /** + * Load an argument address onto the evaluation stack. + */ + final val Ldarga = new OpCode() + opcode(Ldarga, CEE_LDARGA , "ldarga", 0xFFFFFE0A, POP_NONE, PUSH_I, INLINE_VARIABLE , FLOW_NEXT) + + /** + * Loads the local variable at a specific index onto the evaluation stack. + */ + final val Ldloc = new OpCode() + opcode(Ldloc, CEE_LDLOC, "ldloc", 0xFFFFFE0C, POP_NONE, PUSH_1 , INLINE_VARIABLE , FLOW_NEXT) + + /** + * Loads the address of the local variable at a specific index onto the evaluation stack. + */ + final val Ldloca = new OpCode() + opcode(Ldloca, CEE_LDLOCA, "ldloca", 0xFFFFFE0D, POP_NONE, PUSH_I, INLINE_VARIABLE , FLOW_NEXT) + + /** + * Stores the value on top of the evaluation stack in the argument slot at a specified index. + */ + final val Starg = new OpCode() + opcode(Starg, CEE_STARG, "starg", 0xFFFFFE0B, POP_1 , PUSH_NONE, INLINE_VARIABLE , FLOW_NEXT) + + /** + * Pops the current value from the top of the evaluation stack and stores it in a + * the local variable list at a specified index. + */ + final val Stloc = new OpCode() + opcode(Stloc, CEE_STLOC, "stloc", 0xFFFFFE0E, POP_1 , PUSH_NONE, INLINE_VARIABLE , FLOW_NEXT) + + /** + * Allocates a certain number of bytes from the local dynamic memory pool and pushes the + * address (a transient pointer, type *) of the first allocated byte onto the evaluation stack. + */ + final val Localloc = new OpCode() + opcode(Localloc, CEE_LOCALLOC, "localloc" , 0xFFFFFE0F, POP_I, PUSH_I, INLINE_NONE, FLOW_NEXT) + + /** + * Transfers control from the filter clause of an exception back to the + * Common Language Infrastructure (CLI) exception handler. + */ + final val Endfilter = new OpCode() + opcode(Endfilter, CEE_ENDFILTER, "endfilter" , 0xFFFFFE11, POP_I , PUSH_NONE, INLINE_NONE, FLOW_RETURN) + + /** + * Indicates that an address currently atop the evaluation stack might not be aligned + * to the natural size of the immediately following ldind, stind, ldfld, stfld, ldobj, + * stobj, initblk, or cpblk instruction. + */ + final val Unaligned = new OpCode() + opcode(Unaligned, CEE_UNALIGNED, "unaligned.", 0xFFFFFE12, POP_NONE, PUSH_NONE, INLINE_I_S , FLOW_META) + + /** + * Specifies that an address currently atop the evaluation stack might be volatile, + * and the results of reading that location cannot be cached or that multiple stores + * to that location cannot be suppressed. + */ + final val Volatile = new OpCode() + opcode(Volatile, CEE_VOLATILE, "volatile." , 0xFFFFFE13, POP_NONE, PUSH_NONE, INLINE_NONE, FLOW_META) + + /** + * Performs a postfixed method call instruction such that the current method's stack + * frame is removed before the actual call instruction is executed. + */ + final val Tailcall = new OpCode() + opcode(Tailcall, CEE_TAILCALL, "tail." , 0xFFFFFE14, POP_NONE, PUSH_NONE, INLINE_NONE, FLOW_META) + + /** + * Initializes all the fields of the object at a specific address to a null reference + * or a 0 of the appropriate primitive type. + */ + final val Initobj = new OpCode() + opcode(Initobj, CEE_INITOBJ , "initobj" , 0xFFFFFE15, POP_I , PUSH_NONE, INLINE_TYPE, FLOW_NEXT) + + /** + * Copies a specified number bytes from a source address to a destination address . + */ + final val Cpblk = new OpCode() + opcode(Cpblk, CEE_CPBLK , "cpblk" , 0xFFFFFE17, POP_I_I_I, PUSH_NONE, INLINE_NONE, FLOW_NEXT) + + /** + * Initializes a specified block of memory at a specific address to a given size + * and initial value. + */ + final val Initblk = new OpCode() + opcode(Initblk, CEE_INITBLK , "initblk" , 0xFFFFFE18, POP_I_I_I, PUSH_NONE, INLINE_NONE, FLOW_NEXT) + + /** + * Rethrows the current exception. + */ + final val Rethrow = new OpCode() + opcode(Rethrow, CEE_RETHROW , "rethrow", 0xFFFFFE1A, POP_NONE , PUSH_NONE, INLINE_NONE, FLOW_THROW) + + /** + * Pushes the size, in bytes, of a supplied value type onto the evaluation stack. + */ + final val Sizeof = new OpCode() + opcode(Sizeof, CEE_SIZEOF, "sizeof", 0xFFFFFE1C, POP_NONE , PUSH_I , INLINE_TYPE, FLOW_NEXT) + + + + //########################################################################## +} diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/OpCodes.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/OpCodes.scala new file mode 100644 index 0000000000..6a94c6fef6 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/OpCodes.scala @@ -0,0 +1,1196 @@ +/* + * System.Reflection.Emit-like API for writing .NET assemblies to MSIL + */ + +// $Id: OpCodes.java 168 2005-12-12 14:20:06Z mihaylov $ + +package ch.epfl.lamp.compiler.msil.emit + + +/** + * Provides field representations of the Microsoft Intermediate Language (MSIL) + * instructions for emission by the ILGenerator class members (such as Emit). + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +object OpCodes { + + //########################################################################## + + /** + * Adds two values and pushes the result onto the evaluation stack. + */ + final val Add = OpCode.Add + + /** + * Fills space if bytecodes are patched. No meaningful operation is performed + * although a processing cycle can be consumed. + */ + final val Nop = OpCode.Nop + + /** + * Signals the Common Language Infrastructure (CLI) to inform the debugger that + * a break point has been tripped. + */ + final val Break = OpCode.Break + + /** + * Loads the argument at index 0 onto the evaluation stack. + */ + final val Ldarg_0 = OpCode.Ldarg_0 + + /** + * Loads the argument at index 1 onto the evaluation stack. + */ + final val Ldarg_1 = OpCode.Ldarg_1 + + /** + * Loads the argument at index 2 onto the evaluation stack. + */ + final val Ldarg_2 = OpCode.Ldarg_2 + + /** + * Loads the argument at index 3 onto the evaluation stack. + */ + final val Ldarg_3 = OpCode.Ldarg_3 + + /** + * Loads the local variable at index 0 onto the evaluation stack. + */ + final val Ldloc_0 = OpCode.Ldloc_0 + + /** + * Loads the local variable at index 1 onto the evaluation stack. + */ + final val Ldloc_1 = OpCode.Ldloc_1 + + /** + * Loads the local variable at index 2 onto the evaluation stack. + */ + final val Ldloc_2 = OpCode.Ldloc_2 + + /** + * Loads the local variable at index 3 onto the evaluation stack. + */ + final val Ldloc_3 = OpCode.Ldloc_3 + + /** + * Pops the current value from the top of the evaluation stack and + * stores it in a the local variable list at index 0. + */ + final val Stloc_0 = OpCode.Stloc_0 + + /** + * Pops the current value from the top of the evaluation stack and + * stores it in a the local variable list at index 1. + */ + final val Stloc_1 = OpCode.Stloc_1 + + /** + * Pops the current value from the top of the evaluation stack and + * stores it in a the local variable list at index 2. + */ + final val Stloc_2 = OpCode.Stloc_2 + + /** + * Pops the current value from the top of the evaluation stack and + * stores it in a the local variable list at index 3. + */ + final val Stloc_3 = OpCode.Stloc_3 + + /** + * Loads the argument (referenced by a specified short form index) + * onto the evaluation stack. + */ + final val Ldarg_S = OpCode.Ldarg_S + + /** + * Load an argument address, in short form, onto the evaluation stack. + */ + final val Ldarga_S = OpCode.Ldarga_S + + /** + * Loads the local variable at a specific index onto the evaluation stack, + * short form. + */ + final val Ldloc_S = OpCode.Ldloc_S + + /** + * Loads the address of the local variable at a specific index onto + * the evaluation stack, short form. + */ + final val Ldloca_S = OpCode.Ldloca_S + + /** + * Stores the value on top of the evaluation stack in the argument slot + * at a specified index, short form. + */ + final val Starg_S = OpCode.Starg_S + + /** + * Pops the current value from the top of the evaluation stack and stores it + * in a the local variable list at index (short form). + */ + final val Stloc_S = OpCode.Stloc_S + + /** + * Pushes a null reference (type O) onto the evaluation stack. + */ + final val Ldnull = OpCode.Ldnull + + /** + * Pushes the integer value of -1 onto the evaluation stack as an int32. + */ + final val Ldc_I4_M1 = OpCode.Ldc_I4_M1 + + /** + * Pushes the integer value of 0 onto the evaluation stack as an int32. + */ + final val Ldc_I4_0 = OpCode.Ldc_I4_0 + + /** + * Pushes the integer value of 1 onto the evaluation stack as an int32. + */ + final val Ldc_I4_1 = OpCode.Ldc_I4_1 + + /** + * Pushes the integer value of 2 onto the evaluation stack as an int32. + */ + final val Ldc_I4_2 = OpCode.Ldc_I4_2 + + /** + * Pushes the integer value of 3 onto the evaluation stack as an int32. + */ + final val Ldc_I4_3 = OpCode.Ldc_I4_3 + + /** + * Pushes the integer value of 4 onto the evaluation stack as an int32. + */ + final val Ldc_I4_4 = OpCode.Ldc_I4_4 + + /** + * Pushes the integer value of 5 onto the evaluation stack as an int32. + */ + final val Ldc_I4_5 = OpCode.Ldc_I4_5 + + /** + * Pushes the integer value of 6 onto the evaluation stack as an int32. + */ + final val Ldc_I4_6 = OpCode.Ldc_I4_6 + + /** + * Pushes the integer value of 7 onto the evaluation stack as an int32. + */ + final val Ldc_I4_7 = OpCode.Ldc_I4_7 + + /** + * Pushes the integer value of 8 onto the evaluation stack as an int32. + */ + final val Ldc_I4_8 = OpCode.Ldc_I4_8 + + /** + * Pushes the supplied int8 value onto the evaluation stack as an int32, short form. + */ + final val Ldc_I4_S = OpCode.Ldc_I4_S + + /** + * Pushes a supplied value of type int32 onto the evaluation stack as an int32. + */ + final val Ldc_I4 = OpCode.Ldc_I4 + + /** + * Pushes a supplied value of type int64 onto the evaluation stack as an int64. + */ + final val Ldc_I8 = OpCode.Ldc_I8 + + /** + * Pushes a supplied value of type float32 onto the evaluation stack as type F (float). + */ + final val Ldc_R4 = OpCode.Ldc_R4 + + /** + * Pushes a supplied value of type float64 onto the evaluation stack as type F (float). + */ + final val Ldc_R8 = OpCode.Ldc_R8 + + /** + * Copies the current topmost value on the evaluation stack, and then pushes the copy + * onto the evaluation stack. + */ + final val Dup = OpCode.Dup + + /** + * Removes the value currently on top of the evaluation stack. + */ + final val Pop = OpCode.Pop + + /** + * Exits current method and jumps to specified method. + */ + final val Jmp = OpCode.Jmp + + /** + * Calls the method indicated by the passed method descriptor. + */ + final val Call = OpCode.Call + + /** + * Calls the method indicated on the evaluation stack (as a pointer to an entry point) + * with arguments described by a calling convention. + */ + final val Calli = OpCode.Calli + + /** + * Returns from the current method, pushing a return value (if present) from the caller's + * evaluation stack onto the callee's evaluation stack. + */ + final val Ret = OpCode.Ret + + /** + * Unconditionally transfers control to a target instruction (short form). + */ + final val Br_S = OpCode.Br_S + + /** + * Transfers control to a target instruction if value is false, a null reference, or zero. + */ + final val Brfalse_S = OpCode.Brfalse_S + + /** + * Transfers control to a target instruction (short form) if value is true, not null, or non-zero. + */ + final val Brtrue_S = OpCode.Brtrue_S + + /** + * Transfers control to a target instruction (short form) if two values are equal. + */ + final val Beq_S = OpCode.Beq_S + + /** + * Transfers control to a target instruction (short form) if the first value is greater than + * or equal to the second value. + */ + final val Bge_S = OpCode.Bge_S + + /** + * Transfers control to a target instruction (short form) if the first value is greater than + * the second value. + */ + final val Bgt_S = OpCode.Bgt_S + + /** + * Transfers control to a target instruction (short form) if the first value is less than + * or equal to the second value. + */ + final val Ble_S = OpCode.Ble_S + + /** + * Transfers control to a target instruction (short form) if the first value is less than + * the second value. + */ + final val Blt_S = OpCode.Blt_S + + /** + * Transfers control to a target instruction (short form) when two unsigned integer values + * or unordered float values are not equal. + */ + final val Bne_Un_S = OpCode.Bne_Un_S + + /** + * Transfers control to a target instruction (short form) if if the the first value is greather + * than the second value, when comparing unsigned integer values or unordered float values. + */ + final val Bge_Un_S = OpCode.Bge_Un_S + + /** + * Transfers control to a target instruction (short form) if the first value is greater than + * the second value, when comparing unsigned integer values or unordered float values. + */ + final val Bgt_Un_S = OpCode.Bgt_Un_S + + /** + * Transfers control to a target instruction (short form) if the first value is less than + * or equal to the second value, when comparing unsigned integer values or unordered float values. + */ + final val Ble_Un_S = OpCode.Ble_Un_S + + /** + * Transfers control to a target instruction (short form) if the first value is less than + * the second value, when comparing unsigned integer values or unordered float values. + */ + final val Blt_Un_S = OpCode.Blt_Un_S + + /** + * Unconditionally transfers control to a target instruction. + */ + final val Br = OpCode.Br + + /** + * Transfers control to a target instruction if value is false, a null reference + * (Nothing in Visual Basic), or zero. + */ + final val Brfalse = OpCode.Brfalse + + /** + * Transfers control to a target instruction if value is true, not null, or non-zero. + */ + final val Brtrue = OpCode.Brtrue + + /** + * Transfers control to a target instruction if two values are equal. + */ + final val Beq = OpCode.Beq + + /** + * Transfers control to a target instruction if the first value is greater than or + * equal to the second value. + */ + final val Bge = OpCode.Bge + + /** + * Transfers control to a target instruction if the first value is greater than the second value. + */ + final val Bgt = OpCode.Bgt + + /** + * Transfers control to a target instruction if the first value is less than or equal + * to the second value. + */ + final val Ble = OpCode.Ble + + /** + * Transfers control to a target instruction if the first value is less than the second value. + */ + final val Blt = OpCode.Blt + + /** + * Transfers control to a target instruction when two unsigned integer values or + * unordered float values are not equal. + */ + final val Bne_Un = OpCode.Bne_Un + + /** + * Transfers control to a target instruction if the the first value is greather than + * the second value, when comparing unsigned integer values or unordered float values. + */ + final val Bge_Un = OpCode.Bge_Un + + /** + * Transfers control to a target instruction if the first value is greater than the + * second value, when comparing unsigned integer values or unordered float values. + */ + final val Bgt_Un = OpCode.Bgt_Un + + /** + * Transfers control to a target instruction if the first value is less than or equal to + * the second value, when comparing unsigned integer values or unordered float values. + */ + final val Ble_Un = OpCode.Ble_Un + + /** + * Transfers control to a target instruction if the first value is less than the second value, + * when comparing unsigned integer values or unordered float values. + */ + final val Blt_Un = OpCode.Blt_Un + + /** + * Implements a jump table. + */ + final val Switch = OpCode.Switch + + /** + * Loads a value of type int8 as an int32 onto the evaluation stack indirectly. + */ + final val Ldind_I1 = OpCode.Ldind_I1 + + /** + * Loads a value of type int16 as an int32 onto the evaluation stack indirectly. + */ + final val Ldind_I2 = OpCode.Ldind_I2 + + /** + * Loads a value of type int32 as an int32 onto the evaluation stack indirectly. + */ + final val Ldind_I4 = OpCode.Ldind_I4 + + /** + * Loads a value of type int64 as an int64 onto the evaluation stack indirectly. + */ + final val Ldind_I8 = OpCode.Ldind_I8 + + /** + * Loads a value of type natural int as a natural int onto the evaluation stack indirectly. + */ + final val Ldind_I = OpCode.Ldind_I + + /** + * Loads a value of type float32 as a type F (float) onto the evaluation stack indirectly. + */ + final val Ldind_R4 = OpCode.Ldind_R4 + + /** + * Loads a value of type float64 as a type F (float) onto the evaluation stack indirectly. + */ + final val Ldind_R8 = OpCode.Ldind_R8 + + /** + * Loads an object reference as a type O (object reference) onto the evaluation stack indirectly. + */ + final val Ldind_Ref = OpCode.Ldind_Ref + + /** + * Loads a value of type unsigned int8 as an int32 onto the evaluation stack indirectly. + */ + final val Ldind_U1 = OpCode.Ldind_U1 + + /** + * Loads a value of type unsigned int16 as an int32 onto the evaluation stack indirectly. + */ + final val Ldind_U2 = OpCode.Ldind_U2 + + /** + * Loads a value of type unsigned int32 as an int32 onto the evaluation stack indirectly. + */ + final val Ldind_U4 = OpCode.Ldind_U4 + + /** + * Stores a object reference value at a supplied address. + */ + final val Stind_Ref = OpCode.Stind_Ref + + /** + * Stores a value of type int8 at a supplied address. + */ + final val Stind_I1 = OpCode.Stind_I1 + + /** + * Stores a value of type int16 at a supplied address. + */ + final val Stind_I2 = OpCode.Stind_I2 + + /** + * Stores a value of type int32 at a supplied address. + */ + final val Stind_I4 = OpCode.Stind_I4 + + /** + * Stores a value of type int64 at a supplied address. + */ + final val Stind_I8 = OpCode.Stind_I8 + + /** + * Stores a value of type float32 at a supplied address. + */ + final val Stind_R4 = OpCode.Stind_R4 + + /** + * Stores a value of type float64 at a supplied address. + */ + final val Stind_R8 = OpCode.Stind_R8 + + /** + * Subtracts one value from another and pushes the result onto the evaluation stack. + */ + final val Sub = OpCode.Sub + + /** + * Multiplies two values and pushes the result on the evaluation stack. + */ + final val Mul = OpCode.Mul + + /** + * Divides two values and pushes the result as a floating-point (type F) or + * quotient (type int32) onto the evaluation stack. + */ + final val Div = OpCode.Div + + /** + * Divides two unsigned integer values and pushes the result (int32) onto the evaluation stack. + */ + final val Div_Un = OpCode.Div_Un + + /** + * Divides two values and pushes the remainder onto the evaluation stack. + */ + final val Rem = OpCode.Rem + + /** + * Divides two unsigned values and pushes the remainder onto the evaluation stack. + */ + final val Rem_Un = OpCode.Rem_Un + + /** + * Computes the bitwise AND of two values and pushes the result onto the evalution stack. + */ + final val And = OpCode.And + + /** + * Compute the bitwise complement of the two integer values on top of the stack and + * pushes the result onto the evaluation stack. + */ + final val Or = OpCode.Or + + /** + * Computes the bitwise XOR of the top two values on the evaluation stack, + * pushing the result onto the evaluation stack. + */ + final val Xor = OpCode.Xor + + /** + * Shifts an integer value to the left (in zeroes) by a specified number of bits, + * pushing the result onto the evaluation stack. + */ + final val Shl = OpCode.Shl + + /** + * Shifts an integer value (in sign) to the right by a specified number of bits, + * pushing the result onto the evaluation stack. + */ + final val Shr = OpCode.Shr + + /** + * Shifts an unsigned integer value (in zeroes) to the right by a specified number of bits, + * pushing the result onto the evaluation stack. + */ + final val Shr_Un = OpCode.Shr_Un + + /** + * Negates a value and pushes the result onto the evaluation stack. + */ + final val Neg = OpCode.Neg + + /** + * Computes the bitwise complement of the integer value on top of the stack and pushes + * the result onto the evaluation stack as the same type. + */ + final val Not = OpCode.Not + + /** + * Converts the value on top of the evaluation stack to int8, then extends (pads) it to int32. + */ + final val Conv_I1 = OpCode.Conv_I1 + + /** + * Converts the value on top of the evaluation stack to int16, then extends (pads) it to int32. + */ + final val Conv_I2 = OpCode.Conv_I2 + + /** + * Converts the value on top of the evaluation stack to int32. + */ + final val Conv_I4 = OpCode.Conv_I4 + + /** + * Converts the value on top of the evaluation stack to int64. + */ + final val Conv_I8 = OpCode.Conv_I8 + + /** + * Converts the value on top of the evaluation stack to float32. + */ + final val Conv_R4 = OpCode.Conv_R4 + + /** + * Converts the value on top of the evaluation stack to float64. + */ + final val Conv_R8 = OpCode.Conv_R8 + + /** + * Converts the value on top of the evaluation stack to unsigned int32, and extends it to int32. + */ + final val Conv_U4 = OpCode.Conv_U4 + + /** + * Converts the value on top of the evaluation stack to unsigned int64, and extends it to int64. + */ + final val Conv_U8 = OpCode.Conv_U8 + + /** + * Calls a late-bound method on an object, pushing the return value onto the evaluation stack. + */ + final val Callvirt = OpCode.Callvirt + + /** + * Copies the value type located at the address of an object (type &, * or natural int) + * to the address of the destination object (type &, * or natural int). + */ + final val Cpobj = OpCode.Cpobj + + /** + * Copies the value type object pointed to by an address to the top of the evaluation stack. + */ + final val Ldobj = OpCode.Ldobj + + /** + * Pushes a new object reference to a string literal stored in the metadata. + */ + final val Ldstr = OpCode.Ldstr + + /** + * Creates a new object or a new instance of a value type, pushing an object reference + * (type O) onto the evaluation stack. + */ + final val Newobj = OpCode.Newobj + + /** + * Attempts to cast an object passed by reference to the specified class. + */ + final val Castclass = OpCode.Castclass + + /** + * Tests whether an object reference (type O) is an instance of a particular class. + */ + final val Isinst = OpCode.Isinst + + /** + * Converts the unsigned integer value on top of the evaluation stack to float32. + */ + final val Conv_R_Un = OpCode.Conv_R_Un + + /** + * Converts the boxed representation of a value type to its unboxed form. + */ + final val Unbox = OpCode.Unbox + + /** + * Throws the exception object currently on the evaluation stack. + */ + final val Throw = OpCode.Throw + + /** + * Finds the value of a field in the object whose reference is currently + * on the evaluation stack. + */ + final val Ldfld = OpCode.Ldfld + + /** + * Finds the address of a field in the object whose reference is currently + * on the evaluation stack. + */ + final val Ldflda = OpCode.Ldflda + + /** + * Pushes the value of a static field onto the evaluation stack. + */ + final val Ldsfld = OpCode.Ldsfld + + /** + * Pushes the address of a static field onto the evaluation stack. + */ + final val Ldsflda = OpCode.Ldsflda + + /** + * Replaces the value stored in the field of an object reference or pointer with a new value. + */ + final val Stfld = OpCode.Stfld + + /** + * Replaces the value of a static field with a value from the evaluation stack. + */ + final val Stsfld = OpCode.Stsfld + + /** + * Copies a value of a specified type from the evaluation stack into a supplied memory address. + */ + final val Stobj = OpCode.Stobj + + /** + * Converts the unsigned value on top of the evaluation stack to signed int8 and + * extends it to int32, throwing OverflowException on overflow. + */ + final val Conv_Ovf_I1_Un = OpCode.Conv_Ovf_I1_Un + + /** + * Converts the unsigned value on top of the evaluation stack to signed int16 and + * extends it to int32, throwing OverflowException on overflow. + */ + final val Conv_Ovf_I2_Un = OpCode.Conv_Ovf_I2_Un + + /** + * Converts the unsigned value on top of the evaluation stack to signed int32, + * throwing OverflowException on overflow. + */ + final val Conv_Ovf_I4_Un = OpCode.Conv_Ovf_I4_Un + + /** + * Converts the unsigned value on top of the evaluation stack to signed int64, + * throwing OverflowException on overflow. + */ + final val Conv_Ovf_I8_Un = OpCode.Conv_Ovf_I8_Un + + /** + * Converts the unsigned value on top of the evaluation stack to signed natural int, + * throwing OverflowException on overflow. + */ + final val Conv_Ovf_I_Un = OpCode.Conv_Ovf_I_Un + + /** + * Converts the unsigned value on top of the evaluation stack to unsigned int8 and + * extends it to int32, throwing OverflowException on overflow. + */ + final val Conv_Ovf_U1_Un = OpCode.Conv_Ovf_U1_Un + + /** + * Converts the unsigned value on top of the evaluation stack to unsigned int16 and + * extends it to int32, throwing OverflowException on overflow. + */ + final val Conv_Ovf_U2_Un = OpCode.Conv_Ovf_U2_Un + + /** + * Converts the unsigned value on top of the evaluation stack to unsigned int32, + * throwing OverflowException on overflow. + */ + final val Conv_Ovf_U4_Un = OpCode.Conv_Ovf_U4_Un + + /** + * Converts the unsigned value on top of the evaluation stack to unsigned int64, + * throwing OverflowException on overflow. + */ + final val Conv_Ovf_U8_Un = OpCode.Conv_Ovf_U8_Un + + /** + * Converts the unsigned value on top of the evaluation stack to unsigned natural int, + * throwing OverflowException on overflow. + */ + final val Conv_Ovf_U_Un = OpCode.Conv_Ovf_U_Un + + /** + * Converts a value type to an object reference (type O). + */ + final val Box = OpCode.Box + + /** + * Pushes an object reference to a new zero-based, one-dimensional array whose elements + * are of a specific type onto the evaluation stack. + */ + final val Newarr = OpCode.Newarr + + /** + * Pushes the number of elements of a zero-based, one-dimensional array + * onto the evaluation stack. + */ + final val Ldlen = OpCode.Ldlen + + /** + * Loads the address of the array element at a specified array index onto + * the top of the evaluation stack as type & (managed pointer). + */ + final val Ldelema = OpCode.Ldelema + + /** + * Loads the element with type natural int at a specified array index onto the top + * of the evaluation stack as a natural int. + */ + final val Ldelem_I = OpCode.Ldelem_I + + /** + * Loads the element with type int8 at a specified array index onto the top of the + * evaluation stack as an int32. + */ + final val Ldelem_I1 = OpCode.Ldelem_I1 + + /** + * Loads the element with type int16 at a specified array index onto the top of + * the evaluation stack as an int32. + */ + final val Ldelem_I2 = OpCode.Ldelem_I2 + + /** + * Loads the element with type int32 at a specified array index onto the top of the + * evaluation stack as an int32. + */ + final val Ldelem_I4 = OpCode.Ldelem_I4 + + /** + * Loads the element with type int64 at a specified array index onto the top of the + * evaluation stack as an int64. + */ + final val Ldelem_I8 = OpCode.Ldelem_I8 + + /** + * Loads the element with type float32 at a specified array index onto the top of the + * evaluation stack as type F (float) + */ + final val Ldelem_R4 = OpCode.Ldelem_R4 + + /** + * Loads the element with type float64 at a specified array index onto the top of the + * evaluation stack as type F (float) . + */ + final val Ldelem_R8 = OpCode.Ldelem_R8 + + /** + * Loads the element containing an object reference at a specified array index onto + * the top of the evaluation stack as type O (object reference). + */ + final val Ldelem_Ref = OpCode.Ldelem_Ref + + /** + * Loads the element with type unsigned int8 at a specified array index onto the top + * of the evaluation stack as an int32. + */ + final val Ldelem_U1 = OpCode.Ldelem_U1 + + /** + * Loads the element with type unsigned int16 at a specified array index onto the top + * of the evaluation stack as an int32. + */ + final val Ldelem_U2 = OpCode.Ldelem_U2 + + /** + * Loads the element with type unsigned int32 at a specified array index onto the top + * of the evaluation stack as an int32. + */ + final val Ldelem_U4 = OpCode.Ldelem_U4 + + /** + * Replaces the array element at a given index with the natural int value on + * the evaluation stack. + */ + final val Stelem_I = OpCode.Stelem_I + + /** + * Replaces the array element at a given index with the int8 value on the evaluation stack. + */ + final val Stelem_I1 = OpCode.Stelem_I1 + + /** + * Replaces the array element at a given index with the int16 value on the evaluation stack. + */ + final val Stelem_I2 = OpCode.Stelem_I2 + + /** + * Replaces the array element at a given index with the int32 value on the evaluation stack. + */ + final val Stelem_I4 = OpCode.Stelem_I4 + + /** + * Replaces the array element at a given index with the int64 value on the evaluation stack. + */ + final val Stelem_I8 = OpCode.Stelem_I8 + + /** + * Replaces the array element at a given index with the float32 value on the evaluation stack. + */ + final val Stelem_R4 = OpCode.Stelem_R4 + + /** + * Replaces the array element at a given index with the float64 value on the evaluation stack. + */ + final val Stelem_R8 = OpCode.Stelem_R8 + + /** + * Replaces the array element at a given index with the object ref value (type O) + * on the evaluation stack. + */ + final val Stelem_Ref = OpCode.Stelem_Ref + + /** + * Converts the signed value on top of the evaluation stack to signed int8 and + * extends it to int32, throwing OverflowException on overflow. + */ + final val Conv_Ovf_I1 = OpCode.Conv_Ovf_I1 + + /** + * Converts the signed value on top of the evaluation stack to signed int16 and + * extending it to int32, throwing OverflowException on overflow. + */ + final val Conv_Ovf_I2 = OpCode.Conv_Ovf_I2 + + /** + * Converts the signed value on top of the sevaluation tack to signed int32, + * throwing OverflowException on overflow. + */ + final val Conv_Ovf_I4 = OpCode.Conv_Ovf_I4 + + /** + * Converts the signed value on top of the evaluation stack to signed int64, + * throwing OverflowException on overflow. + */ + final val Conv_Ovf_I8 = OpCode.Conv_Ovf_I8 + + /** + * Converts the signed value on top of the evaluation stack to unsigned int8 and + * extends it to int32, throwing OverflowException on overflow. + */ + final val Conv_Ovf_U1 = OpCode.Conv_Ovf_U1 + + /** + * Converts the signed value on top of the evaluation stack to unsigned int16 and + * extends it to int32, throwing OverflowException on overflow. + */ + final val Conv_Ovf_U2 = OpCode.Conv_Ovf_U2 + + /** + * Converts the signed value on top of the evaluation stack to unsigned int32, + * throwing OverflowException on overflow. + */ + final val Conv_Ovf_U4 = OpCode.Conv_Ovf_U4 + + /** + * Converts the signed value on top of the evaluation stack to unsigned int64, + * throwing OverflowException on overflow. + */ + final val Conv_Ovf_U8 = OpCode.Conv_Ovf_U8 + + /** + * Retrieves the address (type &) embedded in a typed reference. + */ + final val Refanyval = OpCode.Refanyval + + /** + * Retrieves the type token embedded in a typed reference . + */ + final val Refanytype = OpCode.Refanytype + + /** + * Throws ArithmeticException if value is not a finite number. + */ + final val Ckfinite = OpCode.Ckfinite + + /** + * Pushes a typed reference to an instance of a specific type onto the evaluation stack. + */ + final val Mkrefany = OpCode.Mkrefany + + /** + * Converts a metadata token to its runtime representation, pushing it onto the evaluation stack. + */ + final val Ldtoken = OpCode.Ldtoken + + /** + * Converts the value on top of the evaluation stack to unsigned int8, and extends it to int32. + */ + final val Conv_U1 = OpCode.Conv_U1 + + /** + * Converts the value on top of the evaluation stack to unsigned int16, and extends it to int32. + */ + final val Conv_U2 = OpCode.Conv_U2 + + /** + * Converts the value on top of the evaluation stack to natural int. + */ + final val Conv_I = OpCode.Conv_I + + /** + * Converts the signed value on top of the evaluation stack to signed natural int, + * throwing OverflowException on overflow. + */ + final val Conv_Ovf_I = OpCode.Conv_Ovf_I + + /** + * Converts the signed value on top of the evaluation stack to unsigned natural int, + * throwing OverflowException on overflow. + */ + final val Conv_Ovf_U = OpCode.Conv_Ovf_U + + /** + * Adds two integers, performs an overflow check, and pushes the result + * onto the evaluation stack. + */ + final val Add_Ovf = OpCode.Add_Ovf + + /** + * Adds two unsigned integer values, performs an overflow check, and pushes the result + * onto the evaluation stack. + */ + final val Add_Ovf_Un = OpCode.Add_Ovf_Un + + /** + * Multiplies two integer values, performs an overflow check, and pushes the result + * onto the evaluation stack. + */ + final val Mul_Ovf = OpCode.Mul_Ovf + + /** + * Multiplies two unsigned integer values , performs an overflow check , + * and pushes the result onto the evaluation stack. + */ + final val Mul_Ovf_Un = OpCode.Mul_Ovf_Un + + /** + * Subtracts one integer value from another, performs an overflow check, + * and pushes the result onto the evaluation stack. + */ + final val Sub_Ovf = OpCode.Sub_Ovf + + /** + * Subtracts one unsigned integer value from another, performs an overflow check, + * and pushes the result onto the evaluation stack. + */ + final val Sub_Ovf_Un = OpCode.Sub_Ovf_Un + + /** + * Transfers control from the fault or finally clause of an exception block back to + * the Common Language Infrastructure (CLI) exception handler. + */ + final val Endfinally = OpCode.Endfinally + + /** + * Exits a protected region of code, unconditionally tranferring control + * to a specific target instruction. + */ + final val Leave = OpCode.Leave + + /** + * Exits a protected region of code, unconditionally tranferring control + * to a target instruction (short form). + */ + final val Leave_S = OpCode.Leave_S + + /** + * Stores a value of type natural int at a supplied address. + */ + final val Stind_I = OpCode.Stind_I + + /** + * Converts the value on top of the evaluation stack to unsigned natural int, + * and extends it to natural int. + */ + final val Conv_U = OpCode.Conv_U + + /** + * Returns an unmanaged pointer to the argument list of the current method. + */ + final val Arglist = OpCode.Arglist + + /** + * Compares two values. If they are equal, the integer value 1 (int32) is pushed + * onto the evaluation stack otherwise 0 (int32) is pushed onto the evaluation stack. + */ + final val Ceq = OpCode.Ceq + + /** + * Compares two values. If the first value is greater than the second, + * the integer value 1 (int32) is pushed onto the evaluation stack + * otherwise 0 (int32) is pushed onto the evaluation stack. + */ + final val Cgt = OpCode.Cgt + + /** + * Compares two unsigned or unordered values. If the first value is greater than + * the second, the integer value 1 (int32) is pushed onto the evaluation stack + * otherwise 0 (int32) is pushed onto the evaluation stack. + */ + final val Cgt_Un = OpCode.Cgt_Un + + /** + * Compares two values. If the first value is less than the second, + * the integer value 1 (int32) is pushed onto the evaluation stack + * otherwise 0 (int32) is pushed onto the evaluation stack. + */ + final val Clt = OpCode.Clt + + /** + * Compares the unsigned or unordered values value1 and value2. If value1 is + * less than value2, then the integer value 1 (int32) is pushed onto the + * evaluation stack otherwise 0 (int32) is pushed onto the evaluation stack. + */ + final val Clt_Un = OpCode.Clt_Un + + /** + * Pushes an unmanaged pointer (type natural int) to the native code implementing + * a specific method onto the evaluation stack. + */ + final val Ldftn = OpCode.Ldftn + + /** + * Pushes an unmanaged pointer (type natural int) to the native code implementing + * a particular virtual method associated with a specified object onto the evaluation stack. + */ + final val Ldvirtftn = OpCode.Ldvirtftn + + /** + * Loads an argument (referenced by a specified index value) onto the stack. + */ + final val Ldarg = OpCode.Ldarg + + /** + * Load an argument address onto the evaluation stack. + */ + final val Ldarga = OpCode.Ldarga + + /** + * Loads the local variable at a specific index onto the evaluation stack. + */ + final val Ldloc = OpCode.Ldloc + + /** + * Loads the address of the local variable at a specific index onto the evaluation stack. + */ + final val Ldloca = OpCode.Ldloca + + /** + * Stores the value on top of the evaluation stack in the argument slot at a specified index. + */ + final val Starg = OpCode.Starg + + /** + * Pops the current value from the top of the evaluation stack and stores it in a + * the local variable list at a specified index. + */ + final val Stloc = OpCode.Stloc + + /** + * Allocates a certain number of bytes from the local dynamic memory pool and pushes the + * address (a transient pointer, type *) of the first allocated byte onto the evaluation stack. + */ + final val Localloc = OpCode.Localloc + + /** + * Transfers control from the filter clause of an exception back to the + * Common Language Infrastructure (CLI) exception handler. + */ + final val Endfilter = OpCode.Endfilter + + /** + * Indicates that an address currently atop the evaluation stack might not be aligned + * to the natural size of the immediately following ldind, stind, ldfld, stfld, ldobj, + * stobj, initblk, or cpblk instruction. + */ + final val Unaligned = OpCode.Unaligned + + /** + * Specifies that an address currently atop the evaluation stack might be volatile, + * and the results of reading that location cannot be cached or that multiple stores + * to that location cannot be suppressed. + */ + final val Volatile = OpCode.Volatile + + /** + * Performs a postfixed method call instruction such that the current method's stack + * frame is removed before the actual call instruction is executed. + */ + final val Tailcall = OpCode.Tailcall + + /** + * Initializes all the fields of the object at a specific address to a null reference + * or a 0 of the appropriate primitive type. + */ + final val Initobj = OpCode.Initobj + + /** + * Copies a specified number bytes from a source address to a destination address . + */ + final val Cpblk = OpCode.Cpblk + + /** + * Initializes a specified block of memory at a specific address to a given size + * and initial value. + */ + final val Initblk = OpCode.Initblk + + /** + * Rethrows the current exception. + */ + final val Rethrow = OpCode.Rethrow + + /** + * Pushes the size, in bytes, of a supplied value type onto the evaluation stack. + */ + final val Sizeof = OpCode.Sizeof + + //########################################################################## +} diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/ParameterBuilder.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/ParameterBuilder.scala new file mode 100644 index 0000000000..d07a88bd0e --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/ParameterBuilder.scala @@ -0,0 +1,45 @@ +/* + * System.Reflection.Emit-like API for writing .NET assemblies to MSIL + */ + +// $Id: ParameterBuilder.java 14655 2008-04-15 09:37:02Z lorch $ + +package ch.epfl.lamp.compiler.msil.emit + +import ch.epfl.lamp.compiler.msil.Type +import ch.epfl.lamp.compiler.msil.ConstructorInfo +import ch.epfl.lamp.compiler.msil.ParameterInfo +import java.io.IOException + +/** + * Creates or associates parameter information. + * Parameter attributes need to consistent with the method signature. + * If you specify Out attributes for a parameter, you should ensure that + * the type of that method parameter is a ByRef type + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +class ParameterBuilder(name: String, tpe: Type, attr: Int, pos: Int) + extends ParameterInfo(name, tpe, attr, pos) + with ICustomAttributeSetter + with Visitable +{ + + //########################################################################## + + /** Sets a custom attribute. */ + def SetCustomAttribute(constr: ConstructorInfo, value: Array[byte]) { + addCustomAttribute(constr, value) + } + + //########################################################################## + + /** The apply method for a visitor */ + @throws(classOf[IOException]) + def apply(v: Visitor) { + v.caseParameterBuilder(this) + } + + //########################################################################## +} diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/SingleFileILPrinterVisitor.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/SingleFileILPrinterVisitor.scala new file mode 100644 index 0000000000..3da17e83ef --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/SingleFileILPrinterVisitor.scala @@ -0,0 +1,94 @@ +/* + * System.Reflection.Emit-like API for writing .NET assemblies in MSIL + */ + +// $Id: ILPrinterVisitor.java 8664 2006-09-12 16:48:03Z mihaylov $ + +package ch.epfl.lamp.compiler.msil.emit + +import java.io.FileWriter +import java.io.BufferedWriter +import java.io.PrintWriter +import java.io.IOException +import java.util.Iterator +import java.util.HashMap +import java.util.Arrays + +import ch.epfl.lamp.compiler.msil._ +import ch.epfl.lamp.compiler.msil.emit +import ch.epfl.lamp.compiler.msil.util.Table + +/** + * The MSIL printer Vistor. It prints a complete + * assembly in a single file. Then this file can be compiled by ilasm. + * + * @author Nikolay Mihaylov + * @author Daniel Lorch + * @version 1.0 + */ +final class SingleFileILPrinterVisitor(_fileName: String) extends ILPrinterVisitor { + var fileName: String = _fileName + + out = new PrintWriter(new BufferedWriter(new FileWriter(fileName))) + + /** + * Visit an AssemblyBuilder + */ + @throws(classOf[IOException]) + def caseAssemblyBuilder(assemblyBuilder: AssemblyBuilder) { + ILPrinterVisitor.currAssembly = assemblyBuilder + + // first get the entryPoint + this.entryPoint = assemblyBuilder.EntryPoint + + // all external assemblies + as = assemblyBuilder.getExternAssemblies() + Arrays.sort(as, assemblyNameComparator) + + assemblyBuilder.generatedFiles.add(fileName) + printAssemblyBoilerplate() + + // print each module + var m: Array[Module] = assemblyBuilder.GetModules() + nomembers = true + for(val i <- 0 until m.length) { + print(m(i).asInstanceOf[ModuleBuilder]) + } + + nomembers = false + for(val i <- 0 until m.length) { + print(m(i).asInstanceOf[ModuleBuilder]) + } + // close out file + out.close() + ILPrinterVisitor.currAssembly = null + } + + /** + * Visit a ModuleBuilder + */ + @throws(classOf[IOException]) + def caseModuleBuilder(module: ModuleBuilder) { + // print module declaration + currentModule = module + if (nomembers) { + print(".module \'"); print(module.Name); println("\'") + printAttributes(module) + } + + if (!module.globalsCreated) + module.CreateGlobalFunctions() + + var m: Array[MethodInfo] = module.GetMethods() + for(val i <- 0 until m.length) { + print(m(i).asInstanceOf[MethodBuilder]) + } + + var t: Array[Type] = module.GetTypes() + for(val i <- 0 until t.length) { + print(t(i).asInstanceOf[TypeBuilder]) + } + currentModule = null + } + +} // class SingleFileILPrinterVisitor diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/TypeBuilder.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/TypeBuilder.scala new file mode 100644 index 0000000000..ca95a2b24d --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/TypeBuilder.scala @@ -0,0 +1,230 @@ +/* + * System.Reflection.Emit-like API for writing .NET assemblies to MSIL + */ + +// $Id: TypeBuilder.java 14655 2008-04-15 09:37:02Z lorch $ + +package ch.epfl.lamp.compiler.msil.emit + +import ch.epfl.lamp.compiler.msil._ +import java.util.HashMap +import java.util.ArrayList +import java.util.Iterator +import java.io.IOException + +/** + * Defines and creates new instances of classes during runtime. + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +class TypeBuilder (module: Module, attributes: int, fullName: String, baseType: Type, interfaces: Array[Type], declType: Type) + extends Type(module, attributes, fullName, baseType, interfaces, declType, 0) + with ICustomAttributeSetter + with Visitable +{ + import TypeBuilder._ + + //########################################################################## + // public members + + /** 'Bakes' the type. */ + def CreateType(): Type = { + fields = fieldBuilders.toArray(new Array[FieldInfo](fieldBuilders.size())).asInstanceOf[Array[FieldInfo]] + methods = methodBuilders.toArray(new Array[MethodInfo](methodBuilders.size())).asInstanceOf[Array[MethodInfo]] + constructors = constructorBuilders.toArray(new Array[ConstructorInfo](constructorBuilders.size())).asInstanceOf[Array[ConstructorInfo]] + nestedTypes = nestedTypeBuilders.toArray(new Array[Type](nestedTypeBuilders.size())).asInstanceOf[Array[Type]] + + raw = false + if (DeclaringType == null) + Module.asInstanceOf[ModuleBuilder].addType(this) + return this + } + + /** + * Adds a new field to the class, with the given name, + * attributes and field type. + */ + def DefineField(name: String, `type`: Type, attrs: short): FieldBuilder = { + val field: FieldBuilder = new FieldBuilder(name, this, attrs, `type`) + fieldBuilders.add(field) + return field + } + + /** + * Adds a new method to the class, with the given name and + * method signature. + */ + def DefineMethod(name: String, attrs: short, returnType: Type, paramTypes: Array[Type]): MethodBuilder = { + val method = new MethodBuilder(name, this, attrs, returnType, paramTypes) + val methods = methodBuilders.iterator() + while(methods.hasNext()) { + val m = methods.next().asInstanceOf[MethodInfo] + if (methodsEqual(m, method)) + throw new RuntimeException("["+ Assembly() + + "] Method has already been defined: " + m) + } + methodBuilders.add(method) + return method + } + + /** + * Adds a new constructor to the class, with the given attributes + * and signature. + */ + def DefineConstructor(attrs: short, callingConvention: short, paramTypes: Array[Type]): ConstructorBuilder = { + val constr = new ConstructorBuilder(this, attrs, paramTypes) + constructorBuilders.add(constr) + return constr + } + + /** + * Defines a nested type given its name. + */ + def DefineNestedType(name: String, attributes: int, baseType: Type, interfaces: Array[Type]): TypeBuilder = { + val nested = nestedTypeBuilders.iterator() + while(nested.hasNext()) { + val nt = nested.next().asInstanceOf[TypeBuilder] + if (nt.Name.equals(name)) { + val message = "Nested type " + name + " has already been defined: " + nt + throw new RuntimeException(message) + } + } + val t = new TypeBuilder(Module, attributes, name, baseType, interfaces, this) + nestedTypeBuilders.add(t) + return t + } + + /** Get the field with the corresponding name. */ + override def GetField(name: String): FieldInfo = { + testRaw(name) + return super.GetField(name) + } + + /** Get all fields of the current Type. */ + override def GetFields(): Array[FieldInfo] = { + testRaw("") + return super.GetFields() + } + + /** + * Searches for a public instance constructor whose parameters + * match the types in the specified array. + */ + override def GetConstructor(params: Array[Type]): ConstructorInfo = { + testRaw(".ctor" + types2String(params)) + return super.GetConstructor(params) + } + + /** + * Returns all the public constructors defined for the current Type. + */ + override def GetConstructors(): Array[ConstructorInfo] = { + testRaw("") + return super.GetConstructors() + } + + /** + * Searches for the specified public method whose parameters + * match the specified argument types. + */ + override def GetMethod(name: String, params: Array[Type]): MethodInfo = { + testRaw(name + types2String(params)) + return super.GetMethod(name, params) + } + + /** Returns all the public methods of the current Type. */ + override def GetMethods(): Array[MethodInfo] = { + testRaw("") + return super.GetMethods() + } + + /** Searches for the nested type with the specified name. */ + override def GetNestedType(name: String): Type = { + testRaw(name) + return super.GetNestedType(name) + } + + /** Returns all the types nested within the current Type. */ + override def GetNestedTypes(): Array[Type] = { + testRaw("") + return super.GetNestedTypes() + } + + /** Sets a custom attribute. */ + def SetCustomAttribute(constr: ConstructorInfo, value: Array[byte]) { + addCustomAttribute(constr, value) + } + + def setPosition(sourceLine: int, sourceFilename: String) { + this.sourceLine = sourceLine + this.sourceFilename = sourceFilename + } + + def setSourceFilepath(sourceFilepath: String) { + this.sourceFilepath = sourceFilepath + } + + //########################################################################## + // protected members + + var sourceLine: Int = _ + var sourceFilename: String = _ + var sourceFilepath: String = _ + + var fieldBuilders = new ArrayList[FieldBuilder]() + var methodBuilders = new ArrayList[MethodBuilder]() + var constructorBuilders = new ArrayList[ConstructorBuilder]() + var nestedTypeBuilders = new ArrayList[TypeBuilder]() + + // shows if the type is 'raw', i.e. still subject to changes + private var raw = true + + // throws an exception if the type is 'raw', + // i.e. not finalized by call to CreateType + protected def testRaw(member: String) { + if (raw) + throw new RuntimeException + ("Not supported for TypeBuilder before CreateType(): " + + FullName + "::" + member) + } + + //########################################################################## + // public members not part of the Reflection.Emit.TypeBuilder interface. + + /** The apply method for a visitor. */ + @throws(classOf[IOException]) + def apply(v: Visitor) { + v.caseTypeBuilder(this) + } + + //########################################################################## + +} // class TypeBuilder + +object TypeBuilder { + def types2String(types: Array[Type]): String = { + var s = new StringBuffer("(") + for(val i <- 0 until types.length) { + if (i > 0) s.append(", ") + s.append(types(i)) + } + s.append(")") + return s.toString() + } + + def methodsEqual(m1: MethodInfo, m2: MethodInfo): boolean = { + if (!m1.Name.equals(m2.Name)) + return false + if (m1.ReturnType != m2.ReturnType) + return false + val p1 = m1.GetParameters() + val p2 = m2.GetParameters() + if (p1.length != p2.length) + return false + for(val i <- 0 until p1.length) + if (p1(i).ParameterType != p2(i).ParameterType) + return false + return true + } +} diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/Visitable.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/Visitable.scala new file mode 100644 index 0000000000..7d065e0ae5 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/Visitable.scala @@ -0,0 +1,25 @@ +/* + * System.Reflection.Emit-like API for writing .NET assemblies to MSIL + */ + +// $Id: Visitable.java 14655 2008-04-15 09:37:02Z lorch $ + +package ch.epfl.lamp.compiler.msil.emit + +import java.io.IOException + +/** + * The Visitable interface + */ +trait Visitable { + + //########################################################################## + + /** + * the visitable method to apply a visitor + */ + @throws(classOf[IOException]) + def apply(v: Visitor): Unit + + //########################################################################## +} diff --git a/src/msil/ch/epfl/lamp/compiler/msil/emit/Visitor.scala b/src/msil/ch/epfl/lamp/compiler/msil/emit/Visitor.scala new file mode 100644 index 0000000000..c35e8be317 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/emit/Visitor.scala @@ -0,0 +1,59 @@ +/* + * System.Reflection.Emit-like API for writing .NET assemblies to MSIL + */ + +// $Id: Visitor.java 14655 2008-04-15 09:37:02Z lorch $ + +package ch.epfl.lamp.compiler.msil.emit + +import java.io.IOException + +/** + * The Visitor interface to walk through the MSIL code Builder hierarchy. + */ +trait Visitor { + + //########################################################################## + + /** Visit an AssemblyBuilder */ + @throws(classOf[IOException]) + def caseAssemblyBuilder(assemblyBuilder: AssemblyBuilder): Unit + + /** Visit a ModuleBuilder */ + @throws(classOf[IOException]) + def caseModuleBuilder(moduleBuilder: ModuleBuilder): Unit + + /** Visit a TypeBuilder */ + @throws(classOf[IOException]) + def caseTypeBuilder(typeBuilder: TypeBuilder): Unit + + /** Visit a FieldBuilder */ + @throws(classOf[IOException]) + def caseFieldBuilder(fieldBuilder: FieldBuilder): Unit + + /** Visit a ConstructorBuilder */ + @throws(classOf[IOException]) + def caseConstructorBuilder(constructorBuilder: ConstructorBuilder): Unit + + /** Visit a MethodBuilder */ + @throws(classOf[IOException]) + def caseMethodBuilder(methodBuilder: MethodBuilder): Unit + + /** Visit a ParameterBuilder */ + @throws(classOf[IOException]) + def caseParameterBuilder(parameterBuilder: ParameterBuilder): Unit + + /** Visit an ILGenerator */ + @throws(classOf[IOException]) + def caseILGenerator(iLGenerator: ILGenerator): Unit + + /** Visit an OpCode */ + @throws(classOf[IOException]) + def caseOpCode(opCode: OpCode): Unit + + /** Visit a LocalBuilder */ + @throws(classOf[IOException]) + def caseLocalBuilder(localBuilder: LocalBuilder): Unit + + //########################################################################## +} diff --git a/src/msil/ch/epfl/lamp/compiler/msil/tests/CustomAttributesTest.java b/src/msil/ch/epfl/lamp/compiler/msil/tests/CustomAttributesTest.java new file mode 100644 index 0000000000..5067489693 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/tests/CustomAttributesTest.java @@ -0,0 +1,32 @@ +// $Id$ + +package ch.epfl.lamp.compiler.msil.tests; + +import ch.epfl.lamp.compiler.msil.*; +import ch.epfl.lamp.compiler.msil.util.Table; + +import java.io.PrintStream; + +public class CustomAttributesTest { + public static void main(String[] args) { + if (args.length < 1) { + System.err.println("You must supply a filename!"); + System.exit(1); + } + + Assembly assem = Assembly.LoadFrom(args[0]); + Type.initMSCORLIB(assem); + + testCustomAttributes(); + } + + public static void testCustomAttributes() { + Object[] attrs = Type.GetType("System.ObsoleteAttribute") + .GetCustomAttributes(false); + assert attrs != null; + for (int i = 0; i < attrs.length; i++) { + System.out.println("\t" + attrs[i]); + } + } + +} diff --git a/src/msil/ch/epfl/lamp/compiler/msil/tests/JavaTypeTest.java b/src/msil/ch/epfl/lamp/compiler/msil/tests/JavaTypeTest.java new file mode 100644 index 0000000000..0c2d12aa0f --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/tests/JavaTypeTest.java @@ -0,0 +1,19 @@ +// $Id$ + +package ch.epfl.lamp.compiler.msil.tests; + +import ch.epfl.lamp.compiler.msil.*; +import ch.epfl.lamp.compiler.msil.util.VJSAssembly; + +public class JavaTypeTest { + + public static void main(String[] args) { + if (args.length < 1) { + System.err.println("usage: java test.JavaTypeTest classname"); + System.exit(1); + } + + Type type = VJSAssembly.VJSLIB.GetType(args[0]); + MembersTest.dumpType(System.out, type); + } +} diff --git a/src/msil/ch/epfl/lamp/compiler/msil/tests/MembersTest.java b/src/msil/ch/epfl/lamp/compiler/msil/tests/MembersTest.java new file mode 100644 index 0000000000..4f20632ce3 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/tests/MembersTest.java @@ -0,0 +1,101 @@ +// $Id$ + +package ch.epfl.lamp.compiler.msil.tests; + +import ch.epfl.lamp.compiler.msil.*; +import ch.epfl.lamp.compiler.msil.util.Table; + +import java.io.PrintStream; + +public class MembersTest { + + public static void main(String[] args) { + if (args.length < 1) { + System.err.println + ("usage: java test.MembersTest assembly [classname]"); + System.exit(1); + } + + Assembly mscorlib = Assembly.LoadFrom("mscorlib.dll"); + Type.initMSCORLIB(mscorlib); + Assembly assem = Assembly.LoadFrom(args[0]); + if (args.length > 1) { + Type type = assem.GetType(args[1]); + if (type != null) + dumpMember(System.out, type); + else System.err.println("Cannot find type " + args[1] + + " in " + assem); + } else { + Type[] types = assem.GetTypes(); + System.out.println("Number of types in assembly " + assem + + " -> " + types.length); + dumpCustomAttributes(System.out, "assembly: ", assem); + Module[] modules = assem.GetModules(); + for (int i = 0; i < modules.length; i++) { + dumpCustomAttributes(System.out, "module " + modules[i] + ": ", + modules[i]); + } + dumpMembers(System.out, types); + } + } + + public static final void dumpMember(PrintStream out, MemberInfo member) { + try { + if (member.MemberType() == MemberTypes.TypeInfo + || member.MemberType() == MemberTypes.NestedType) { + Type type = (Type)member; + dumpCustomAttributes(out, "", type); + out.print(TypeAttributes.accessModsToString(type.Attributes)); + out.print(type.IsInterface() ? " interface " : " class "); + out.print(type); + if (type.BaseType() != null) + out.println(" extends " + type.BaseType()); + Type[] ifaces = type.GetInterfaces(); + if (ifaces.length > 0) { + out.print("\timplements "); + for (int i = 0; i < ifaces.length; i++) { + out.print(ifaces[i]); + if (i < (ifaces.length - 1)) + out.print(", "); + } + out.println(); + } + out.println("{"); + int all = BindingFlags.Public | BindingFlags.DeclaredOnly// | BindingFlags.NonPublic + | BindingFlags.Instance | BindingFlags.Static; + dumpMembers(out, type.GetNestedTypes()); + dumpMembers(out, type.GetFields(all)); + dumpMembers(out, type.GetConstructors(all)); + dumpMembers(out, type.GetMethods(all)); + dumpMembers(out, type.GetProperties(all)); + dumpMembers(out, type.GetEvents()); + out.println("}"); + } else { + dumpCustomAttributes(out, "", member); + out.print(MemberTypes.toString(member.MemberType())); + out.print(": "); out.print(member); + out.println(); + } + } catch (Throwable e) { + String message = MemberTypes.toString(member.MemberType()) + + ": " + member; + throw new RuntimeException(message, e); + } + } + + public static void dumpCustomAttributes(PrintStream out, + String prefix, + ICustomAttributeProvider att) + { + Object[] attrs = att.GetCustomAttributes(false); + for (int j = 0; j < attrs.length; j++) + out.println(prefix + attrs[j]); + } + + public static void dumpMembers(PrintStream out, MemberInfo[] members) { + for (int i = 0; i < members.length; i++) { + dumpMember(out, members[i]); + } + } + +} diff --git a/src/msil/ch/epfl/lamp/compiler/msil/tests/TableDump.java b/src/msil/ch/epfl/lamp/compiler/msil/tests/TableDump.java new file mode 100644 index 0000000000..0687af2f9f --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/tests/TableDump.java @@ -0,0 +1,312 @@ +// $Id$ + +package ch.epfl.lamp.compiler.msil.tests; + +import ch.epfl.lamp.compiler.msil.PEFile; +import ch.epfl.lamp.compiler.msil.util.Table; +import ch.epfl.lamp.compiler.msil.util.Table.*; + +import java.io.PrintStream; +import java.io.FileNotFoundException; + +public class TableDump extends PEFile { + + //########################################################################## + + public TableDump(String filename) throws FileNotFoundException { + super(filename); + } + + /***/ + public void dump(PrintStream out) { + out.println("CLI RVA: " + CLI_RVA); + out.println("Optional header size: " + optHeaderSize); + out.println("Number of sections: " + numOfSections); + out.println(); + + for (int i = 0; i < sections.length; i++) { + sections[i].dump(out); + out.println(); + } + + out.println("MetaData Offset: 0x" + Integer.toHexString(posMetadata)); + out.println("Number of streams: " + numOfStreams); + + out.println("#~ stream"); Meta.dump(out); out.println(); + out.println("#Strings stream"); Strings.dump(out); out.println(); + if (US != null) { + out.println("#US stream"); US.dump(out); out.println(); + } + out.println("#GUID stream"); GUID.dump(out); out.println(); + out.println("#Blob stream"); Blob.dump(out); out.println(); + + out.println("Heap Sizes Vector = 0x0" + Integer.toHexString(heapSizes)); + out.println(); + + for(int i = 0; i < Table.MAX_NUMBER; i++) + if(getTable(i).rows > 0) { + dump(out, getTable(i)); + out.println(); + } + + } + + /** Dumps the contents of this table. */ + public void dump(PrintStream out, Table table) { + out.println("Table:" + " ID = 0x" + byte2hex(table.id)); + out.println("\tname = " + table.getTableName()); + out.println("\trows = " + table.rows); + //out.println("\tStart pos in file = 0x" + Long.toHexString(table.start)); + for (int i = 1; i <= table.rows; i++) + dumpRow(out, table, i); + } + + public void dumpIndex(PrintStream out, int tableSetId, int index) { + int tableId = Table.getTableId(tableSetId, index); + int row = Table.getTableIndex(tableSetId, index); + out.print(getTable(tableId).getTableName()); + out.print('['); + out.print(getTable(tableId).isShort ? short2hex(row) : int2hex(row)); + out.print(']'); + } + + public void dumpRow(PrintStream out, Table table, int row) { + table.readRow(row); + out.print(table.getTableName()); + out.print("[" + short2hex(row) + "]: "); + dumpRow(out, table); + out.println(); + } + + /** Prints the current content of the fields of the class. */ + public void dumpRow(PrintStream out, Table table) { + if (table instanceof ModuleDef) { + ModuleDef t = (ModuleDef)table; + out.print("Generation = 0x" + short2hex(t.Generation)); + out.print("; Name = " + getString(t.Name)); + //out.print("; Mvid = (" + bytes2hex(getGUID(Mvid)) + ")"); + } else if (table instanceof TypeRef) { + TypeRef t = (TypeRef)table; + out.print("FullName = " + t.getFullName()); + out.print("; ResolutionScope = 0x" + int2hex(t.ResolutionScope)); + } else if (table instanceof TypeDef) { + TypeDef t = (TypeDef)table; + out.print("Flags = 0x"); out.print(int2hex(t.Flags)); + out.print("; FullName = "); out.print(t.getFullName()); + out.print("; Extends = "); + dumpIndex(out, Table._TypeDefOrRef, t.Extends); + out.print("; FieldList = "); out.print(t.FieldList); + out.print("; MethodList = "); out.print(t.MethodList); + } else if (table instanceof FieldTrans) { + FieldTrans t = (FieldTrans)table; + out.print("Field = "); out.print(t.Field); + } else if (table instanceof FieldDef) { + FieldDef t = (FieldDef)table; + out.print("Flags = 0x" + short2hex(t.Flags)); + out.print("; Name = " + t.getName()); + out.print("; Signature = (" + + bytes2hex(getBlob(t.Signature)) + ")"); + } else if (table instanceof MethodTrans) { + MethodTrans t = (MethodTrans)table; + out.print("Method = "); out.print(t.Method); + } else if (table instanceof MethodDef) { + MethodDef t = (MethodDef)table; + out.print("Flags = 0x" + short2hex(t.Flags)); + out.print("; Name = " + t.getName()); + out.print("; ParamList = " + t.ParamList); + out.print("; Signature = (" + + bytes2hex(getBlob(t.Signature)) + ")"); + } else if (table instanceof ParamDef) { + ParamDef t = (ParamDef)table; + out.print("Flags = 0x" + short2hex(t.Flags)); + out.print("; Name = " + t.getName()); + out.print("; Sequence = " + t.Sequence); + } else if (table instanceof InterfaceImpl) { + InterfaceImpl t = (InterfaceImpl)table; + out.print("Class = 0x" + short2hex(t.Class));// + " (ref to: "); + //TypeDef td = (TypeDef) getTable(TypeDef.ID); + //td.readRow(Class); + //td.dumpRow(out); + out.print("; Interface = 0x" + short2hex(t.Interface)); + } else if (table instanceof MemberRef) { + MemberRef t = (MemberRef)table; + out.print("Name = " + t.getName()); + out.print("; Signature = (" + + bytes2hex(getBlob(t.Signature)) + ")"); + out.print("; Class = " + t.Class); + } else if (table instanceof Constant) { + Constant t = (Constant)table; + out.print("Parent = "); dumpIndex(out, Table._HasConstant, t.Parent); + out.print("; Type = 0x" + byte2hex(t.Type)); + out.print("; Value = (" + bytes2hex(getBlob(t.Value))); + out.print("); Value = " + t.getValue()); + } else if (table instanceof CustomAttribute) { + CustomAttribute t = (CustomAttribute)table; + //out.print("Parent = 0x" + int2hex(t.Parent)); + out.print("Parent = "); + dumpIndex(out, Table._HasCustomAttribute, t.Parent); + //out.print("; Type = 0x" + short2hex(t.Type)); + out.print("; Type = "); + dumpIndex(out, Table._CustomAttributeType, t.Type); + out.print("; Value = (" + bytes2hex(t.getValue()) + ")"); + } else if (table instanceof FieldMarshal) { + FieldMarshal t = (FieldMarshal)table; + out.print("NativeType = ("); + out.print(bytes2hex(getBlob(t.NativeType)) + ")"); + } else if (table instanceof DeclSecurity) { + DeclSecurity t = (DeclSecurity)table; + out.print("Action = 0x" + short2hex(t.Action)); + out.print("; PermissionSet = (" + + bytes2hex(getBlob(t.PermissionSet)) + ")"); + } else if (table instanceof ClassLayout) { + ClassLayout t = (ClassLayout)table; + out.print("PackingSize = 0x" + short2hex(t.PackingSize)); + out.print("; ClassSize = 0x" + int2hex(t.ClassSize)); + out.print(": Parent = " + t.Parent + " (ref to: "); + dumpRow(out, this.TypeDef(t.Parent)); + out.print(")"); + } else if (table instanceof FieldLayout) { + FieldLayout t = (FieldLayout)table; + out.print("Offset = 0x" + int2hex(t.Offset)); + out.print("; Field = (ref to: "); + dumpRow(out, this.FieldDef(t.Field)); + out.print(")"); + } else if (table instanceof StandAloneSig) { + StandAloneSig t = (StandAloneSig)table; + out.print("StandAloneSig: Signature = (" + + bytes2hex(getBlob(t.Signature)) + ")"); + } else if (table instanceof EventMap) { + EventMap t = (EventMap)table; + out.print("Parent = 0x" + int2hex(t.Parent) + " (ref to: "); + dumpRow(out, this.TypeDef(t.Parent)); + out.print("); EventList = 0x"); out.print(int2hex(t.EventList)); + } else if (table instanceof EventDef) { + EventDef t = (EventDef)table; + out.print("EventFlags = 0x" + short2hex(t.EventFlags)); + out.print("; Name = " + t.getName()); + out.print("; EventType = 0x" + int2hex(t.EventType)); + } else if (table instanceof PropertyMap) { + PropertyMap t = (PropertyMap)table; + out.print("Parent = " + t.Parent + " (ref to: "); + dumpRow(out, this.TypeDef(t.Parent)); + out.print(")"); + } else if (table instanceof PropertyDef) { + PropertyDef t = (PropertyDef)table; + out.print("Flags = 0x" + short2hex(t.Flags)); + out.print("; Name = " + t.getName()); + out.print("; Type = (" + bytes2hex(getBlob(t.Type)) + ")"); + } else if (table instanceof MethodSemantics) { + MethodSemantics t = (MethodSemantics)table; + out.print("Semantics = 0x" + short2hex(t.Semantics)); + out.print("; Method = 0x" + int2hex(t.Method) + " (ref to: "); + dumpRow(out, this.MethodDef(t.Method)); + out.print("); Association = 0x" + int2hex(t.Association)); + } else if (table instanceof MethodImpl) { + MethodImpl t = (MethodImpl)table; + out.print("Class = (ref to: "); + dumpRow(out, this.TypeDef(t.Class)); + out.print(")"); + } else if (table instanceof ModuleRef) { + ModuleRef t = (ModuleRef)table; + out.print("Name = " + t.getName()); + } else if (table instanceof TypeSpec) { + TypeSpec t = (TypeSpec)table; + out.print("Signature = (" + + bytes2hex(getBlob(t.Signature)) + ")"); + } else if (table instanceof ImplMap) { + ImplMap t = (ImplMap)table; + out.print("ImportName = " + getString(t.ImportName)); + } else if (table instanceof FieldRVA) { + FieldRVA t = (FieldRVA)table; + out.print("RVA = 0x" + int2hex(t.RVA)); + out.print("; Field = (ref to: "); + dumpRow(out, this.FieldDef(t.Field)); + out.print(")"); + } else if (table instanceof AssemblyDef) { + AssemblyDef t = (AssemblyDef)table; + out.print("Flags = 0x" + int2hex(t.Flags)); + out.print(" ; Name = " + getString(t.Name)); + out.print("; Culture = " + getString(t.Culture)); + out.print(" ; Version = " + t.MajorVersion + "."); + out.print(t.MinorVersion + "." + t.BuildNumber); + out.print("." + t.RevisionNumber); + out.print("; HashAlgId = 0x" + int2hex(t.HashAlgId)); + out.print("; PublicKey = ("); + out.print(bytes2hex(getBlob(t.PublicKey)) + ")"); + } else if (table instanceof AssemblyProcessor) { + AssemblyProcessor t = (AssemblyProcessor)table; + out.print("Processor = 0x" + int2hex(t.Processor)); + } else if (table instanceof AssemblyOS) { + AssemblyOS t = (AssemblyOS)table; + out.print("!?!"); + } else if (table instanceof AssemblyRef) { + AssemblyRef t = (AssemblyRef)table; + out.print("Flags = 0x" + int2hex(t.Flags)); + out.print("; Name = " + getString(t.Name)); + out.print("; Culture = " + getString(t.Culture)); + out.print("; Version = " + t.MajorVersion + "." + t.MinorVersion); + out.print("." + t.BuildNumber + "." + t.RevisionNumber); + out.print("; PublicKeyOrToken = (" + + bytes2hex(getBlob(t.PublicKeyOrToken)) + ")"); + out.print("; HashValue = (" + + bytes2hex(getBlob(t.HashValue)) + ")"); + } else if (table instanceof AssemblyRefProcessor) { + AssemblyRefProcessor t = (AssemblyRefProcessor)table; + out.print("!?!"); + } else if (table instanceof AssemblyRefOS) { + AssemblyRefOS t = (AssemblyRefOS)table; + out.print("!?!"); + } else if (table instanceof FileDef) { + FileDef t = (FileDef)table; + out.print("Flags = 0x" + int2hex(t.Flags)); + out.print("; Name = " + t.getName()); + out.print("; HashValue = (" + bytes2hex(getBlob(t.HashValue)) +")"); + } else if (table instanceof ExportedType) { + ExportedType t = (ExportedType)table; + out.print("FullName = " + t.getFullName()); + } else if (table instanceof ManifestResource) { + ManifestResource t = (ManifestResource)table; + out.print("Name = " + getString(t.Name)); + out.print("; Flags = 0x" + int2hex(t.Flags)); + } else if (table instanceof NestedClass) { + NestedClass t = (NestedClass)table; + out.print(this.TypeDef(t.EnclosingClass).getFullName()); + out.print("/"); + out.print(this.TypeDef(t.NestedClass).getFullName()); + } else + throw new RuntimeException("Unknown table " + table.getClass()); + } + + //########################################################################## + + public static void main(String[] args) { + if (args.length < 1) { + System.err.println("You must supply a filename!"); + System.exit(1); + } + + TableDump file = null; + try { + file = new TableDump(args[0]); + } catch (FileNotFoundException e) { e.printStackTrace(); } + + if (args.length > 1) { + nextarg: + for (int i = 1; i < args.length; i++) { + String name = args[i]; + for (int tableId = 0; tableId < Table.MAX_NUMBER; tableId++) { + Table table = file.getTable(tableId); + if ((table.rows > 0) && name.equals(table.getTableName())) { + file.dump(System.out, table); + System.out.println(); + continue nextarg; + } + } + System.err.println("No such table: " + name); + } + } else + file.dump(System.out); + } + + //########################################################################## +} diff --git a/src/msil/ch/epfl/lamp/compiler/msil/tests/Test.java b/src/msil/ch/epfl/lamp/compiler/msil/tests/Test.java new file mode 100644 index 0000000000..d1c81f4fb5 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/tests/Test.java @@ -0,0 +1,93 @@ +// $Id$ + +package test; + +import ch.epfl.lamp.compiler.msil.*; +import ch.epfl.lamp.compiler.msil.util.Table; + +import java.io.PrintStream; + +public class Test { + public static void main(String[] args) { + if (args.length < 1) { + System.err.println("You must supply a filename!"); + System.exit(1); + } + + Assembly assem = Assembly.LoadFrom(args[0]); + Type.initMSCORLIB(assem); + + //"System.Collections.ArrayList" + if (args.length >= 2) { + Type t = Type.GetType(args[1]); + dumpType(System.out, t); + } else { + dumpAssembly(assem); + } + } + + + public static void dumpAssembly(Assembly assem) { + Module[] modules = assem.GetModules(); +// System.out.println("Modules in assembly " + assem + +// " (" + modules.length + ")"); +// for (int i = 0; i < modules.length; i++) { +// System.out.println("\t" + modules[i]); +// } + + Type[] types = modules[0].GetTypes(); +// System.out.println("Types in assembly " + assem + +// " (" + types.length + ")"); + for (int i = 0; i < types.length; i++) { + System.out.println("#" + i + " -> " + types[i]); + types[i].completeType(); + } + } + + public static final void dumpType(PrintStream out, Type type) { + out.println("Type = " + type); + out.println("Name = " + type.Name); + out.println("Namespace = " + type.Namespace); + out.println("FullName = " + type.FullName); + out.println("Attributes = " + TypeAttributes.toString(type.Attributes)); + out.println("BaseType = " + type.BaseType); + Type[] ifaces = type.GetInterfaces(); + if (ifaces != null) { + for (int i = 0; i < ifaces.length; i++) + out.println("\timplements " + ifaces[i]); + } + out.println("Assembly = " + type.Assembly); + out.println("Module = " + type.Module); + out.println("DeclaringType = " + type.DeclaringType); + out.println("IsInterface = " + type.IsInterface); + out.println("IsAbstract = " + type.IsAbstract); + + FieldInfo[] fields = type.GetFields(BindingFlags.Instance + | BindingFlags.Static + | BindingFlags.NonPublic); + out.println("\nFields (" + fields.length + "):"); + for (int i = 0; i < fields.length; i++) { + out.println("\t" + fields[i]); + out.println("\t\tDeclaringType = " + fields[i].DeclaringType); + out.println("\t\tReflectedType = " + fields[i].ReflectedType); + } + + ConstructorInfo[] constrs = type.GetConstructors(); + out.println("\nConstructors (" + constrs.length + "):"); + for (int i = 0; i < constrs.length; i++) { + out.println("\t" + constrs[i]); + } + +// MethodInfo[] methods = type.GetMethods(BindingFlags.Instance +// | BindingFlags.Static +// | BindingFlags.Public +// | BindingFlags.NonPublic); + MethodInfo[] methods = type.GetMethods(); + out.println("\nMethods (" + methods.length + "):"); + for (int i = 0; i < methods.length; i++) { + out.println("\t" + methods[i]); + out.println("\t\tDeclaringType = " + methods[i].DeclaringType); + out.println("\t\tReflectedType = " + methods[i].ReflectedType); + } + } +} diff --git a/src/msil/ch/epfl/lamp/compiler/msil/util/PESection.java b/src/msil/ch/epfl/lamp/compiler/msil/util/PESection.java new file mode 100644 index 0000000000..84f604af53 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/util/PESection.java @@ -0,0 +1,58 @@ +/* + * System.Reflection-like API for acces to .NET assemblies (DLL & EXE) + */ + +// $Id$ + +package ch.epfl.lamp.compiler.msil.util; + +import ch.epfl.lamp.compiler.msil.PEFile; + +import java.io.PrintStream; + +/** Describes a section from a PE/COFF file + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +public final class PESection { + + private final PEFile file; + private final long sectionStart; + + public final String name; + public final int virtAddr; + public final int virtSize; + public final int realAddr; + public final int realSize; + public final int flags; + + private static final byte[] buf = new byte[8]; + + public PESection(PEFile file) { + this.file = file; + sectionStart = file.pos(); + file.read(buf); + int i; + for(i = 7; (i >= 0) && (0 == buf[i]); i--); + name = new String(buf, 0, i + 1); + virtSize = file.readInt(); + virtAddr = file.readInt(); + realSize = file.readInt(); + realAddr = file.readInt(); + file.skip(3 * PEFile.INT_SIZE); + flags = file.readInt(); + } + + + public void dump(PrintStream out) { + out.println("Section name: " + name + + " (name.length=" + name.length() + ")"); + out.println("Virtual Address: 0x" + PEFile.int2hex(virtAddr)); + out.println("Virtual Size: 0x" + PEFile.int2hex(virtSize)); + out.println("Real Address: 0x" + PEFile.int2hex(realAddr)); + out.println("Real Size: 0x" + PEFile.int2hex(realSize)); + out.println("Flags: 0x" + PEFile.int2hex(flags)); + } + +} // class PESection diff --git a/src/msil/ch/epfl/lamp/compiler/msil/util/PEStream.java b/src/msil/ch/epfl/lamp/compiler/msil/util/PEStream.java new file mode 100644 index 0000000000..4feb0f7b1e --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/util/PEStream.java @@ -0,0 +1,200 @@ +/* + * System.Reflection-like API for acces to .NET assemblies (DLL & EXE) + */ + +// $Id$ + +package ch.epfl.lamp.compiler.msil.util; + +import ch.epfl.lamp.compiler.msil.PEFile; +import ch.epfl.lamp.compiler.msil.PEFile.Sig; + +import java.io.PrintStream; +import java.io.IOException; + +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; + +/** + * Implements support for CLI streams within a PE file. + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +public final class PEStream implements Signature { + + //########################################################################## + // Members + + /** The name of the stream. */ + public final String name; + + /** The offset of the stream from the beginning of the file. */ + public final int offset; + + /** The size of the stream in bytes; shall be multiple of 4. */ + public final int size; + + private final PEFile file; + + private final ByteBuffer buffer; + + //########################################################################## + + /** The PEStream class constructor. + * @param file - the PEFile to which this stream belongs + */ + public PEStream(PEFile file) { + this.file = file; + offset = file.fromRVA(file.rvaMetadata + file.readInt()); + size = file.readInt(); + buffer = file.getBuffer(offset, size); + + int i = 0; + byte [] _buf = new byte [16]; + do { + _buf[i] = (byte) file.readByte(); + i++; + } while(0 != _buf[i-1]); + name = new String(_buf, 0, i - 1); + + file.align(PEFile.INT_SIZE, file.posMetadata); + //assert size % 4 == 0; + } + + /** Move to the specified position in the stream. */ + private void seek(int pos) { + try { + buffer.position(pos); + } catch (IllegalArgumentException e) { + System.err.println("\nSeek failed in file " + file + + " for position " + pos + + " of stream " + name + " (" + buffer + ")"); + throw e; + } + } + + /** Return a string from the specified position in the stream. */ + public String getString(int pos) { + seek(pos); + buffer.mark(); + int i; + for (i = 0; getByte() != 0; i++); + byte[] buf = new byte[i]; + buffer.reset(); // go back to the marked position + buffer.get(buf); + try { + return new String(buf, "UTF-8"); + } catch (java.io.UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + + /** Read a byte from the stream. */ + public int getByte() { + return (buffer.get() + 0x0100) & 0xff; + } + + /** Return the GUID at the given position in the stream. */ + public byte[] getGUID(int pos) { + seek(pos); + byte[] buf = new byte[32]; // 128-bit GUID + try { + buffer.get(buf); + } catch (Exception e) { + System.err.println(); + System.err.println("PEStream.getBlob(): Exception for pos = " + + pos + " and buf.length = " + buf.length); + System.err.println("\tbuffer = " + buffer); + e.printStackTrace(); + throw new RuntimeException(); + } + return buf; + } + + public int readLength() { + int length = getByte(); + if ((length & 0x80) != 0) { + length = ((length & 0x7f) << 8) | getByte(); + if ((length & 0x4000) != 0) + length = ((length & 0x3fff) << 16) | (getByte()<<8) | getByte(); + } + return length; + } + + /** Return a blob from the specified position in the stream. */ + public byte[] getBlob(int pos) { + seek(pos); + // the length indicates the number of bytes + // AFTER the encoded size of the blob + int length = readLength(); + byte[] buf = new byte[length]; + buffer.get(buf); + return buf; + } + + /***/ + public Sig getSignature(int pos) { + seek(pos); + return file.newSignature(buffer); + } + + /** + */ + public Object getConstant(int type, int pos) { + Object val = null; + seek(pos); + int length = readLength(); // skip over the blob length field + switch (type) { + case ELEMENT_TYPE_BOOLEAN: + assert length == 1; + return buffer.get() == 0 ? Boolean.FALSE : Boolean.TRUE; + case ELEMENT_TYPE_CHAR: + assert length == 2 : "length == " + length; + return new Character(buffer.getChar()); + case ELEMENT_TYPE_I1: + case ELEMENT_TYPE_U1: + assert length == 1; + return new Byte(buffer.get()); + case ELEMENT_TYPE_I2: + case ELEMENT_TYPE_U2: + assert length == 2; + return new Short(buffer.getShort()); + case ELEMENT_TYPE_I4: + case ELEMENT_TYPE_U4: + assert length == 4; + return new Integer(buffer.getInt()); + case ELEMENT_TYPE_I8: + case ELEMENT_TYPE_U8: + assert length == 8; + return new Long(buffer.getLong()); + case ELEMENT_TYPE_R4: + assert length == 4; + return new Float(buffer.getFloat()); + case ELEMENT_TYPE_R8: + assert length == 8; + return new Double(buffer.getDouble()); + case ELEMENT_TYPE_STRING: +// length /= 2; +// char[] chars = new char[length]; +// for (int i = 0; i < length; i++) +// chars[i] = buffer.getChar(); +// val = new String(chars); + try { + return new String(getBlob(pos), "UTF-16LE"); + } catch(java.io.UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + default: throw new RuntimeException("Illegal constant type: " + type); + } + } + + public void dump(PrintStream out) { + out.println("Stream name: " + name + " (length " + + name.length() + " characters)"); + out.println("Stream offset: 0x" + PEFile.int2hex(offset)); + out.println("Stream size: 0x" + PEFile.int2hex(size)); + } + + //########################################################################## +} // class PEStream diff --git a/src/msil/ch/epfl/lamp/compiler/msil/util/Signature.java b/src/msil/ch/epfl/lamp/compiler/msil/util/Signature.java new file mode 100644 index 0000000000..ded2dd64a7 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/util/Signature.java @@ -0,0 +1,119 @@ +/* + * System.Reflection-like API for acces to .NET assemblies (DLL & EXE) + */ + +// $Id$ + +package ch.epfl.lamp.compiler.msil.util; + +import ch.epfl.lamp.compiler.msil.Type; + +/** + * Signatures + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +public interface Signature { + + //########################################################################## + + /** Marks end of a list. */ + public static final int ELEMENT_TYPE_END = 0x00; + /** void */ + public static final int ELEMENT_TYPE_VOID = 0x01; + /** boolean */ + public static final int ELEMENT_TYPE_BOOLEAN = 0x02; + /** char */ + public static final int ELEMENT_TYPE_CHAR = 0x03; + /** signed byte */ + public static final int ELEMENT_TYPE_I1 = 0x04; + /** byte */ + public static final int ELEMENT_TYPE_U1 = 0x05; + /** short */ + public static final int ELEMENT_TYPE_I2 = 0x06; + /** unsigned short */ + public static final int ELEMENT_TYPE_U2 = 0x07; + /** int */ + public static final int ELEMENT_TYPE_I4 = 0x08; + /** unsigned int */ + public static final int ELEMENT_TYPE_U4 = 0x09; + /** long */ + public static final int ELEMENT_TYPE_I8 = 0x0a; + /** unsigned long */ + public static final int ELEMENT_TYPE_U8 = 0x0b; + /** float */ + public static final int ELEMENT_TYPE_R4 = 0x0c; + /** double */ + public static final int ELEMENT_TYPE_R8 = 0x0d; + /** string */ + public static final int ELEMENT_TYPE_STRING = 0x0e; + /** Followed by token. */ + public static final int ELEMENT_TYPE_PTR = 0x0f; + /** Followed by token. */ + public static final int ELEMENT_TYPE_BYREF = 0x10; + /** Followed by token */ + public static final int ELEMENT_TYPE_VALUETYPE = 0x11; + /** Followed by token */ + public static final int ELEMENT_TYPE_CLASS = 0x12; + /** ... ... */ + public static final int ELEMENT_TYPE_ARRAY = 0x14; + /***/ + public static final int ELEMENT_TYPE_TYPEDBYREF = 0x16; + /** System.IntPtr */ + public static final int ELEMENT_TYPE_I = 0x18; + /** System.UIntPtr */ + public static final int ELEMENT_TYPE_U = 0x19; + /** Followed by full method signature. */ + public static final int ELEMENT_TYPE_FNPTR = 0x1b; + /** System.Object. */ + public static final int ELEMENT_TYPE_OBJECT = 0x1c; + /** Single-dim array with 0 lower bound. */ + public static final int ELEMENT_TYPE_SZARRAY = 0x1d; + /** Required modifier : followed by a TypeDef or TypeRef token. */ + public static final int ELEMENT_TYPE_CMOD_REQD = 0x1f; + /** Optional modifier : followed by a TypeDef or TypeRef token. */ + public static final int ELEMENT_TYPE_CMOD_OPT = 0x20; + /** Implemented within the CLI. */ + public static final int ELEMENT_TYPE_INTERNAL = 0x21; + /** Or'd with following element types. */ + public static final int ELEMENT_TYPE_MODIFIER = 0x40; + /** Sentinel for varargs method signature. */ + public static final int ELEMENT_TYPE_SENTINEL = 0x41; + /**Denotes a local variable that points at a pinned object. */ + public static final int ELEMENT_TYPE_PINNED = 0x45; + + //########################################################################## + // signature designators + + public static final int HASTHIS = 0x20; + public static final int EXPLICITTHIS = 0x40; + public static final int DEFAULT = 0x00; + public static final int VARARG = 0x05; + public static final int SENTINEL = 0x41; + public static final int C = 0x01; + public static final int STDCALL = 0x02; + public static final int THISCALL = 0x03; + public static final int FASTCALL = 0x04; + public static final int FIELD = 0x06; + public static final int PROPERTY = 0x08; + public static final int LOCAL_SIG = 0x07; + + //########################################################################## + // extra IDs used in the serialization format of named arguments + // to custom attributes. Reverse-engineered from compiled C# example + + /** What follows is a string with the full name of the type. */ + public static final int X_ELEMENT_TYPE_TYPE = 0x50; + + /** What follows is a string with the full name of the enumeration type*/ + public static final int X_ELEMENT_TYPE_ENUM = 0x55; + + /** The named argument specifies a field. */ + public static final int X_ELEMENT_KIND_FIELD = 0x53; + + /** The named argument specifies a property. */ + public static final int X_ELEMENT_KIND_PROPERTY = 0x54; + + //########################################################################## +} // interface Signature diff --git a/src/msil/ch/epfl/lamp/compiler/msil/util/Table.java b/src/msil/ch/epfl/lamp/compiler/msil/util/Table.java new file mode 100644 index 0000000000..a4860c369f --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/util/Table.java @@ -0,0 +1,1600 @@ +/* + * System.Reflection-like API for acces to .NET Assemblies + */ + +// $Id$ + +package ch.epfl.lamp.compiler.msil.util; + +import ch.epfl.lamp.compiler.msil.PEFile; +import ch.epfl.lamp.compiler.msil.PEFile.Sig; + +import java.io.PrintStream; +import java.nio.ByteBuffer; +import java.nio.MappedByteBuffer; + +/** + * Represents a table in a .NET assembly + * + * @author Nikolay Mihaylov + * @version 1.0 + */ +public abstract class Table { + + //########################################################################## + + public static final int MAX_NUMBER = 64; + + public static final long VALID_TABLES_MASK = 0x03ff3fb7ff57L; + + //########################################################################## + // fields and methods for handling predefined sets of tables + + public static final int TABLE_SET_LENGTH = 12; + + public static final int _TypeDefOrRef = 0; + public static final int _HasConstant = 1; + public static final int _HasCustomAttribute = 2; + public static final int _HasFieldMarshal = 3; + public static final int _HasDeclSecurity = 4; + public static final int _MemberRefParent = 5; + public static final int _HasSemantics = 6; + public static final int _MethodDefOrRef = 7; + public static final int _MemberForwarded = 8; + public static final int _Implementation = 9; + public static final int _CustomAttributeType = 10; + public static final int _ResolutionScope = 11; + + + public static final int[][] TableSet = new int[TABLE_SET_LENGTH][]; + static { + TableSet[_TypeDefOrRef] = + new int[] {TypeDef.ID, TypeRef.ID, TypeSpec.ID}; + TableSet[_HasConstant] = + new int[] {FieldDef.ID, ParamDef.ID, PropertyDef.ID}; + TableSet[_HasCustomAttribute] = + new int[] {MethodDef.ID, FieldDef.ID, TypeRef.ID, TypeDef.ID, + ParamDef.ID, InterfaceImpl.ID, MemberRef.ID, ModuleDef.ID, + -1, PropertyDef.ID, EventDef.ID, -1, ModuleRef.ID, + TypeSpec.ID, AssemblyDef.ID, AssemblyRef.ID, + FileDef.ID, ExportedType.ID, ManifestResource.ID}; + TableSet[_HasFieldMarshal] = + new int[] {FieldDef.ID, ParamDef.ID}; + TableSet[_HasDeclSecurity] = + new int[] {TypeDef.ID, MethodDef.ID, AssemblyDef.ID}; + TableSet[_MemberRefParent] = + new int[] {-1, TypeRef.ID, ModuleRef.ID, MethodDef.ID, TypeSpec.ID}; + TableSet[_HasSemantics] = + new int[] {EventDef.ID, PropertyDef.ID}; + TableSet[_MethodDefOrRef] = + new int[] {MethodDef.ID, MemberRef.ID}; + TableSet[_MemberForwarded] = + new int[] {FieldDef.ID, MethodDef.ID}; + TableSet[_Implementation] = + new int[] {FileDef.ID, AssemblyRef.ID, ExportedType.ID}; + TableSet[_CustomAttributeType] = + new int[] {-1, -1, MethodDef.ID, MemberRef.ID, -1}; + TableSet[_ResolutionScope] = + new int[] {ModuleDef.ID, ModuleRef.ID, AssemblyRef.ID, TypeRef.ID}; + } + + public static final int[] NoBits = + new int[] {2, 2, 5, 1, 2, 3, 1, 1, 1, 2, 3, 2}; + + public static int getMask(int tableSetId) { + return (1 << NoBits[tableSetId]) - 1; + } + + public static int getTableId(int tableSet, int index) { + return TableSet[tableSet][index & getMask(tableSet)]; + } + + public static int getTableIndex(int tableSet, int index) { + return index >> NoBits[tableSet]; + } + + public static int encodeIndex(int index, int tableSetId, int tableId) { + int[] tableSet = TableSet[tableSetId]; + for (int i = 0; i < tableSet.length; i++) { + if (tableSet[i] == tableId) + return (index << NoBits[tableSetId]) | i; + } + throw new RuntimeException("Cannot find table #" + tableId + + " in table set #" + tableSetId); + } + + //########################################################################## + + private static final String [] tableName = { + "Module", "TypeRef", "TypeDef", " FieldTrans", + "Field", "MethodTrans", "Method", "", + "Param", "InterfaceImpl", "MemberRef", "Constant", + "CustomAttribute", "FieldMarshal", "DeclSecurity","ClassLayout", + "FieldLayout", "StandAloneSig", "EventMap", "", + "Event", "PropertyMap", "", "Property", + "MethodSemantics", "MethodImpl", "ModuleRef", "TypeSpec", + "ImplMap", "FieldRVA", "", "", + "Assembly", "AssemblyProcessor","AssemblyOS", "AssemblyRef", + "AssemblyRefProcessor","AssemblyRefOS", "File", "ExportedType", + "ManifestResource", "NestedClass", "", "", + "", "", "", "",//0x28-0x2f + "", "", "", "", + "", "", "", "",//0x30-0x37 + "", "", "", "", + "", "", "", "" //0x37-0x3f + }; + + /** Creates a table with the given id and number of rows. + */ + public static Table newTable(PEFile file, int id, int rows) { + Table table = null; + switch(id) { + case ModuleDef.ID: table = new ModuleDef(file, rows); break; + case TypeRef.ID: table = new TypeRef(file, rows); break; + case TypeDef.ID: table = new TypeDef(file, rows); break; + case FieldTrans.ID: table = new FieldTrans(file, rows); break; + case FieldDef.ID: table = new FieldDef(file, rows); break; + case MethodTrans.ID: table = new MethodTrans(file, rows); break; + case MethodDef.ID: table = new MethodDef(file, rows); break; + case ParamDef.ID: table = new ParamDef(file, rows); break; + case InterfaceImpl.ID: table = new InterfaceImpl(file, rows); break; + case MemberRef.ID: table = new MemberRef(file, rows); break; + case Constant.ID: table = new Constant(file, rows); break; + case CustomAttribute.ID: table = new CustomAttribute(file, rows); break; + case FieldMarshal.ID: table = new FieldMarshal(file, rows); break; + case DeclSecurity.ID: table = new DeclSecurity(file, rows); break; + case ClassLayout.ID: table = new ClassLayout(file, rows); break; + case FieldLayout.ID: table = new FieldLayout(file, rows); break; + case StandAloneSig.ID: table = new StandAloneSig(file, rows); break; + case EventMap.ID: table = new EventMap(file, rows); break; + case EventDef.ID: table = new EventDef(file, rows); break; + case PropertyMap.ID: table = new PropertyMap(file, rows); break; + case PropertyDef.ID: table = new PropertyDef(file, rows); break; + case MethodSemantics.ID: table = new MethodSemantics(file, rows); break; + case MethodImpl.ID: table = new MethodImpl(file, rows); break; + case ModuleRef.ID: table = new ModuleRef(file, rows); break; + case TypeSpec.ID: table = new TypeSpec(file, rows); break; + case ImplMap.ID: table = new ImplMap(file, rows); break; + case FieldRVA.ID: table = new FieldRVA(file, rows); break; + case AssemblyDef.ID: table = new AssemblyDef(file, rows); break; + case AssemblyProcessor.ID: table = new AssemblyProcessor(file, rows); break; + case AssemblyOS.ID: table = new AssemblyOS(file, rows); break; + case AssemblyRef.ID: table = new AssemblyRef(file, rows); break; + case AssemblyRefProcessor.ID: + table = new AssemblyRefProcessor(file, rows); break; + case AssemblyRefOS.ID: table = new AssemblyRefOS(file, rows); break; + case FileDef.ID: table = new FileDef(file, rows); break; + case ExportedType.ID: table = new ExportedType(file, rows); break; + case ManifestResource.ID: table = new ManifestResource(file, rows); break; + case NestedClass.ID: table = new NestedClass(file, rows); break; + default: + table = new Empty(id); + } +// System.out.println("created table " + table.getName() + " with " +// + table.rows + " rows"); + return table; + } + + + //########################################################################## + // public fields + + /** Number of rows in the table. */ + public final int rows; + + /** Table ID as specified in Partition II. */ + public final int id; + + /** The file to which the table belongs. */ + protected final PEFile file; + + /** Memory mapped buffer wrapping the table. */ + protected ByteBuffer buffer; + + /** + * specified wheter a new memory-mapped byte buffer should be created + * for this table. + */ + protected boolean newMapping = false; + + /** Tells wheter the table is indexed by 2-byte (short) integer + * or by 4-byte integer. */ + public final boolean isShort; + + private int rowSize = -1; + + // the starting position of the table relative to the beginning of the file + private long start = -1; + + // the number of the row who can be accessed via the fields of the table + private int currentRow = 0; + + //########################################################################## + + protected Table(PEFile file, int id, int rows) { + this.file = file; + this.id = id; + this.rows = rows;//file.readInt(); + this.isShort = rows < (1 << 16); +// assert ((1L << id) & VALID_TABLES_MASK) != 0 +// : "Table does not have a vaid ID: " + byte2hex(id); + } + + /** + * Additional table initialization. + * @return the starting position of the next table in the stream. + */ + public final long init(long start) { + if (rows < 1) + return start; + if (this.start == -1) + this.start = start; + else throw new RuntimeException + ("Cannot re-initialize table \'" + getTableName() + "\'"); + rowSize = getRowSize(); + int size = rows * rowSize(); + buffer = this.newMapping ? file.mapBuffer(start, size) + : file.getBuffer(start, size); + return start + size; + } + + + public final String getTableName() { + return 0 <= id && id < MAX_NUMBER ? tableName[id] : ""; + } + + /** + * @return the size of the row in bytes + */ + public final int rowSize() { + return rowSize; + } + + /** + * if the underlying buffer is memory-mapped, load its contents into memory + */ + public void load() { + if (buffer instanceof MappedByteBuffer) + ((MappedByteBuffer)buffer).load(); + } + + /***/ + public final int readByte() { + return (buffer.get() + 0x100) & 0xff; + } + + /***/ + public final int readShort() { + return (buffer.getShort() + 0x10000) & 0xffff; + } + + /***/ + public final int readInt() { + return buffer.getInt(); + } + + /***/ + public final int readStringIndex() { + return file.StringIsShort ? readShort() : readInt(); + } + + /***/ + public final int readBlobIndex() { + return file.BlobIsShort ? readShort() : readInt(); + } + + /***/ + public final int readGUIDIndex() { + return file.GUIDIsShort ? readShort() : readInt(); + } + + /***/ + public final int readTableIndex(int tableId) { + return file.getTable(tableId).isShort ? readShort() : readInt(); + } + + /***/ + public final int readTableSetIndex(int tableSetId) { + return file.indexSize[tableSetId] == 2 ? readShort() : readInt(); + } + + /** Read the specified row and populate the fields of the instance. */ + public final void readRow(int row) { + seekRow(row); + int lastSeek = buffer.position(); + populateFields(); + int rowSizeRead = (int) (buffer.position() - lastSeek); + if (rowSizeRead != rowSize()) + throw new RuntimeException("Table ID=0x" + PEFile.byte2hex(id) + + ": read row size = " + rowSizeRead + + "; expected row size = " + rowSize()); + currentRow = row; + } + + /** Seeks in the file the position of the specified row. */ + protected final void seekRow(int row) { + assert row > 0 && row <= rows + : "Index " + row + " is not within the table with #rows = " + rows; + buffer.position((row - 1)* rowSize()); + } + + public final int currentRow() { return currentRow; } + + public final void nextRow() { readRow(currentRow() + 1); } + + //########################################################################## + // abstract members + + /** Assigns values to the fields of the class. */ + protected abstract void populateFields(); + + /** Returns the size of a row in bytes. */ + protected abstract int getRowSize(); + + //########################################################################## + // a table with 0 rows + + private static final class Empty extends Table { + public Empty(int id) { + super(null, id, 0); + } + protected int getRowSize() { return 0; } + protected void populateFields() { + throw new RuntimeException("Table 0x" + PEFile.byte2hex(id)); + } + } + + //########################################################################## + // table Module; ID=0x00; p115, 21.27 + + public static final class ModuleDef extends Table { + public static final int ID = 0x00; + + /** 2-byte value; reserved - shall be 0. */ + public int Generation; + + /** Index into #String. */ + public int Name; + + /** Index into #GUID; used to distinguish between + * two version of the same module. */ + public int Mvid; + + /** Index into #GUID; reserved - shall be 0. */ + public int EncId; + + /** Index into #GUID; reseved - shall be 0. */ + public int EncBaseId; + + public ModuleDef(PEFile file, int rows) { super(file, ID, rows); } + + protected void populateFields() { + Generation = readShort(); + Name = readStringIndex(); + Mvid = readGUIDIndex(); + EncId = readGUIDIndex(); + EncBaseId = readGUIDIndex(); + } + + protected int getRowSize() { + return 2 + file.getStringIndexSize() + 3*file.getGUIDIndexSize(); + } + + public String getName() { + return file.getString(Name); + } + + } // class ModuleDef + + //########################################################################## + // table TypeRef; ID=0x01; p125, 21.35 + + public static final class TypeRef extends Table { + public static final int ID = 0x1; + + /** A ResolutionScope coded index. */ + public int ResolutionScope; + + /** Index into #String. */ + public int Name; + + /** Index into #String. */ + public int Namespace; + + public TypeRef(PEFile file, int rows) { super(file, ID, rows); } + + protected void populateFields() { + ResolutionScope = readTableSetIndex(_ResolutionScope); + Name = readStringIndex(); + Namespace = readStringIndex(); + } + + protected int getRowSize() { + return file.getTableSetIndexSize(_ResolutionScope) + + 2 * file.getStringIndexSize(); + } + + public String getFullName() { + String namespace = file.getString(Namespace); + return namespace.length() == 0 ? file.getString(Name) + : namespace + "." + file.getString(Name); + } + + } // class TypeRef + + //########################################################################## + // table TypeDef; ID=0x02; p120, 21.34 + + public static final class TypeDef extends Table { + public static final int ID = 0x02; + + /** 4-byte bitmask of type TypeAttributes (22.1.14). */ + public int Flags; + + /** Index into #String. */ + public int Name; + + /** Index into #String. */ + public int Namespace; + + /** TypeDefOrRef coded index. */ + public int Extends; + + /** Index into Field table. + */ + public int FieldList; + + /** Index into Method table. */ + public int MethodList; + + + public TypeDef(PEFile file, int rows) { + super(file, ID, rows); + this.newMapping = true; + } + + public String getFullName() { + String namespace = file.getString(Namespace); + return namespace.length() == 0 ? file.getString(Name) + : namespace + "." + file.getString(Name); + } + + protected void populateFields() { + Flags = readInt(); + Name = readStringIndex(); + Namespace = readStringIndex(); + Extends = readTableSetIndex(_TypeDefOrRef); + FieldList = readTableIndex(FieldDef.ID); + MethodList = readTableIndex(MethodDef.ID); + } + + protected int getRowSize() { + return 4 + 2*file.getStringIndexSize() + + file.getTableSetIndexSize(_TypeDefOrRef) + + file.getTableIndexSize(FieldDef.ID) + + file.getTableIndexSize(MethodDef.ID); + } + + } // class TypeDef + + //########################################################################## + // Table FieldTrans; ID=0x03; undocumented + + /** + * Undocumented table. Appears to be used for translating the Field entry + * in the TypeDef(0x02) table into the real entry in the Fields(0x06) table + */ + public static final class FieldTrans extends Table { + public static final int ID = 0x03; + + public int Field; + + public FieldTrans(PEFile file, int rows) { + super(file, ID, rows); + newMapping = true; + } + + protected void populateFields() { + Field = readTableIndex(FieldDef.ID); + } + + protected int getRowSize() { + return file.getTableIndexSize(FieldDef.ID); + } + + } + + //########################################################################## + // table Field; ID=0x04; p102, 21.15 + + public static final class FieldDef extends Table { + public static final int ID = 0x04; + + /** 2-byte bitmask of type FieldAttributes (22.1.5). */ + public int Flags; + + /** Index into #String. */ + public int Name; + + /** Index into #Blob. */ + public int Signature; + + public FieldDef(PEFile file, int rows) { + super(file, ID, rows); + newMapping = true; + } + + protected void populateFields() { + Flags = readShort(); + Name = readStringIndex(); + Signature = readBlobIndex(); + } + + protected int getRowSize() { + return 2 + file.getStringIndexSize() + file.getBlobIndexSize(); + } + + public String getName() { return file.getString(Name); } + + public Sig getSignature() { return file.getSignature(Signature); } + + } //class FieldDef + + //########################################################################## + // Table MethodTrans; ID=0x05; undocumented + + /** + * Undocumented table. Appears to be used for translating the Method entry + * in the TypeDef(0x02) table into the real entry in the Methods(0x06) table + */ + public static final class MethodTrans extends Table { + public static final int ID = 0x05; + + public int Method; + + public MethodTrans(PEFile file, int rows) { + super(file, ID, rows); + newMapping = true; + } + + protected void populateFields() { + Method = readTableIndex(FieldDef.ID); + } + + protected int getRowSize() { + return file.getTableIndexSize(MethodDef.ID); + } + + } + + //########################################################################## + // table MethodDef; ID=0x06; p110, 21.24 + + public static final class MethodDef extends Table { + public static final int ID = 0x06; + + /** 4-byte constant. */ + public int RVA; + + /** 2-byte bitmask of type MethodImplAttributes (22.1.10). */ + public int ImplFlags; + + /** 2-byte bitmask of type MethodAttributes (22.1.9). */ + public int Flags; + + /** Index into #String. */ + public int Name; + + /** Index into #Blob. */ + public int Signature; + + /** Index into Param Table. */ + public int ParamList; + + public MethodDef(PEFile file, int rows) { + super(file, ID, rows); + newMapping = true; + } + + protected void populateFields() { + RVA = readInt(); + ImplFlags = readShort(); + Flags = readShort(); + Name = readStringIndex(); + Signature = readBlobIndex(); + ParamList = readTableIndex(ParamDef.ID); + } + + protected int getRowSize() { + return 8 + file.getStringIndexSize() + file.getBlobIndexSize() + + file.getTableIndexSize(ParamDef.ID); + } + + public String getName() { return file.getString(Name); } + + public Sig getSignature() { return file.getSignature(Signature); } + } // class Method + + //########################################################################## + // table Param; ID=0x08; p116, 21.30 + + public static final class ParamDef extends Table { + public static final int ID = 0x08; + + /** 2-byte bitmask of type ParamAttributes (22.1.12). */ + public int Flags; + + /** 2-byte constant. */ + public int Sequence; + + /** Index into #String. */ + public int Name; + + public ParamDef(PEFile file, int rows) { + super(file, ID, rows); + newMapping = true; + } + + protected void populateFields() { + Flags = readShort(); + Sequence = readShort(); + Name = readStringIndex(); + } + + protected int getRowSize() { return 4 + file.getStringIndexSize(); } + + public String getName() { return file.getString(Name); } + + } // class Param + + //########################################################################## + // table InterfaceImpl, ID=0x09; p107, 21.21 + + public static final class InterfaceImpl extends Table { + public static final int ID = 0x09; + + /** Index into TypeDef table. */ + public int Class; + + /** Index into TypeDefOrRef table set. */ + public int Interface; + + public InterfaceImpl(PEFile file, int rows) { super(file, ID, rows); } + + protected void populateFields() { + Class = readTableIndex(TypeDef.ID); + Interface = readTableSetIndex(_TypeDefOrRef); + } + + protected int getRowSize() { + return file.getTableIndexSize(TypeDef.ID) + + file.getTableSetIndexSize(_TypeDefOrRef); + } + + /** finds the index of the first entry + * @param targetIndex - index in the TypeDef table - the type to look for + * @return the index of the first interface for the given type; + * 0 if the type doesn't implement any interfaces + */ + + // binary search implementation +// public int findType(int targetIndex) { +// int l = 1, h = rows; +// int classIndex; +// while (l <= h) { +// int mid = (l + h) / 2; +// seekRow(mid); +// classIndex = readTableIndex(TypeDef.ID); +// if (targetIndex <= classIndex) h = mid - 1; +// else l = mid + 1; +// } +// return (targetIndex == classIndex) ? h : 0; +// } + + //linear search implementation + public int findType(int targetIndex) { + for (int i = 1; i <= rows; i++) { + seekRow(i); + if (targetIndex == readTableIndex(TypeDef.ID)) + return i; + } + return 0; + } + + } // class InterfaceImpl + + //########################################################################## + // table MemberRef; ID=0x0a; p109, 21.23 + + public static final class MemberRef extends Table { + public static final int ID = 0x0a; + + /** Index into MemberRefParent table set. */ + public int Class; + + /** Index into #String. */ + public int Name; + + /** Index into #Blob. */ + public int Signature; + + public MemberRef(PEFile file, int rows) { super(file, ID, rows); } + + protected void populateFields() { + Class = readTableSetIndex(_MemberRefParent); + Name = readStringIndex(); + Signature = readBlobIndex(); + } + + protected int getRowSize() { + return file.getTableSetIndexSize(_MemberRefParent) + + file.getStringIndexSize() + file.getBlobIndexSize(); + } + + public String getName() { + return file.getString(Name); + } + + public Sig getSignature() { + return file.getSignature(Signature); + } + + } // class MemberRef + + //########################################################################## + // table Constant; ID=0x0b; p95, 21.9 + + public static final class Constant extends Table { + public static final int ID = 0x0b; + + /** 1-byte constant followed by 1-byte padding 0 (see 22.1.15). */ + public int Type; + + /** Index into HasConst table set. */ + public int Parent; + + /** Index into #Blob. */ + public int Value; + + public Constant(PEFile file, int rows) { super(file, ID, rows); } + + protected void populateFields() { + Type = readShort(); + Parent = readTableSetIndex(_HasConstant); + Value = readBlobIndex(); + } + + protected int getRowSize() { + return 2 + file.getTableSetIndexSize(_HasConstant) + + file.getBlobIndexSize(); + } + + public Object getValue() { + if (Type == Signature.ELEMENT_TYPE_CLASS) + return null; + return file.Blob.getConstant(Type, Value); + } + + + } // class Constant + + //########################################################################## + // table CustomAttribute; ID=0x0c; p95, 21.10 + + public static final class CustomAttribute extends Table { + public static final int ID = 0x0c; + + /** Index into any metadata table, except the CustomAttribute itself; + * more precisely - index into HasCustomAttribute table set. + */ + public int Parent; + + /** Index into the CustomAttributeType table set. */ + public int Type; + + /** Index into #Blob. */ + public int Value; + + public CustomAttribute(PEFile file, int rows) { super(file, ID, rows); } + + protected void populateFields() { + Parent = readTableSetIndex(_HasCustomAttribute); + Type = readTableSetIndex(_CustomAttributeType); + Value = readBlobIndex(); + } + + protected int getRowSize() { + return file.getTableSetIndexSize(_HasCustomAttribute) + + file.getTableSetIndexSize(_CustomAttributeType) + + file.getBlobIndexSize(); + } + + public byte[] getValue() { + return Value == 0 ? null : file.getBlob(Value); + } + } // class CustomAttribute + + //########################################################################## + // table FieldMarshal; ID=0x0d; p105, 21.17 + + public static final class FieldMarshal extends Table { + public static final int ID = 0x0d; + + /** Index into HasFieldMarshal table set. */ + public int Parent; + + /** Index into #Blob. */ + public int NativeType; + + public FieldMarshal(PEFile file, int rows) { super(file, ID, rows); } + + protected void populateFields() { + Parent = readTableSetIndex(_HasFieldMarshal); + NativeType = readBlobIndex(); + } + + protected int getRowSize() { + return file.getTableSetIndexSize(_HasFieldMarshal) + + file.getBlobIndexSize(); + } + + } // class FieldMarshal + + //########################################################################## + // table DeclSecurity; ID=0x0e; p97, 21.11 + + public static final class DeclSecurity extends Table { + public static final int ID = 0x0e; + + /** 2-byte value. */ + public int Action; + + /** Index into HasDeclSecurity table set. */ + public int Parent; + + /** Index into #Blob. */ + public int PermissionSet; + + public DeclSecurity(PEFile file, int rows) { super(file, ID, rows); } + + protected void populateFields() { + Action = readShort(); + Parent = readTableSetIndex(_HasDeclSecurity); + PermissionSet = readBlobIndex(); + } + + protected int getRowSize() { + return 2 + file.getTableSetIndexSize(_HasDeclSecurity) + + file.getBlobIndexSize(); + } + + } // class DeclSecurity + + //########################################################################## + // table ClassLayout; ID=0x0f, p92, 21.8 + + public static final class ClassLayout extends Table { + public static final int ID = 0x0f; + + /** 2-byte constant. */ + public int PackingSize; + + /** 4-byte constant. */ + public int ClassSize; + + /** Index into TypeDef table. */ + public int Parent; + + public ClassLayout(PEFile file, int rows) { super(file, ID, rows); } + + protected void populateFields() { + PackingSize = readShort(); + ClassSize = readInt(); + Parent = readTableIndex(TypeDef.ID); + } + + protected int getRowSize() { + return 6 + file.getTableIndexSize(TypeDef.ID); + } + + } // class ClassLayout + + //########################################################################## + // table FieldLayout; ID=0x10; p104, 21.16 + + public static final class FieldLayout extends Table { + public static final int ID = 0x10; + + /** 4-byte constant. */ + public int Offset; + + /** Index into the Field table. */ + public int Field; + + public FieldLayout(PEFile file, int rows) { super(file, ID, rows); } + + protected void populateFields() { + Offset = readInt(); + Field = readTableIndex(FieldDef.ID); + } + + protected int getRowSize() { + return 4 + file.getTableIndexSize(FieldDef.ID); + } + + } // class FieldLayout + + //########################################################################## + // table StandAloneSig; ID=0x11; p119, 21.33 + + public static final class StandAloneSig extends Table { + public static final int ID = 0x11; + + /** Index into #Blob. */ + public int Signature; + + public StandAloneSig(PEFile file, int rows) { super(file, ID, rows); } + + protected void populateFields() { + Signature = readBlobIndex(); + } + + protected int getRowSize() { return file.getBlobIndexSize(); } + + } // class StandAloneSig + + //########################################################################## + // table EventMap; ID=0x12; p99, 21.12 + + public static final class EventMap extends Table { + public static final int ID = 0x12; + + /** Index into the TypeDef table. */ + public int Parent; + + /** Index into the Event table. */ + public int EventList; + + public EventMap(PEFile file, int rows) { super(file, ID, rows); } + + protected void populateFields() { + Parent = readTableIndex(TypeDef.ID); + EventList = readTableIndex(EventDef.ID); + } + + protected int getRowSize() { + return file.getTableIndexSize(TypeDef.ID) + + file.getTableIndexSize(EventDef.ID); + } + + } // class EventMap + + //########################################################################## + // table Event; ID=0x14; p99, 21.13 + + public static final class EventDef extends Table { + public static final int ID = 0x14; + + /** 2-byte bitmask of type EventAttribute (22.1.4). */ + public int EventFlags; + + /** Index into #String. */ + public int Name; + + /** Index into TypeDefOrRef table set. [This corresponds to the Type + * of the event; it is not the Type that owns the event] + */ + public int EventType; + + public EventDef(PEFile file, int rows) { super(file, ID, rows); } + + protected void populateFields() { + EventFlags = readShort(); + Name = readStringIndex(); + EventType = readTableSetIndex(_TypeDefOrRef); + } + + protected int getRowSize() { + return 2 + file.getStringIndexSize() + + file.getTableSetIndexSize(_TypeDefOrRef); + } + + public String getName() { return file.getString(Name); } + + } // class EventDef + + //########################################################################## + // table PropertyMap; ID=0x15; p119, 21.32 + + public static final class PropertyMap extends Table { + public static final int ID = 0x15; + + /** Index into the TypeDef table. */ + public int Parent; + + /** Index into the Property table. */ + public int PropertyList; + + public PropertyMap(PEFile file, int rows) { super(file, ID, rows); } + + protected void populateFields() { + Parent = readTableIndex(TypeDef.ID); + PropertyList = readTableIndex(PropertyDef.ID); + } + + protected int getRowSize() { + return file.getTableIndexSize(TypeDef.ID) + + file.getTableIndexSize(PropertyDef.ID); + } + + } // class PropertyMap + + //########################################################################## + // table Property; ID=0x17; p117, 21.31 + + public static final class PropertyDef extends Table { + public static final int ID = 0x17; + + /** 2-byte bitmask of type PropertyAttributes (22.1.13). */ + public int Flags; + + /** Index into #String. */ + public int Name; + + /** Index into #Blob. (Indexes the signature in the #Blob) */ + public int Type; + + public PropertyDef(PEFile file, int rows) { super(file, ID, rows); } + + protected void populateFields() { + Flags = readShort(); + Name = readStringIndex(); + Type = readBlobIndex(); + } + + protected int getRowSize() { + return 2 + file.getStringIndexSize() + + file.getBlobIndexSize(); + } + + public String getName() { return file.getString(Name); } + + public Sig getSignature() { return file.getSignature(Type); } + + } // class PropertyDef + + //########################################################################## + // table MethodSemantics; ID=0x18; p114, 21.26 + + public static final class MethodSemantics extends Table { + public static final int ID = 0x18; + + /** 2-byte bitmaks of type MethodSemanticsAttribute (22.1.11). */ + public int Semantics; + + /** Index into the Method table. */ + public int Method; + + /** Index into Event or Property table (HasSemantics table set). */ + public int Association; + + public MethodSemantics(PEFile file, int rows) { super(file, ID, rows); } + + protected void populateFields() { + Semantics = readShort(); + Method = readTableIndex(MethodDef.ID); + Association = readTableSetIndex(_HasSemantics); + } + + protected int getRowSize() { + return 2 + file.getTableIndexSize(MethodDef.ID) + + file.getTableSetIndexSize(_HasSemantics); + } + + public boolean isGetter() { return (Semantics & Getter) != 0; } + public boolean isSetter() { return (Semantics & Setter) != 0; } + public boolean isOther() { return (Semantics & Other) != 0; } + public boolean isAddOn() { return (Semantics & AddOn) != 0; } + public boolean isRemoveOn() { return (Semantics & RemoveOn) != 0; } + public boolean isFire() { return (Semantics & Fire) != 0; } + + private static final short Setter = (short)0x0001; + private static final short Getter = (short)0x0002; + private static final short Other = (short)0x0004; + private static final short AddOn = (short)0x0008; + private static final short RemoveOn = (short)0x0010; + private static final short Fire = (short)0x0020; + + } // class MethodSemantics + + + //########################################################################## + // table MethodImpl; ID=0x19; p113, 21.25 + + public static final class MethodImpl extends Table { + public static final int ID = 0x19; + + /** Index into the TypeDef table. */ + public int Class; + + /** Index into MethodDefOrRef table set. */ + public int MethodBody; + + /** Index into MethodDefOrRef table set. */ + public int MethodDeclaration; + + public MethodImpl(PEFile file, int rows) { super(file, ID, rows); } + + protected void populateFields() { + Class = readTableIndex(TypeDef.ID); + MethodBody = readTableSetIndex(_MethodDefOrRef); + MethodDeclaration = readTableSetIndex(_MethodDefOrRef); + } + + protected int getRowSize() { + return file.getTableIndexSize(TypeDef.ID) + + 2 * file.getTableSetIndexSize(_MethodDefOrRef); + } + + } // class MethodImpl + + //########################################################################## + // table ModuleRef; ID=0x1a; p116, 21.28 + + public static final class ModuleRef extends Table { + public static final int ID = 0x1a; + + /** Index into #String. */ + public int Name; + + public ModuleRef(PEFile file, int rows) { super(file, ID, rows); } + + protected void populateFields() { + Name = readStringIndex(); + } + + protected int getRowSize() { return file.getStringIndexSize(); } + + public String getName() { return file.getString(Name); } + + } // class ModuleRef + + //########################################################################## + // table TypeSpec; ID=0x1b; p126, 21.36 + + public static final class TypeSpec extends Table { + public static final int ID = 0x1b; + + /** Index into #Blob, where the blob is formatted + * as specified in 22.2.15 + */ + public int Signature; + + public TypeSpec(PEFile file, int rows) { super(file, ID, rows); } + + protected void populateFields() { + Signature = readBlobIndex(); + } + + protected int getRowSize() { return file.getBlobIndexSize(); } + + public Sig getSignature() { return file.getSignature(Signature); } + } // class TypeSpec + + //########################################################################## + // table ImplMap; ID=0x1c; p107, 21.20 + + public static final class ImplMap extends Table { + public static final int ID = 0x1c; + + /** 2-byte bitmask of type PInvokeAttributes (22.1.7). */ + public int MappingFlags; + + /** Index into MemberForwarded table set. */ + public int MemberForwarded; + + /** Index into #String. */ + public int ImportName; + + /** Index into the ModuleRef table. */ + public int ImportScope; + + public ImplMap(PEFile file, int rows) { super(file, ID, rows); } + + protected void populateFields() { + MappingFlags = readShort(); + MemberForwarded = readTableSetIndex(_MemberForwarded); + ImportName = readStringIndex(); + ImportScope = readTableIndex(ModuleRef.ID); + } + + protected int getRowSize() { + return 2 + file.getTableSetIndexSize(_MemberForwarded) + + file.getStringIndexSize() + + file.getTableIndexSize(ModuleRef.ID); + } + + } // class ImplMap + + //########################################################################## + // table FieldRVA; ID=0x1d; p106, 21.18 + + public static final class FieldRVA extends Table { + public static final int ID = 0x1d; + + /** 4-byte constant. */ + public int RVA; + + /** Index into the Field table. */ + public int Field; + + public FieldRVA(PEFile file, int rows) { super(file, ID, rows); } + + protected void populateFields() { + RVA = readInt(); + Field = readTableIndex(Table.FieldDef.ID); + } + + protected int getRowSize() { + return 4 + file.getTableIndexSize(FieldDef.ID); + } + + } + + //########################################################################## + // table Assembly; ID=0x20; p90, 21.2 + + public static final class AssemblyDef extends Table { + public static final int ID = 0x20; + + /** 4-byte constatnt of type AssemblyHashAlgorithm, clause 22.1.1 */ + public int HashAlgId; + + /** 2-byte constant */ + public int MajorVersion; + + /** 2-byte constant */ + public int MinorVersion; + + /** 2-byte constant */ + public int BuildNumber; + + /** 2-byte constant */ + public int RevisionNumber; + + /** 4-byte constant */ + public int Flags; + + /** index into #Blob */ + public int PublicKey; + + /** index into #String */ + public int Name; + + /** index into #String */ + public int Culture; + + public AssemblyDef(PEFile file, int rows) { super(file, ID, rows); } + + protected void populateFields() { + HashAlgId = readInt(); + MajorVersion = readShort(); + MinorVersion = readShort(); + BuildNumber = readShort(); + RevisionNumber = readShort(); + Flags = readInt(); + PublicKey = readBlobIndex(); + Name = readStringIndex(); + Culture = readStringIndex(); + } + + protected int getRowSize() { + return 16 + file.getBlobIndexSize() + 2*file.getStringIndexSize(); + } + + } // class AssemblyDef + + //########################################################################## + // table AssemblyProcessor; ID=0x21; p91, 21.4 + + public static final class AssemblyProcessor extends Table { + public static final int ID = 0x21; + + /** 4-byte constant. */ + public int Processor; + + public AssemblyProcessor(PEFile file, int rows) { super(file, ID, rows); } + + protected void populateFields() { + Processor = readInt(); + } + + protected int getRowSize() { return 4; } + + } + + //########################################################################## + // table AssemblyOS; ID = 0x22; p90, 21.3 + + public static final class AssemblyOS extends Table { + public static final int ID = 0x22; + + /** 4-byte constant. */ + public int OSPlatformID; + + /** 4-byte constant. */ + public int OSMajorVersion; + + /** 4-byte constant. */ + public int OSMinorVersion; + + public AssemblyOS(PEFile file, int rows) { super(file, ID, rows); } + + protected void populateFields() { + OSPlatformID = readInt(); + OSMajorVersion = readInt(); + OSMinorVersion = readInt(); + } + + protected int getRowSize() { return 12; } + + } + + //########################################################################## + // table AssemblyRef; ID = 0x23; pp91, 21.5 + + public static final class AssemblyRef extends Table { + public static final int ID = 0x23; + + /** 2-byte constant. */ + public int MajorVersion; + + /** 2-byte constant. */ + public int MinorVersion; + + /** 2-byte constant. */ + public int BuildNumber; + + /** 2-byte constant. */ + public int RevisionNumber; + + /** 4-byte bitmask of type AssemblyFlags (22.1.2). */ + public int Flags; + + /** index into #Blob. */ + public int PublicKeyOrToken; + + /** index into #String. */ + public int Name; + + /** index into #String. */ + public int Culture; + + /** index into #Blob. */ + public int HashValue; + + public AssemblyRef(PEFile file, int rows) { super(file, ID, rows); } + + protected void populateFields() { + MajorVersion = readShort(); + MinorVersion = readShort(); + BuildNumber = readShort(); + RevisionNumber = readShort(); + Flags = readInt(); + PublicKeyOrToken = readBlobIndex(); + Name = readStringIndex(); + Culture = readStringIndex(); + HashValue = readBlobIndex(); + } + + protected int getRowSize() { + return 12 + 2*file.getBlobIndexSize() + 2*file.getStringIndexSize(); + } + + public String getName() { return file.getString(Name); } + } + + //########################################################################## + // table AssemblyRefProcessor; ID=0x24; p92, 21.7 + + public static final class AssemblyRefProcessor extends Table { + public static final int ID = 0x24; + + /** 4-byte constant. */ + public int Processor; + + /** Index into the AssemblyRef table. */ + public int AssemblyRef; + + public AssemblyRefProcessor(PEFile file, int rows) { super(file, ID, rows); } + + protected void populateFields() { + Processor = readInt(); + AssemblyRef = readTableIndex(Table.AssemblyRef.ID); + } + + protected int getRowSize() { + return 4 + file.getTableIndexSize(Table.AssemblyRef.ID); + } + + } // class AssemblyRefProcessor + + //########################################################################## + // table AssemblyRefOS; ID=0x25; p92, 21.6 + + public static final class AssemblyRefOS extends Table { + public static final int ID = 0x25; + + /** 4-byte constant. */ + public int OSPlatformId; + + /** 4-byte constant. */ + public int OSMajorVersion; + + /** 4-byte constant. */ + public int OSMinorVersion; + + /** Index into the AssemblyRef table. */ + public int AssemblyRef; + + public AssemblyRefOS(PEFile file, int rows) { super(file, ID, rows); } + + protected void populateFields() { + OSPlatformId = readInt(); + OSMajorVersion = readInt(); + OSMinorVersion = readInt(); + AssemblyRef = readTableIndex(Table.AssemblyRef.ID); + } + + protected int getRowSize() { + return 12 + file.getTableIndexSize(Table.AssemblyRef.ID); + } + + } // class AssemblyRefOS + + //########################################################################## + // table File; ID=0x26; p106, 21.19 + + public static final class FileDef extends Table { + public static final int ID = 0x26; + + /** 4-byte bitmask of type FileAttributes (22.1.6). */ + public int Flags; + + /** Index into #String. */ + public int Name; + + /** Index into #Blob. */ + public int HashValue; + + public FileDef(PEFile file, int rows) { super(file, ID, rows); } + + protected void populateFields() { + Flags = readInt(); + Name = readStringIndex(); + HashValue = readBlobIndex(); + } + + protected int getRowSize() { + return 4 + file.getStringIndexSize() + file.getBlobIndexSize(); + } + + public String getName() { + return file.getString(Name); + } + + } // class FileDef + + //########################################################################## + // table ExportedType; ID=0x27; p100, 21.14 + + public static final class ExportedType extends Table { + public static final int ID = 0x27; + + /** 4-byte bitmask of type TypeAttribute (22.1.6). */ + public int Flags; + + /** 4-byte index into a TypeDef table of + * another module in this assembly. + */ + public int TypeDefId; + + /** Index into #String. */ + public int TypeName; + + /** Index into #Stream. */ + public int TypeNamespace; + + /** Index into one of two tables as follows: + * - 'File' table, where that entry says which module + * in the current assembly holds the TypeDef + * - 'ExportedType' table, where that entry is + * the enclosing Type of the current nested Type + */ + public int Implementation; + + public ExportedType(PEFile file, int rows) { super(file, ID, rows); } + + protected void populateFields() { + Flags = readInt(); + TypeDefId = readInt(); + TypeName = readStringIndex(); + TypeNamespace = readStringIndex(); + Implementation = readTableSetIndex(_Implementation); + } + + protected int getRowSize() { + return 8 + 2*file.getStringIndexSize() + + file.getTableSetIndexSize(_Implementation); + } + + public String getFullName() { + String namespace = file.getString(TypeNamespace); + return namespace.length() == 0 ? file.getString(TypeName) + : namespace + "." + file.getString(TypeName); + } + + } // class ExportedType + + //########################################################################## + // table ManifestResource; ID=0x28; p108, 21.22 + + public static final class ManifestResource extends Table { + public static final int ID = 0x28; + + /** 4-byte constant. */ + public int Offset; + + /** 4-byte bitmask of type ManifestResourceAttributes (22.1.8). */ + public int Flags; + + /** Index into #String. */ + public int Name; + + /** Index into the Implementation table set. */ + public int Implementation; + + public ManifestResource(PEFile file, int rows) { super(file, ID, rows); } + + protected void populateFields() { + Offset = readInt(); + Flags = readInt(); + Name = readStringIndex(); + Implementation = readTableSetIndex(_Implementation); + } + + protected int getRowSize() { + return 8 + file.getStringIndexSize() + + file.getTableSetIndexSize(_Implementation); + } + + } // class ManifestResource + + //########################################################################## + // table NestedClass; ID=0x29; p116, 21.29 + + public static final class NestedClass extends Table { + public static final int ID = 0x29; + + /** Index into the TypeDef table. */ + public int NestedClass; + + /** Index into the TypeDef table. */ + public int EnclosingClass; + + public NestedClass(PEFile file, int rows) { super(file, ID, rows); } + + protected void populateFields() { + NestedClass = readTableIndex(TypeDef.ID); + EnclosingClass = readTableIndex(TypeDef.ID); + } + + protected int getRowSize() { + return 2 * file.getTableIndexSize(TypeDef.ID); + } + + } // class NestedClass + + //########################################################################## + +} // class Table diff --git a/src/msil/ch/epfl/lamp/compiler/msil/util/VJSAssembly.java b/src/msil/ch/epfl/lamp/compiler/msil/util/VJSAssembly.java new file mode 100644 index 0000000000..8722aafa27 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/util/VJSAssembly.java @@ -0,0 +1,294 @@ +// $Id: VJSAssembly.java 125 2005-04-05 09:16:50Z mihaylov $ + +package ch.epfl.lamp.compiler.msil.util; + +import java.lang.reflect.*; +import java.util.HashMap; + +import ch.epfl.lamp.compiler.msil.*; + +/** + * Represents the Microsoft vjslib.dll assembly. + */ +public final class VJSAssembly extends Assembly { + + private VJSAssembly(AssemblyName an) { super(an); } + + protected void loadModules() { + VJSLIB_DLL.init(); + addModule("vjslib.dll", VJSLIB_DLL); + } + + public static final Assembly VJSLIB; + private static final VJSModule VJSLIB_DLL; + + static { + AssemblyName an = new AssemblyName(); + an.Name = "vjslib"; + an.Version = new Version(1, 0, 3300, 0); + an.SetPublicKeyToken(new byte [] {(byte)0xB0, 0x3F, 0x5F, 0x7F, + 0x11, (byte)0xD5, 0x0A, 0x3A}); + VJSLIB = new VJSAssembly(an); + VJSLIB_DLL = new VJSModule(VJSLIB); + } + + + //########################################################################## + + private static final class VJSModule extends Module { + + VJSModule(Assembly vjslib) { + super("vjslib", "vjslib.dll", "vjslib.dll", vjslib); + } + + void init() { + addType("void", Type.GetType("System.Void")); + addType("boolean", Type.GetType("System.Boolean")); + addType("char", Type.GetType("System.Char")); + addType("float", Type.GetType("System.Single")); + addType("double", Type.GetType("System.Double")); + addType("byte", Type.GetType("System.SByte")); + addType("short", Type.GetType("System.Int16")); + addType("int", Type.GetType("System.Int32")); + addType("long", Type.GetType("System.Int64")); + addType("java.lang.Object", Type.GetType("System.Object")); + addType("java.lang.String", Type.GetType("System.String")); + } + + public Type[] GetTypes() { + throw new RuntimeException("Operation not supported!"); + } + + public Type GetType(String name) { + // look it up in the typesMap + Type type = super.GetType(name); + if (type != null) + return type; + Class clazz = null; + try { + clazz = Class.forName(name); + } catch (ClassNotFoundException e) {} + return getType(clazz); + } + + Type getType(Class clazz) { + if (clazz == null) return null; + Type type = null; + if (clazz.isArray()) { + Type elemType = getType(clazz.getComponentType()); + type = super.GetType(elemType.FullName + "[]"); + if (type != null) + return type; + type = Type.mkArray(elemType, 1); + } else { + type = super.GetType(clazz.getName()); + if (type != null) + return type; + type = new JavaType(clazz); + } + return addType(type); + } + + Type[] getTypes(Class [] classes) { + if (classes.length == 0) return Type.EmptyTypes; + Type [] types = new Type[classes.length]; + for (int i = 0; i < classes.length; i++) + types[i] = getType(classes[i]); + return types; + } + + } // class VJSModule + + //########################################################################## + + private static final class JavaType extends Type { + + //###################################################################### + + private final Class clazz; + + JavaType(Class clazz, int attrs, String name, + Type baseType, Type[] interfaces, Type declType) + { + super(VJSLIB_DLL, attrs, name, baseType, interfaces, declType, 0); + this.clazz = clazz; + } + + JavaType(Class clazz, String name) { + super(VJSLIB_DLL, + translateTypeAttrs(clazz.getModifiers()), + name, + VJSLIB_DLL.getType(clazz.getSuperclass()), + null, + VJSLIB_DLL.getType(clazz.getDeclaringClass()), + 0); + this.clazz = clazz; + } + + JavaType(Class clazz) { + this(clazz, clazz.getName()); + } + + //###################################################################### + // lazy JavaType member loaders + + protected void loadInterfaces() { + this.interfaces = VJSLIB_DLL.getTypes(clazz.getInterfaces()); + } + + protected void loadNestedTypes() { + Class [] nested = clazz.getDeclaredClasses(); + this.nestedTypes = new Type[nested.length]; + for (int i = 0; i < nested.length; i++) { + String name = nested[i].getName(); + name = name.substring(name.lastIndexOf('$') + 1); + nestedTypes[i] = new JavaType(nested[i], name); + } + } + + protected void loadFields() { + Field [] jfields = clazz.getDeclaredFields(); + FieldInfo[] fields = new FieldInfo[jfields.length]; + for (int i = 0; i < jfields.length; i++) + fields[i] = new JavaFieldInfo(jfields[i]); + this.fields = fields; + } + + protected void loadMethods() { + Constructor[] jconstrs = clazz.getDeclaredConstructors(); + this.constructors = new ConstructorInfo[jconstrs.length]; + for (int i = 0; i < jconstrs.length; i++) + this.constructors[i] = new JavaConstructorInfo(jconstrs[i]); + + Method[] jmethods = clazz.getDeclaredMethods(); + this.methods = new MethodInfo[jmethods.length]; + for (int i = 0; i < jmethods.length; i++) + this.methods[i] = JavaMethodInfo.getMethod(jmethods[i]); + } + + //###################################################################### + // type resolution methods + + + static int translateTypeAttrs(int mods) { + int attr = 0; + + if (Modifier.isInterface(mods)) + attr |= TypeAttributes.Interface; + else + attr |= TypeAttributes.Class; + + if (Modifier.isAbstract(mods)) + attr |= TypeAttributes.Abstract; + + if (Modifier.isFinal(mods)) + attr |= TypeAttributes.Sealed; + + if (Modifier.isPublic(mods)) + attr |= TypeAttributes.Public; + else + attr |= TypeAttributes.NotPublic; + + return attr; + } + + //###################################################################### + } // class JavaType + + //########################################################################## + + private static final class JavaFieldInfo extends FieldInfo { + JavaFieldInfo(Field field) { + super(field.getName(), + VJSLIB_DLL.getType(field.getDeclaringClass()), + translateFieldAttrs(field.getModifiers()), + VJSLIB_DLL.getType(field.getType())); + } + + //translate java modifiers into corresponding .NET Field attributes + static short translateFieldAttrs(int mods) { + short attr = 0; + + if (Modifier.isFinal(mods)) + attr |= FieldAttributes.InitOnly; + + if (Modifier.isPublic(mods)) + attr |= FieldAttributes.Public; + else if (Modifier.isProtected(mods)) + attr |= FieldAttributes.FamORAssem; + else if (Modifier.isPrivate(mods)) + attr |= FieldAttributes.Private; + + if (Modifier.isStatic(mods)) + attr |= FieldAttributes.Static; + + return attr; + } + + } // class JavaFieldInfo + + //########################################################################## + + private static final class JavaConstructorInfo extends ConstructorInfo { + JavaConstructorInfo(Constructor constr) { + super(VJSLIB_DLL.getType(constr.getDeclaringClass()), + JavaMethodInfo.translateMethodAttrs(constr.getModifiers()), + VJSLIB_DLL.getTypes(constr.getParameterTypes())); + } + } + + //########################################################################## + + private static final class JavaMethodInfo extends MethodInfo { + + JavaMethodInfo(String name, Type declType, int attrs, + Type returnType, Type[] paramTypes) { + super(name, declType, declType, attrs, returnType, paramTypes); + } + + static MethodInfo getMethod(Method method) { + String name = method.getName(); + if (name.equals("toString")) + name = "ToString"; + else if(name.equals("equals")) + name = "Equals"; + else if (name.equals("hashCode")) + name = "GetHashCode"; + return new JavaMethodInfo + (name, VJSLIB_DLL.getType(method.getDeclaringClass()), + translateMethodAttrs(method.getModifiers()), + VJSLIB_DLL.getType(method.getReturnType()), + VJSLIB_DLL.getTypes(method.getParameterTypes())); + } + + static short translateMethodAttrs(int mods) { + short attr = 0; + + if (Modifier.isAbstract(mods)) + attr |= MethodAttributes.Abstract; + + if (Modifier.isFinal(mods)) + attr |= MethodAttributes.Final; + + if (Modifier.isPublic(mods)) + attr |= MethodAttributes.Public; + else if (Modifier.isProtected(mods)) + attr |= MethodAttributes.FamORAssem; + else if (Modifier.isPrivate(mods)) + attr |= MethodAttributes.Private; + + if (Modifier.isStatic(mods)) + attr |= MethodAttributes.Static; + else + attr |= MethodAttributes.Virtual; + + //if (Modifier.isSynchronized(mods)) + // attr |= MethodAttributes.Synchronized; + + return attr; + } + } // class JavaMethodInfo + + //########################################################################## + +} // class VJSAssembly diff --git a/src/msil/ch/epfl/lamp/compiler/msil/util/VJSAssembly.java2 b/src/msil/ch/epfl/lamp/compiler/msil/util/VJSAssembly.java2 new file mode 100644 index 0000000000..ada30ca7c9 --- /dev/null +++ b/src/msil/ch/epfl/lamp/compiler/msil/util/VJSAssembly.java2 @@ -0,0 +1,294 @@ +// $Id: VJSAssembly.java 145 2005-05-06 07:55:25Z mihaylov $ + +package ch.epfl.lamp.compiler.msil.util; + +import java.lang.reflect.*; +import java.util.HashMap; + +import ch.epfl.lamp.compiler.msil.*; + +/** + * Represents the Microsoft vjslib.dll assembly. + */ +public final class VJSAssembly extends Assembly { + + private VJSAssembly(AssemblyName an) { super(an); } + + protected void loadModules() { + VJSLIB_DLL.init(); + addModule("vjslib.dll", VJSLIB_DLL); + } + + public static final Assembly VJSLIB; + private static final VJSModule VJSLIB_DLL; + + static { + AssemblyName an = new AssemblyName(); + an.Name = "vjslib"; + an.Version = new Version(1, 0, 3300, 0); + an.SetPublicKeyToken(new byte [] {(byte)0xB0, 0x3F, 0x5F, 0x7F, + 0x11, (byte)0xD5, 0x0A, 0x3A}); + VJSLIB = new VJSAssembly(an); + VJSLIB_DLL = new VJSModule(VJSLIB); + } + + + //########################################################################## + + private static final class VJSModule extends Module { + + VJSModule(Assembly vjslib) { + super("vjslib", "vjslib.dll", "vjslib.dll", vjslib); + } + + void init() { + addType("void", Type.GetType("System.Void")); + addType("boolean", Type.GetType("System.Boolean")); + addType("char", Type.GetType("System.Char")); + addType("float", Type.GetType("System.Single")); + addType("double", Type.GetType("System.Double")); + addType("byte", Type.GetType("System.SByte")); + addType("short", Type.GetType("System.Int16")); + addType("int", Type.GetType("System.Int32")); + addType("long", Type.GetType("System.Int64")); + addType("java.lang.Object", Type.GetType("System.Object")); + addType("java.lang.String", Type.GetType("System.String")); + } + + public Type[] GetTypes() { + throw new RuntimeException("Operation not supported!"); + } + + public Type GetType(String name) { + // look it up in the typesMap + Type type = super.GetType(name); + if (type != null) + return type; + Class clazz = null; + try { + clazz = Class.forName(name); + } catch (ClassNotFoundException e) {} + return getType(clazz); + } + + Type getType(Class clazz) { + if (clazz == null) return null; + Type type = null; + if (clazz.isArray()) { + Type elemType = getType(clazz.getComponentType()); + type = super.GetType(elemType.FullName + "[]"); + if (type != null) + return type; + type = Type.mkArray(elemType, 1); + } else { + type = super.GetType(clazz.getName()); + if (type != null) + return type; + type = new JavaType(clazz); + } + return addType(type); + } + + Type[] getTypes(Class [] classes) { + if (classes.length == 0) return Type.EmptyTypes; + Type [] types = new Type[classes.length]; + for (int i = 0; i < classes.length; i++) + types[i] = getType(classes[i]); + return types; + } + + } // class VJSModule + + //########################################################################## + + private static final class JavaType extends Type { + + //###################################################################### + + private final Class clazz; + + JavaType(Class clazz, int attrs, String name, + Type baseType, Type[] interfaces, Type declType) + { + super(VJSLIB_DLL, attrs, name, baseType, interfaces, declType, 0); + this.clazz = clazz; + } + + JavaType(Class clazz, String name) { + super(VJSLIB_DLL, + translateTypeAttrs(clazz.getModifiers()), + name, + VJSLIB_DLL.getType(clazz.getSuperclass()), + null, + VJSLIB_DLL.getType(clazz.getDeclaringClass()), + 0); + this.clazz = clazz; + } + + JavaType(Class clazz) { + this(clazz, clazz.getName()); + } + + //###################################################################### + // lazy JavaType member loaders + + protected void loadInterfaces() { + this.interfaces = VJSLIB_DLL.getTypes(clazz.getInterfaces()); + } + + protected void loadNestedTypes() { + Class [] nested = clazz.getDeclaredClasses(); + this.nestedTypes = new Type[nested.length]; + for (int i = 0; i < nested.length; i++) { + String name = nested[i].getName(); + name = name.substring(name.lastIndexOf('$') + 1); + nestedTypes[i] = new JavaType(nested[i], name); + } + } + + protected void loadFields() { + Field [] jfields = clazz.getDeclaredFields(); + FieldInfo[] fields = new FieldInfo[jfields.length]; + for (int i = 0; i < jfields.length; i++) + fields[i] = new JavaFieldInfo(jfields[i]); + this.fields = fields; + } + + protected void loadMethods() { + Constructor[] jconstrs = clazz.getDeclaredConstructors(); + this.constructors = new ConstructorInfo[jconstrs.length]; + for (int i = 0; i < jconstrs.length; i++) + this.constructors[i] = new JavaConstructorInfo(jconstrs[i]); + + Method[] jmethods = clazz.getDeclaredMethods(); + this.methods = new MethodInfo[jmethods.length]; + for (int i = 0; i < jmethods.length; i++) + this.methods[i] = JavaMethodInfo.getMethod(jmethods[i]); + } + + //###################################################################### + // type resolution methods + + + static int translateTypeAttrs(int mods) { + int attr = 0; + + if (Modifier.isInterface(mods)) + attr |= TypeAttributes.Interface; + else + attr |= TypeAttributes.Class; + + if (Modifier.isAbstract(mods)) + attr |= TypeAttributes.Abstract; + + if (Modifier.isFinal(mods)) + attr |= TypeAttributes.Sealed; + + if (Modifier.isPublic(mods)) + attr |= TypeAttributes.Public; + else + attr |= TypeAttributes.NotPublic; + + return attr; + } + + //###################################################################### + } // class JavaType + + //########################################################################## + + private static final class JavaFieldInfo extends FieldInfo { + JavaFieldInfo(Field field) { + super(field.getName(), + VJSLIB_DLL.getType(field.getDeclaringClass()), + translateFieldAttrs(field.getModifiers()), + VJSLIB_DLL.getType(field.getType())); + } + + //translate java modifiers into corresponding .NET Field attributes + static short translateFieldAttrs(int mods) { + short attr = 0; + + if (Modifier.isFinal(mods)) + attr |= FieldAttributes.InitOnly; + + if (Modifier.isPublic(mods)) + attr |= FieldAttributes.Public; + else if (Modifier.isProtected(mods)) + attr |= FieldAttributes.FamORAssem; + else if (Modifier.isPrivate(mods)) + attr |= FieldAttributes.Private; + + if (Modifier.isStatic(mods)) + attr |= FieldAttributes.Static; + + return attr; + } + + } // class JavaFieldInfo + + //########################################################################## + + private static final class JavaConstructorInfo extends ConstructorInfo { + JavaConstructorInfo(Constructor constr) { + super(VJSLIB_DLL.getType(constr.getDeclaringClass()), + JavaMethodInfo.translateMethodAttrs(constr.getModifiers()), + VJSLIB_DLL.getTypes(constr.getParameterTypes())); + } + } + + //########################################################################## + + private static final class JavaMethodInfo extends MethodInfo { + + JavaMethodInfo(String name, Type declType, int attrs, + Type returnType, Type[] paramTypes) { + super(name, declType, declType, attrs, returnType, paramTypes); + } + + static MethodInfo getMethod(Method method) { + String name = method.getName(); + if (name.equals("toString")) + name = "ToString"; + else if(name.equals("equals")) + name = "Equals"; + else if (name.equals("hashCode")) + name = "GetHashCode"; + return new JavaMethodInfo + (name, VJSLIB_DLL.getType(method.getDeclaringClass()), + translateMethodAttrs(method.getModifiers()), + VJSLIB_DLL.getType(method.getReturnType()), + VJSLIB_DLL.getTypes(method.getParameterTypes())); + } + + static short translateMethodAttrs(int mods) { + short attr = 0; + + if (Modifier.isAbstract(mods)) + attr |= MethodAttributes.Abstract; + + if (Modifier.isFinal(mods)) + attr |= MethodAttributes.Final; + + if (Modifier.isPublic(mods)) + attr |= MethodAttributes.Public; + else if (Modifier.isProtected(mods)) + attr |= MethodAttributes.FamORAssem; + else if (Modifier.isPrivate(mods)) + attr |= MethodAttributes.Private; + + if (Modifier.isStatic(mods)) + attr |= MethodAttributes.Static; + else + attr |= MethodAttributes.Virtual; + + //if (Modifier.isSynchronized(mods)) + // attr |= MethodAttributes.Synchronized; + + return attr; + } + } // class JavaMethodInfo + + //########################################################################## + +} // class VJSAssembly -- cgit v1.2.3