/* * 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