private EcmaCil.MethodMeta EnqueueMethod(MethodBase aMethod, object aSource, string aSourceType) { if (mLogEnabled) { LogMapPoint(aSource, aSourceType, aMethod); } if (aMethod.IsGenericMethodDefinition) { throw new Exception("Cannot queue generic method definitions"); } Type xReturnType = null; var xMethodInfo = aMethod as MethodInfo; if (xMethodInfo != null) { xReturnType = xMethodInfo.ReturnType; } else { xReturnType = typeof(void); } var xQueuedMethod = new QueuedMethod(aMethod.DeclaringType, aMethod, (from item in aMethod.GetParameters() select item.ParameterType).ToArray(), xReturnType); EcmaCil.MethodMeta xMethodMeta; if(mMethods.TryGetValue(xQueuedMethod, out xMethodMeta)){ return xMethodMeta; } var xDeclaringType = EnqueueType(aMethod.DeclaringType, aMethod, "Declaring type"); xMethodMeta = new EcmaCil.MethodMeta(); mMethodMetaToMethod.Add(xMethodMeta, aMethod); xMethodMeta.DeclaringType = xDeclaringType; xDeclaringType.Methods.Add(xMethodMeta); mMethods.Add(xQueuedMethod, xMethodMeta); mQueue.Enqueue(xQueuedMethod); return xMethodMeta; }
private void ScanMethod(QueuedMethod aMethod, EcmaCil.MethodMeta aMethodMeta) { // todo: add support for plugs #if DEBUG aMethodMeta.Data[EcmaCil.DataIds.DebugMetaId] = aMethod.Method.GetFullName(); #endif aMethodMeta.IsVirtual = aMethod.Method.IsVirtual; aMethodMeta.IsPublic = aMethod.Method.IsPublic; var xMethod = aMethod.Method; aMethodMeta.StartsNewVirtualTree = aMethodMeta.IsVirtual && ((aMethod.Method.Attributes & MethodAttributes.NewSlot) == MethodAttributes.NewSlot); var xParamOffset = 0; if (!aMethod.Method.IsStatic) { xParamOffset = 1; } var xMethodParameters = aMethod.Method.GetParameters(); aMethodMeta.Parameters = new EcmaCil.MethodParameterMeta[xMethodParameters.Length + xParamOffset]; if (!aMethod.Method.IsStatic) { aMethodMeta.Parameters[0] = new EcmaCil.MethodParameterMeta { IsByRef = aMethod.Method.DeclaringType.IsValueType, PropertyType = EnqueueType(aMethod.Method.DeclaringType, aMethod, "Declaring type") }; #if DEBUG aMethodMeta.Parameters[0].Data[EcmaCil.DataIds.DebugMetaId] = "$this"; #endif } for (int i = 0; i < xMethodParameters.Length; i++) { var xParam = xMethodParameters[i]; var xParamType = xParam.ParameterType; var xParamMeta = aMethodMeta.Parameters[i + xParamOffset] = new EcmaCil.MethodParameterMeta(); var xType = EnqueueType(xParamType, aMethod, "parameter"); #if DEBUG var xSB = new StringBuilder(); xSB.Append(xParam.Name); xSB.Append(": "); if (xParamMeta.IsByRef) { xSB.Append("ref "); } xSB.Append(xParamType.ToString()); xParamMeta.Data[EcmaCil.DataIds.DebugMetaId] = xSB.ToString(); #endif xParamMeta.PropertyType = xType; } if (aMethodMeta.IsVirtual && ((aMethod.Method.Attributes & MethodAttributes.NewSlot) != MethodAttributes.NewSlot)) { // method is override // now need to find parent method, just one level up, because when the parent method is scanned, its parent method will be found.. var xBaseType = aMethod.Method.DeclaringType; #if DEBUG if (xBaseType == null) { throw new Exception("New virtual method found, but declaring type has no base type"); } #endif var xBindFlags = BindingFlags.Instance; if (xMethod.IsPublic) { xBindFlags |= BindingFlags.Public; } else { xBindFlags |= BindingFlags.NonPublic; } var xFoundMethod = xBaseType.GetMethod(aMethod.Method.Name, xBindFlags, null, (from item in xMethodParameters select item.ParameterType).ToArray(), null); if (xFoundMethod != null) { EnqueueMethod(xFoundMethod, aMethod, "Overridden method"); } } var xMethodInfo = aMethod.Method as MethodInfo; var xReturnType = typeof(void); if (xMethodInfo != null) { xReturnType = xMethodInfo.ReturnType; } if (xReturnType != typeof(void)) { aMethodMeta.ReturnType = EnqueueType(xReturnType, aMethod.Method, "Return Type"); } aMethodMeta.IsStatic = aMethod.Method.IsStatic; ScanMethodBody(aMethod, aMethodMeta); }
protected override void ScanMethodBody(QueuedMethod aMethod, EcmaCil.MethodMeta aMethodMeta) { base.ScanMethodBody(aMethod, aMethodMeta); }
protected virtual void ScanMethodBody(QueuedMethod aMethod, EcmaCil.MethodMeta aMethodMeta) { var xBody = aMethod.Method.GetMethodBody(); if (xBody != null) { var xBodyMeta = aMethodMeta.Body = new EcmaCil.MethodBodyMeta(); xBodyMeta.InitLocals = xBody.InitLocals; #region handle exception handling clauses if (xBody.ExceptionHandlingClauses.Count > 0) { throw new Exception("ExceptionHandlers are not supported yet"); } #endregion #region handle locals xBodyMeta.LocalVariables = new EcmaCil.LocalVariableMeta[xBody.LocalVariables.Count]; for (int i = 0; i < xBody.LocalVariables.Count; i++) { var xVar = xBody.LocalVariables[i]; var xVarMeta = xBodyMeta.LocalVariables[i] = new EcmaCil.LocalVariableMeta(); xVarMeta.LocalType = EnqueueType(xVar.LocalType, aMethod, "Local variable"); #if DEBUG xVarMeta.Data[EcmaCil.DataIds.DebugMetaId] = xVar.LocalType.ToString(); #endif } #endregion //List<EcmaCil.IL.BaseInstruction> xInstructions; var xILOffsetToInstructionOffset = new Dictionary<int, int>(); var xInstructionOffsetToILOffset = new Dictionary<int, int>(); var xSecondStageInits = new List<Action<EcmaCil.MethodMeta>>(); var xILStream = xBody.GetILAsByteArray(); foreach (var xPosition in ILStreamPositionReader.GetIndexes(xILStream)) { xILOffsetToInstructionOffset.Add(xPosition.Key, xPosition.Value); xInstructionOffsetToILOffset.Add(xPosition.Value, xPosition.Key); } xBodyMeta.Instructions = ScanMethodBody_DoIt(aMethod.Method, aMethodMeta, xILOffsetToInstructionOffset, xInstructionOffsetToILOffset).ToArray(); } }
private BaseInstruction CreateInstructionMeta(QueuedMethod aMethod, EcmaCil.MethodMeta aMethodMeta, Instruction curInstruction, IDictionary<int, int> aILToInstructionOffset, IDictionary<int, int> aInstructionToILOffset, int aCurrentIndex, IList<Action<EcmaCil.MethodMeta>> aSecondStageInits, int aNextIndex) { switch (curInstruction.OpCode.Code) { case Code.Nop: return new InstructionNone(InstructionKindEnum.Nop, aCurrentIndex); case Code.Pop: return new InstructionNone(InstructionKindEnum.Pop, aCurrentIndex); case Code.Ldc_I4_S: return new InstructionInt32(GetInstructionKind(curInstruction.OpCode.Code), aCurrentIndex, (int)(sbyte)curInstruction.Operand); case Code.Stloc_0: return new InstructionInt32(InstructionKindEnum.Stloc, aCurrentIndex, 0); case Code.Stloc_1: return new InstructionInt32(InstructionKindEnum.Stloc, aCurrentIndex, 1); case Code.Ldloc_0: return new InstructionLocal(InstructionKindEnum.Ldloc, aCurrentIndex, aMethodMeta.Body.LocalVariables[0]); case Code.Ldloc_1: return new InstructionLocal(InstructionKindEnum.Ldloc, aCurrentIndex, aMethodMeta.Body.LocalVariables[1]); case Code.Ldloc_2: return new InstructionLocal(InstructionKindEnum.Ldloc, aCurrentIndex, aMethodMeta.Body.LocalVariables[2]); case Code.Call: return new InstructionMethod(InstructionKindEnum.Call, aCurrentIndex, EnqueueMethod(curInstruction.Operand as MethodReference, aMethod.Method, "Operand value")); case Code.Callvirt: return new InstructionMethod(InstructionKindEnum.Callvirt, aCurrentIndex, EnqueueMethod(curInstruction.Operand as MethodReference, aMethod.Method, "Operand value")); case Code.Stloc_2: return new InstructionLocal(InstructionKindEnum.Stloc, aCurrentIndex, aMethodMeta.Body.LocalVariables[2]); case Code.Stloc_3: return new InstructionLocal(InstructionKindEnum.Stloc, aCurrentIndex, aMethodMeta.Body.LocalVariables[3]); case Code.Ret: return new InstructionNone(InstructionKindEnum.Ret, aCurrentIndex); case Code.Ldarg_0: return new InstructionArgument(InstructionKindEnum.Ldarg, aCurrentIndex, aMethodMeta.Parameters[0]); case Code.Ldarg_1: return new InstructionArgument(InstructionKindEnum.Ldarg, aCurrentIndex, aMethodMeta.Parameters[1]); case Code.Add: return new InstructionNone(InstructionKindEnum.Add, aCurrentIndex); case Code.Ldstr: return new InstructionString(InstructionKindEnum.Ldstr, aCurrentIndex, (string)curInstruction.Operand); case Code.Newobj: return new InstructionMethod(InstructionKindEnum.Newobj, aCurrentIndex, EnqueueMethod(curInstruction.Operand as MethodReference, aMethod.Method, "Operand value")); case Code.Br_S: case Code.Brfalse_S: var xInstr = new InstructionBranch(GetInstructionKind(curInstruction.OpCode.Code), aCurrentIndex); var xTargetInstr = (Instruction)curInstruction.Operand; var xTargetOffset = xTargetInstr.Offset; aSecondStageInits.Add(delegate(EcmaCil.MethodMeta aTheMethod) { xInstr.Target = aTheMethod.Body.Instructions[aILToInstructionOffset[xTargetOffset]]; }); return xInstr; // case //case OperandType.InlineNone: // { // xInstrMeta = new InstructionNone(GetInstructionKind(xInstr.OpCode.Code), i + xOffset); // break; // } //case OperandType.ShortInlineI: // { // xInstrMeta = new InstructionInt32(GetInstructionKind(xInstr.OpCode.Code), i + xOffset, (int)(sbyte)xInstr.Operand); // break; // } default: throw new Exception("Op '" + curInstruction.OpCode.Code + "' not implemented!"); } }
protected virtual void ScanMethodBody(QueuedMethod aMethod, EcmaCil.MethodMeta aMethodMeta) { if (aMethod.Method.HasBody) { var xBody = aMethod.Method.Body; var xBodyMeta = aMethodMeta.Body = new EcmaCil.MethodBodyMeta(); xBodyMeta.InitLocals = xBody.InitLocals; #region handle exception handling clauses if (xBody.HasExceptionHandlers) { throw new Exception("ExceptionHandlers are not supported yet"); } #endregion #region handle locals xBodyMeta.LocalVariables = new EcmaCil.LocalVariableMeta[xBody.Variables.Count]; for (int i = 0; i < xBody.Variables.Count; i++) { var xVar = xBody.Variables[i]; var xVarMeta = xBodyMeta.LocalVariables[i] = new EcmaCil.LocalVariableMeta(); xVarMeta.LocalType = EnqueueType(xVar.VariableType, aMethod, "Local variable"); #if DEBUG xVarMeta.Data[EcmaCil.DataIds.DebugMetaId] = xVar.Name + ":" + xVar.VariableType.ToString(); #endif } #endregion xBodyMeta.Instructions = new EcmaCil.IL.BaseInstruction[xBody.Instructions.Count]; var xILOffsetToInstructionOffset = new Dictionary<int, int>(); var xInstructionOffsetToILOffset = new Dictionary<int, int>(); var xSecondStageInits = new List<Action<EcmaCil.MethodMeta>>(); for (int i = 0; i < xBody.Instructions.Count; i++) { xILOffsetToInstructionOffset.Add(xBody.Instructions[i].Offset, i); xInstructionOffsetToILOffset.Add(i, xBody.Instructions[i].Offset); } for (int i = 0; i < xBody.Instructions.Count; i++) { var xInstr = xBody.Instructions[i]; xBodyMeta.Instructions[i] = CreateInstructionMeta(aMethod, aMethodMeta, xInstr, xILOffsetToInstructionOffset, xInstructionOffsetToILOffset, i, xSecondStageInits, i + 1); } if (xSecondStageInits.Count > 0) { foreach (var xInit in xSecondStageInits) { xInit(aMethodMeta); } } } }
private void ScanMethod(QueuedMethod aMethod, EcmaCil.MethodMeta aMethodMeta) { // todo: add support for plugs #if DEBUG aMethodMeta.Data[EcmaCil.DataIds.DebugMetaId] = aMethod.Method.ToString(); #endif var xParamOffset = 0; if (!aMethod.Method.IsStatic) { xParamOffset = 1; } aMethodMeta.Parameters = new EcmaCil.MethodParameterMeta[aMethod.Method.Parameters.Count + xParamOffset]; if (!aMethod.Method.IsStatic) { aMethodMeta.Parameters[0] = new EcmaCil.MethodParameterMeta { IsByRef = aMethod.Method.DeclaringType.IsValueType, PropertyType = EnqueueType(aMethod.Method.DeclaringType, aMethod, "Declaring type") }; #if DEBUG aMethodMeta.Parameters[0].Data[EcmaCil.DataIds.DebugMetaId] = "$this"; #endif } for(int i = 0; i < aMethod.Method.Parameters.Count;i++){ var xParam = aMethod.Method.Parameters[i]; var xParamType = xParam.ParameterType; if (xParamType is GenericParameter) { // todo: resolve generics. throw new NotImplementedException(); } var xParamMeta = aMethodMeta.Parameters[i + xParamOffset] = new EcmaCil.MethodParameterMeta(); //if (xParamType is ReferenceType) //{ // xParamType = ((ReferenceType)xParamType).ElementType; // xParamMeta.IsByRef = true; //} var xType = EnqueueType(xParamType, aMethod, "parameter"); #if DEBUG var xSB = new StringBuilder(); xSB.Append(xParam.Name); xSB.Append(": "); if (xParamMeta.IsByRef) { xSB.Append("ref "); } xSB.Append(xParamType.ToString()); xParamMeta.Data[EcmaCil.DataIds.DebugMetaId] = xSB.ToString(); #endif xParamMeta.PropertyType = xType; } if (aMethod.Method.ReturnType.FullName != "System.Void") { aMethodMeta.ReturnType = EnqueueType(aMethod.Method.ReturnType, aMethod.Method, "Return Type"); } aMethodMeta.IsStatic = aMethod.Method.IsStatic; ScanMethodBody(aMethod, aMethodMeta); #region Virtuals scan if (aMethod.Method.IsVirtual) { if (aMethod.Method.HasGenericParameters) { throw new Exception("GEnerics not yet fully supported"); } // For virtuals we need to climb up the type tree // and find the top base method. We then add that top // node to the mVirtuals list. We don't need to add the // types becuase adding DeclaringType will already cause // all ancestor types to be added. var xVirtMethod = aMethod.Method; TypeReference xVirtType = aMethod.Method.DeclaringType; xVirtMethod = xVirtMethod.GetOriginalBaseMethod(); #region old code // MethodReference xNewVirtMethod = null; // while (true) // { // var xNewVirtType = xVirtType.Resolve(); // if (xNewVirtType.HasGenericParameters) // { // throw new Exception("Generics not fully supported yet!"); // } // if (xNewVirtType == null) // { // xVirtType = null; // } // else // { //#warning // todo: verify if next code works ok with generics // var xTempNewVirtMethod = xNewVirtType. .m.Methods..GetMethod(aMethod.Method.Name, aMethod.Method.Parameters); // if (xTempNewVirtMethod !=null) // { // if (xTempNewVirtMethod.IsVirtual) // { // xNewVirtMethod = xTempNewVirtMethod; // } // } // else // { // xNewVirtMethod = null; // } // } // if (xNewVirtMethod == null) // { // if (mVirtuals.ContainsKey(aMethod)) // { // xVirtMethod = null; // } // break; // } // xVirtMethod = xNewVirtMethod.Resolve(); // xVirtType = xNewVirtType.BaseType; // if (xVirtType == null) // { // break; // } // } #endregion old code if (xVirtMethod!=null) { EnqueueMethod(xVirtMethod, aMethod, "Virtual Base"); foreach (var xType in mTypes) { if (xType.Key.Type.IsSubclassOf(xVirtMethod.DeclaringType)) { //xType.Key.Type.res //var xNewMethod = xType.Key.Type.Methods.GetMethod(aMethod.Method.Name, aMethod.Method.Parameters); //if (xNewMethod != null) //{ // // We need to check IsVirtual, a non virtual could // // "replace" a virtual above it? // // MtW: correct // if (xNewMethod.IsVirtual) // { // EnqueueMethod(xNewMethod, aMethod, "Virtual Downscan"); // } //} throw new NotImplementedException(); } } } } #endregion }
private EcmaCil.MethodMeta EnqueueMethod(MethodReference aMethod, object aSource, string aSourceType) { if (mLogEnabled) { LogMapPoint(aSource, aSourceType, aMethod); } List<TypeReference> xTypeArgs = null; var xGenSpec = aMethod as GenericInstanceMethod; TypeDefinition xTypeDef; MethodDefinition xMethodDef; TypeReference xRefType; if (xGenSpec != null) { xMethodDef = ResolveMethod(xGenSpec.ElementMethod); xRefType = xGenSpec.DeclaringType; xTypeArgs = new List<TypeReference>(); foreach (TypeReference xArg in xGenSpec.GenericArguments) { xTypeArgs.Add(xArg); } } else { xMethodDef = ResolveMethod(aMethod); xRefType = aMethod.DeclaringType; } #region resolve type xTypeDef = xRefType as TypeDefinition; if (xTypeDef == null) { var xGenType = xRefType as GenericInstanceType; if (xGenType != null) { xTypeDef = ResolveType(xGenType.DeclaringType); if (xTypeArgs == null) { xTypeArgs = new List<TypeReference>(); } for (int i = 0; i < xGenType.GenericArguments.Count; i++) { xTypeArgs.Insert(i, xGenType.GenericArguments[i]); } } else { xTypeDef = ResolveType(xRefType); } } #endregion var xQueuedMethod = new QueuedMethod(xTypeDef, xMethodDef, (xTypeArgs == null ? null : xTypeArgs.ToArray())); EcmaCil.MethodMeta xMethodMeta; if(mMethods.TryGetValue(xQueuedMethod, out xMethodMeta)){ return xMethodMeta; } var xDeclaringType = EnqueueType(xRefType, aMethod, "Declaring type"); xMethodMeta = new EcmaCil.MethodMeta(); xMethodMeta.DeclaringType = xDeclaringType; xDeclaringType.Methods.Add(xMethodMeta); mMethods.Add(xQueuedMethod, xMethodMeta); mQueue.Enqueue(xQueuedMethod); return xMethodMeta; }