// // Copyright (c) Microsoft Corporation. All rights reserved. // using System; using System.Text; /////////////////////////////////////////////////////////////////////// // // The Bartok.msil.Signature* classes represent the signatures read // from the Blob heap of the input file(s). // // Since the signatures have references to MetaData* objects, the // signatures are initially just an array of bytes. When all the // MetaData objects have been created, the array of bytes is processed // and the references resolved. // ////////////////////////////////////////////////////////////////////// namespace Bartok.MSIL { public abstract class Signature { // Constructor Methods internal virtual Signature resolve(MetaDataLoader mdLoader) { return this; } internal virtual Signature resolveTypeSpec(MetaDataLoader mdLoader) { return this; } // Internal Classes public enum CallingConventions: byte { Default = 0x00, Unmanaged_cdecl = 0x01, Unmanaged_sdtcall = 0x02, Unmanaged_thiscall = 0x03, Unmanaged_fastcall = 0x04, VarArg = 0x05, Field = 0x06, LocalVar = 0x07, Property = 0x08, Unmanaged = 0x09, Mask = 0x0f, Generic = 0x10, HasThis = 0x20, ExplicitThis = 0x40 } // REVIEW: Consider memoizing these types. public class Type { // Constructor Methods // elementType \in // { VOID, BOOLEAN, CHAR, I1, U1, I2, U2, I4, U4, I8, U8, R4, R8, // U, I, OBJECT, STRING, TYPEDBYREF } internal Type(ElementTypes elementType) { this.elementType = elementType; } // elementType \in {VALUETYPE, CLASS} internal Type(ElementTypes elementType, MetaDataObject classObject) { this.elementType = elementType; this.classObject = classObject; } // elementType \in {SZARRAY, CMOD_OPT, CMOD_REQD, PINNED, PTR, BYREF} internal Type(ElementTypes elementType, Type typeObject, Modifier modifierList) { this.elementType = elementType; this.typeObject = typeObject; this.modifierList = modifierList; } // elementType is ARRAY internal Type(ElementTypes elementType, Type typeObject, uint[] lowerBounds, uint[] upperBounds) { this.elementType = elementType; this.typeObject = typeObject; this.lowerBounds = lowerBounds; this.upperBounds = upperBounds; } // elementType is FNPTR internal Type(ElementTypes elementType, SignatureMethod methodSignature) { this.elementType = elementType; this.methodSignature = methodSignature; } // elementType \in {VAR, MVAR} internal Type(ElementTypes elementType, uint number) { this.elementType = elementType; this.number = number; } // elementType is GENERICINST internal Type(ElementTypes elementType, Type typeObject, Type[] typeList) { this.elementType = elementType; this.typeObject = typeObject; this.typeList = typeList; } // Accessors public ElementTypes ElementType { get { return elementType; } } public MetaDataObject ClassObject { // REVIEW: throw on inconsistent elementtype? get { return classObject; } } public Type TypeObject { // REVIEW: throw on inconsistent elementtype? get { return typeObject; } } public Type[] TypeList { // REVIEW: throw on inconsistent elementtype? get { return typeList; } } public Modifier ModifierList { // REVIEW: throw on inconsistent elementtype? get { return modifierList; } } public uint[] UpperBounds { // REVIEW: throw on inconsistent elementtype? get { return upperBounds; } } public uint[] LowerBounds { // REVIEW: throw on inconsistent elementtype? get { return lowerBounds; } } public int Rank { get { return upperBounds.Length; } } public SignatureMethod MethodSignature { // REVIEW: throw on inconsistent elementtype? get { return methodSignature; } } public uint Number { // REVIEW: throw on inconsistent elementtype? get { return number; } } #region SyncBlockHack // Equality methods public override bool Equals(Object o) { return this == o; } public override int GetHashCode() { if (hash == 0) { if (nextHash == 0) { nextHash++; } hash = nextHash++; } return hash; } #endregion // Debug Methods public override string ToString() { StringBuilder sb = new StringBuilder("Type(0x"); // BUGBUG: use symbolic printing when selfhost can do so sb.Append(((uint) elementType).ToString("x")); sb.Append(","); for (Modifier modifier = this.modifierList; modifier != null; modifier = modifier.next) { sb.Append(modifier); sb.Append(","); } if (this.typeObject != null) { sb.Append(this.typeObject); sb.Append(","); } if (this.typeList != null) { sb.Append("typelist["); sb.Append(this.typeList[0]); for (int i = 1; i < this.typeList.Length; i++) { sb.Append(","); sb.Append(this.typeList[i]); } sb.Append("],"); } if (this.classObject != null) { sb.Append(this.classObject); sb.Append(","); } if (this.lowerBounds != null) { sb.Append("lowerbounds["); sb.Append(this.lowerBounds[0]); for (int i = 1; i < this.lowerBounds.Length; i++) { sb.Append(","); sb.Append(this.lowerBounds[i]); } sb.Append("],"); } if (this.upperBounds != null) { sb.Append("upperbounds["); sb.Append(this.upperBounds[0]); for (int i = 1; i < this.upperBounds.Length; i++) { sb.Append(","); sb.Append(this.upperBounds[i]); } sb.Append("],"); } if (this.methodSignature != null) { sb.Append(methodSignature); sb.Append(","); } if (this.elementType == ElementTypes.VAR || this.elementType == ElementTypes.MVAR) { sb.Append(number); sb.Append(","); } sb.Remove(sb.Length-1, 1); sb.Append(")"); return sb.ToString(); } // State private readonly ElementTypes elementType; private readonly MetaDataObject classObject; private readonly Type typeObject; private readonly Type[] typeList; private readonly Modifier modifierList; private readonly uint[] lowerBounds; private readonly uint[] upperBounds; private readonly SignatureMethod methodSignature; private readonly uint number; #region SyncBlockHack private int hash; private static int nextHash; #endregion } public class Param { // Constructor Methods internal Param(Modifier modifierList, ElementTypes kind, Type type) { this.modifierList = modifierList; this.kind = kind; this.type = type; } // Access Methods public Modifier ModifierList { get { return this.modifierList; } } // One of ElementTypes.{END, BYREF, TYPEDBYREF}, // ElementTypes.END means no flag present public ElementTypes Kind { get { return this.kind; } } public Type Type { get { return this.type; } } // Debug Methods public override string ToString() { StringBuilder sb = new StringBuilder("Parameter("); for (Modifier modifier = this.modifierList; modifier != null; modifier = modifier.next) { sb.Append(modifier); sb.Append(","); } sb.Append(((uint) kind).ToString("x")); sb.Append(","); sb.Append(type); sb.Append(")"); return sb.ToString(); } // State private readonly Modifier modifierList; private readonly ElementTypes kind; private readonly Type type; } public class Modifier { // Constructor Methods internal Modifier(ElementTypes kind, MetaDataObject type, Modifier next) { this.kind = kind; this.type = type; this.next = next; } // Accessor public ElementTypes Kind { get { return kind; } } public MetaDataObject Type { get { return type; } } public Modifier Next { get { return next; } } // Debug Methods public override string ToString() { return (((uint) kind).ToString("x")+" "+type); } // State private readonly ElementTypes kind; private readonly MetaDataObject type; internal readonly Modifier next; } } internal class SignatureBuffer: Signature { // Constructor Methods internal SignatureBuffer(byte[] buffer) { this.buffer = buffer; } internal override Signature resolve(MetaDataLoader mdLoader) { uint unmaskedCallingConvention = uncompressInt(this.buffer, ref this.offset); CallingConventions callingConvention = (CallingConventions) (unmaskedCallingConvention & (uint) CallingConventions.Mask); switch (callingConvention) { case CallingConventions.Field: { // Section 22.2.4 of ECMA spec, partition II Type type = this.parseSignatureType(mdLoader); if (this.offset != this.buffer.Length) { throw new MetaDataLoader.IllegalMetaDataFormatException("Only read "+this.offset+" bytes of "+this); } return new SignatureField(type); } case CallingConventions.LocalVar: { // Section 22.2.6 of ECMA spec, partition II uint count = uncompressInt(this.buffer, ref this.offset); Type[] locals = new Type[count]; for (int i = 0; i < count; i++) { locals[i] = parseSignatureLocal(mdLoader); } if (this.offset != this.buffer.Length) { throw new MetaDataLoader.IllegalMetaDataFormatException("Only read "+this.offset+" bytes of "+this); } return new SignatureLocalVar(locals); } case CallingConventions.Property: { // Section 22.2.5 of ECMA spec, partition II uint paramCount = uncompressInt(this.buffer, ref this.offset); Type returnType = this.parseSignatureType(mdLoader); Param[] parameters = new Param[paramCount]; for (int i = 0; i < paramCount; i++) { parameters[i] = this.parseSignatureParam(mdLoader); } if (this.offset != this.buffer.Length) { throw new MetaDataLoader.IllegalMetaDataFormatException("Only read "+this.offset+" bytes of "+this); } return new SignatureProperty(returnType, parameters); } default: { // Section2 22.2.1, 22.2.2, and 22.2.3 of ECMA spec, II uint genericParamCount = 0; if((unmaskedCallingConvention & (uint) CallingConventions.Generic) != 0) { genericParamCount = uncompressInt(this.buffer, ref this.offset); } uint paramCount = uncompressInt(this.buffer, ref this.offset); Type returnType = this.parseSignatureType(mdLoader); int sentinelLocation = -1; Param[] parameters = new Param[paramCount]; for (int i = 0; i < paramCount; i++) { byte first = this.buffer[this.offset]; if (first == (byte) ElementTypes.SENTINEL) { sentinelLocation = i; this.offset++; } parameters[i] = this.parseSignatureParam(mdLoader); } if (this.offset != this.buffer.Length) { throw new MetaDataLoader.IllegalMetaDataFormatException("Only read "+this.offset+" bytes of "+this); } // pass unmasked convention because user of signature (e.g. memberRef) // may need to know the static vs. instance status of the method // Erik, 4/13/01 return new SignatureMethod((CallingConventions) unmaskedCallingConvention, genericParamCount, returnType, parameters, sentinelLocation); } } } internal override Signature resolveTypeSpec(MetaDataLoader mdLoader) { Type type = this.parseSignatureType(mdLoader); if (this.offset != this.buffer.Length) { throw new MetaDataLoader.IllegalMetaDataFormatException("Only read "+this.offset+" bytes of "+this); } return new SignatureTypeSpec(type); } internal static uint uncompressInt(byte[] buffer, ref int offset) { byte first = buffer[offset]; if ((first & 0x80) == 0x00) { // 0??? ????: one byte encoding offset++; return first; } else if ((first & 0xC0) == 0x80) { // 10?? ????: two byte encoding byte second = buffer[offset+1]; offset += 2; return (((first & 0x3fU) << 8) | second); } else { // 11?? ????: four byte encoding byte second = buffer[offset+1]; byte third = buffer[offset+2]; byte fourth = buffer[offset+3]; offset += 4; return (((uint) ((first & 0x3fU) << 24)) | ((uint) (second << 16)) | ((uint) (third << 8)) | ((uint) fourth)); } } private MetaDataObject uncompressToken(MetaDataLoader mdLoader) { uint codedToken = uncompressInt(this.buffer, ref this.offset); MetaDataLoader.TokenType tokenType = ((((codedToken & 0x2) == 0) ? (((codedToken & 0x1) == 0) ? MetaDataLoader.TokenType.TypeDef : MetaDataLoader.TokenType.TypeRef) : (((codedToken & 0x1) == 0) ? MetaDataLoader.TokenType.TypeSpec : MetaDataLoader.TokenType.BaseType))); int token = (int) (codedToken >> 2) | (int) tokenType; return mdLoader.getObjectFromToken(token); } private Type parseSignatureType(MetaDataLoader mdLoader) { ElementTypes elementType = (ElementTypes) this.buffer[this.offset]; this.offset++; switch (elementType) { case ElementTypes.VOID: case ElementTypes.BOOLEAN: case ElementTypes.CHAR: case ElementTypes.I1: case ElementTypes.U1: case ElementTypes.I2: case ElementTypes.U2: case ElementTypes.I4: case ElementTypes.U4: case ElementTypes.I8: case ElementTypes.U8: case ElementTypes.R4: case ElementTypes.R8: case ElementTypes.U: case ElementTypes.I: case ElementTypes.OBJECT: case ElementTypes.STRING: case ElementTypes.TYPEDBYREF: { return new Type(elementType); } case ElementTypes.VALUETYPE: case ElementTypes.CLASS: { // Followed by: TypeDefOrRefEncoded MetaDataObject classObject = uncompressToken(mdLoader); return new Type(elementType, classObject); } case ElementTypes.SZARRAY: { // Followed by: CustomMod* Type Modifier modifierList = this.parseSignatureModifiers(mdLoader); Type type = this.parseSignatureType(mdLoader); return new Type(elementType, type, modifierList); } case ElementTypes.ARRAY: { // Followed by: Type ArrayShape Type type = this.parseSignatureType(mdLoader); uint rank = uncompressInt(this.buffer, ref this.offset); if (rank == 0) { throw new MetaDataLoader.IllegalMetaDataFormatException("ARRAY with rank 0"); } uint[] upperBounds = new uint[rank]; uint[] lowerBounds = new uint[rank]; uint numUpperBounds = uncompressInt(this.buffer, ref this.offset); if (numUpperBounds > rank) { throw new MetaDataLoader.IllegalMetaDataFormatException("ARRAY with upper bounds > rank"); } for (int i = 0; i < numUpperBounds; i++) { upperBounds[i] = uncompressInt(this.buffer, ref this.offset); } uint numLowerBounds = uncompressInt(this.buffer, ref this.offset); if (numLowerBounds > rank) { throw new MetaDataLoader.IllegalMetaDataFormatException("ARRAY with lower bounds > rank"); } for (int i = 0; i < numLowerBounds; i++) { lowerBounds[i] = uncompressInt(this.buffer, ref this.offset); } return new Type(elementType, type, lowerBounds, upperBounds); } case ElementTypes.FNPTR: { // Followed by: MethodDefSig or MethodRefSig uint unmaskedCallingConvention = uncompressInt(this.buffer, ref this.offset); CallingConventions callingConvention = (CallingConventions) (unmaskedCallingConvention & (uint) CallingConventions.Mask); if (callingConvention == CallingConventions.Field || callingConvention == CallingConventions.LocalVar || callingConvention == CallingConventions.Property) { throw new MetaDataLoader.IllegalMetaDataFormatException("FNPTR surprised by calling convention "+callingConvention); } if ((unmaskedCallingConvention & (uint) CallingConventions.Generic) != 0) { throw new MetaDataLoader.IllegalMetaDataFormatException("FNPTR generic unimplemented - check to see if legal"); } uint paramCount = uncompressInt(this.buffer, ref this.offset); Type returnType = this.parseSignatureType(mdLoader); int sentinelLocation = -1; Param[] parameters = new Param[paramCount]; for (int i = 0; i < paramCount; i++) { byte first = this.buffer[this.offset]; if (first == (byte) ElementTypes.SENTINEL) { sentinelLocation = i; this.offset++; } parameters[i] = this.parseSignatureParam(mdLoader); } SignatureMethod signature = new SignatureMethod(callingConvention, 0, returnType, parameters, sentinelLocation); return new Type(elementType, signature); } case ElementTypes.VAR: case ElementTypes.MVAR: { // Generic type variables uint number = uncompressInt(this.buffer, ref this.offset); return new Type(elementType, number); } case ElementTypes.GENERICINST: { // Generic type instantiation Type type = this.parseSignatureType(mdLoader); uint typeCount = uncompressInt(this.buffer, ref this.offset); Type[] typeParams = new Type[typeCount]; for (int i = 0; i < typeCount; i++) { Type paramType = this.parseSignatureType(mdLoader); typeParams[i] = paramType; } return new Type(elementType, type, typeParams); } case ElementTypes.CMOD_OPT: case ElementTypes.CMOD_REQD: { // Modifiers this.offset--; Modifier modifierList = this.parseSignatureModifiers(mdLoader); Type type = this.parseSignatureType(mdLoader); return new Type(elementType, type, modifierList); } case ElementTypes.PINNED: case ElementTypes.PTR: case ElementTypes.BYREF: { // Modifiers Type type = this.parseSignatureType(mdLoader); return new Type(elementType, type, (Modifier) null); } default: { throw new MetaDataLoader.IllegalMetaDataFormatException("Unknown signature type: 0x"+((byte) elementType).ToString("x2")+" at "+this.offset+" in "+this); } } } private Modifier parseSignatureModifiers(MetaDataLoader mdLoader) { Modifier result = null; ElementTypes mod = (ElementTypes) this.buffer[this.offset]; while (mod == ElementTypes.CMOD_REQD || mod == ElementTypes.CMOD_OPT) { this.offset++; uint typeEncoded = uncompressInt(this.buffer, ref this.offset); // BUGBUG: type conversion on int. MetaDataObject type = mdLoader.getTypeDefOrRef((int) typeEncoded); result = new Modifier(mod, type, result); if (this.offset < this.buffer.Length) { mod = (ElementTypes) this.buffer[this.offset]; } else { mod = ElementTypes.VOID; } } return result; } private Param parseSignatureParam(MetaDataLoader mdLoader) { Modifier modifierList = this.parseSignatureModifiers(mdLoader); byte first = this.buffer[this.offset]; if (first == (byte) ElementTypes.BYREF) { this.offset++; Type type = this.parseSignatureType(mdLoader); return new Param(modifierList, (ElementTypes) first, type); } else if (first == (byte) ElementTypes.TYPEDBYREF) { this.offset++; return new Param(modifierList, (ElementTypes) first, null); } else { Type type = this.parseSignatureType(mdLoader); return new Param(modifierList, ElementTypes.END, type); } } private Type parseSignatureLocal(MetaDataLoader mdLoader) { ElementTypes first = (ElementTypes) this.buffer[this.offset]; if (first == ElementTypes.PINNED) { this.offset++; Type type = this.parseSignatureType(mdLoader); return new Type(first, type, (Modifier) null); } else { return this.parseSignatureType(mdLoader); } } // Debug Methods public override string ToString() { StringBuilder sb = new StringBuilder("SignatureBuffer("); int bufferSize = this.buffer.Length; if (bufferSize > 0) { sb.Append("0x"); sb.Append(this.buffer[0].ToString("x2")); for (int i = 1; i < bufferSize; i++) { sb.Append(","); sb.Append("0x"); sb.Append(this.buffer[i].ToString("x2")); } } sb.Append(")"); return sb.ToString(); } // State private readonly byte[] buffer; private int offset; } }