/*
* System.Reflection-like API for access to .NET assemblies (DLL & EXE)
*/
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 ch.epfl.lamp.compiler.msil.util.PECustomMod;
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();
PECustomMod pecmod = 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, pecmod, 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();
/* we're about to parse a MethodDefSig, defined in Sec. 23.2.1 of Partition II () */
int callConv = sig.readByte();
// TODO decode HASTHIS from high byte of calling convention
// TODO decode EXPLICITTHIS from high byte of calling convention
// TODO handle VARARG calling convention (not CLS but may show up )
if((callConv & 0x1F) == Signature.GENERIC) {
int genParamCount = sig.decodeInt();
/* genParamCount is ignored because the method's type params will be obtained below
(see: file.GenericParam.getMVarIdxes(row) ) */
}
int paramCount = sig.decodeInt();
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 = paramListBeg + paramCount;
if (paramListEnd > file.ParamDef.rows) {
/* don't try to read param names past ParamDef's row count
Some assembly-writers don't bother to give names for all params. */
paramListEnd = file.ParamDef.rows + 1;
}
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);
int[] mvarIdxes = file.GenericParam.getMVarIdxes(row);
// if(mvarIdxes.length > 0) { System.out.println("Method: " + method); }
for(int i = 0; i < mvarIdxes.length; i++) {
GenericParamAndConstraints mvarAndConstraints = pemodule.getTypeConstraints(mvarIdxes[i]);
// add mvarAndConstraints as i-th MVar in method
((PEMethodInfo)method).addMVar(mvarAndConstraints);
}
}
(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, PECustomMod pecmod, Object value)
{
super(name, PEType.this, attrs, pecmod, 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