private void ScanType(QueuedType aType, EcmaCil.TypeMeta aTypeMeta) { #if DEBUG var xSB = new StringBuilder(); xSB.Append(aType.Type.ToString()); if (aType.Args.Length > 0) { xSB.Append("<"); for (int i = 0; i < aType.Args.Length; i++) { xSB.Append(aType.Args[i].ToString()); if (i < (aType.Args.Length - 1)) { xSB.Append(", "); } } xSB.Append(">"); } aTypeMeta.Data[EcmaCil.DataIds.DebugMetaId] = xSB.ToString(); #endif }
protected override void ScanMethodBody(QueuedMethod aMethod, EcmaCil.MethodMeta aMethodMeta) { base.ScanMethodBody(aMethod, aMethodMeta); }
private void ScanArrayType(QueuedArrayType aArrayType, EcmaCil.ArrayTypeMeta aArrayMeta) { aArrayMeta.Dimensions = aArrayType.ArrayType.GetArrayRank(); // todo: fix? // foreach (ArrayDimension xDimension in aType.ArrayType.Dimensions) //{ // if (xDimension.LowerBound != 0 || xDimension.UpperBound != 0) // { // throw new Exception("Arrays with limited dimensions not supported"); // } //} if (aArrayType.ArrayType.GetArrayRank() != 1) { throw new Exception("Multidimensional arrays not yet supported!"); } #if DEBUG var xSB = new StringBuilder(); xSB.Append(aArrayMeta.ElementType.ToString()); xSB.Append("["); xSB.Append(new String(',', aArrayMeta.Dimensions - 1)); xSB.Append("]"); aArrayMeta.Data[EcmaCil.DataIds.DebugMetaId] = xSB.ToString(); #endif }
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 List<EcmaCil.IL.BaseInstruction> ScanMethodBody_DoIt(MethodBase aMethod, EcmaCil.MethodMeta aMethodMeta, IDictionary<int, int> aILOffsetToInstructionIndex, IDictionary<int, int> aInstructionIndexToILOffset) { var xResult = new List<EcmaCil.IL.BaseInstruction>(aILOffsetToInstructionIndex.Count); var xBody = aMethod.GetMethodBody(); // Cache for use in field and method resolution Type[] xTypeGenArgs = null; Type[] xMethodGenArgs = null; if (aMethod.DeclaringType.IsGenericType) { xTypeGenArgs = aMethod.DeclaringType.GetGenericArguments(); } if (aMethod.IsGenericMethod) { xMethodGenArgs = aMethod.GetGenericArguments(); } // Some methods return no body. Not sure why.. have to investigate // They arent abstracts or icalls... // MtW: how about externs (pinvoke, etc) if (xBody == null) { return null; } var xIL = xBody.GetILAsByteArray(); int xPos = 0; var xInstructionIndex = 0; var xInitSecondStage = new List<Action>(aILOffsetToInstructionIndex.Count); while (xPos < xIL.Length) { ExceptionHandlingClause xCurrentHandler = null; #region Determine current handler // todo: add support for nested handlers using a stack or so.. foreach (ExceptionHandlingClause xHandler in xBody.ExceptionHandlingClauses) { if (xHandler.TryOffset > 0) { if (xHandler.TryOffset <= xPos && (xHandler.TryLength + xHandler.TryOffset + 1) > xPos) // + 1 because index should be less than the try { if (xCurrentHandler == null) { xCurrentHandler = xHandler; continue; } else if (xHandler.TryOffset > xCurrentHandler.TryOffset && (xHandler.TryLength + xHandler.TryOffset) < (xCurrentHandler.TryLength + xCurrentHandler.TryOffset)) { // only replace if the current found handler is narrower xCurrentHandler = xHandler; continue; } } } if (xHandler.HandlerOffset > 0) { if (xHandler.HandlerOffset <= xPos && (xHandler.HandlerOffset + xHandler.HandlerLength + 1) > xPos) { if (xCurrentHandler == null) { xCurrentHandler = xHandler; continue; } else if (xHandler.HandlerOffset > xCurrentHandler.HandlerOffset && (xHandler.HandlerOffset + xHandler.HandlerLength) < (xCurrentHandler.HandlerOffset + xCurrentHandler.HandlerLength)) { // only replace if the current found handler is narrower xCurrentHandler = xHandler; continue; } } } if ((xHandler.Flags & ExceptionHandlingClauseOptions.Filter) > 0) { if (xHandler.FilterOffset > 0) { if (xHandler.FilterOffset <= xPos) { if (xCurrentHandler == null) { xCurrentHandler = xHandler; continue; } else if (xHandler.FilterOffset > xCurrentHandler.FilterOffset) { // only replace if the current found handler is narrower xCurrentHandler = xHandler; continue; } } } } } #endregion OpCodeEnum xOpCodeVal; OpCode xOpCode; int xOpPos = xPos; if (xIL[xPos] == 0xFE) { xOpCodeVal = (OpCodeEnum)(0xFE00 | xIL[xPos + 1]); xOpCode = mOpCodesHi[xIL[xPos + 1]]; xPos = xPos + 2; } else { xOpCodeVal = (OpCodeEnum)xIL[xPos]; xOpCode = mOpCodesLo[xIL[xPos]]; xPos++; } EcmaCil.IL.BaseInstruction xILOpCode = null; Cil.InstructionBranch xBranch; Console.WriteLine(xOpCode.ToString() + " " + xOpCode.OperandType); #region switch(xOpCode.OperandType) switch (xOpCode.OperandType) { // No operand. case OperandType.InlineNone: { #region Inline none options // These shortcut translation regions expand shortcut ops into full ops // This elminates the amount of code required in the assemblers // by allowing them to ignore the shortcuts switch (xOpCodeVal) { case OpCodeEnum.Ldarg_0: xILOpCode = new Cil.InstructionArgument(EcmaCil.IL.InstructionKindEnum.Ldarg, xInstructionIndex, aMethodMeta.Parameters[0]); break; case OpCodeEnum.Ldarg_1: xILOpCode = new Cil.InstructionArgument(EcmaCil.IL.InstructionKindEnum.Ldarg, xInstructionIndex, aMethodMeta.Parameters[1]); break; case OpCodeEnum.Ldarg_2: xILOpCode = new Cil.InstructionArgument(EcmaCil.IL.InstructionKindEnum.Ldarg, xInstructionIndex, aMethodMeta.Parameters[2]); break; case OpCodeEnum.Ldarg_3: xILOpCode = new Cil.InstructionArgument(EcmaCil.IL.InstructionKindEnum.Ldarg, xInstructionIndex, aMethodMeta.Parameters[3]); break; case OpCodeEnum.Ldc_I4_0: xILOpCode = new Cil.InstructionInt32(EcmaCil.IL.InstructionKindEnum.Ldc_I4, xInstructionIndex, 0); break; case OpCodeEnum.Ldc_I4_1: xILOpCode = new Cil.InstructionInt32(EcmaCil.IL.InstructionKindEnum.Ldc_I4, xInstructionIndex, 1); break; case OpCodeEnum.Ldc_I4_2: xILOpCode = new Cil.InstructionInt32(EcmaCil.IL.InstructionKindEnum.Ldc_I4, xInstructionIndex, 2); break; case OpCodeEnum.Ldc_I4_3: xILOpCode = new Cil.InstructionInt32(EcmaCil.IL.InstructionKindEnum.Ldc_I4, xInstructionIndex, 3); break; case OpCodeEnum.Ldc_I4_4: xILOpCode = new Cil.InstructionInt32(EcmaCil.IL.InstructionKindEnum.Ldc_I4, xInstructionIndex, 4); break; case OpCodeEnum.Ldc_I4_5: xILOpCode = new Cil.InstructionInt32(EcmaCil.IL.InstructionKindEnum.Ldc_I4, xInstructionIndex, 5); break; case OpCodeEnum.Ldc_I4_6: xILOpCode = new Cil.InstructionInt32(EcmaCil.IL.InstructionKindEnum.Ldc_I4, xInstructionIndex, 6); break; case OpCodeEnum.Ldc_I4_7: xILOpCode = new Cil.InstructionInt32(EcmaCil.IL.InstructionKindEnum.Ldc_I4, xInstructionIndex, 7); break; case OpCodeEnum.Ldc_I4_8: xILOpCode = new Cil.InstructionInt32(EcmaCil.IL.InstructionKindEnum.Ldc_I4, xInstructionIndex, 8); break; case OpCodeEnum.Ldc_I4_M1: xILOpCode = new Cil.InstructionInt32(EcmaCil.IL.InstructionKindEnum.Ldc_I4, xInstructionIndex, -1); break; case OpCodeEnum.Ldloc_0: xILOpCode = new Cil.InstructionLocal(EcmaCil.IL.InstructionKindEnum.Ldloc, xInstructionIndex, aMethodMeta.Body.LocalVariables[0]); break; case OpCodeEnum.Ldloc_1: xILOpCode = new Cil.InstructionLocal(EcmaCil.IL.InstructionKindEnum.Ldloc, xInstructionIndex, aMethodMeta.Body.LocalVariables[1]); break; case OpCodeEnum.Ldloc_2: xILOpCode = new Cil.InstructionLocal(EcmaCil.IL.InstructionKindEnum.Ldloc, xInstructionIndex, aMethodMeta.Body.LocalVariables[2]); break; case OpCodeEnum.Ldloc_3: xILOpCode = new Cil.InstructionLocal(EcmaCil.IL.InstructionKindEnum.Ldloc, xInstructionIndex, aMethodMeta.Body.LocalVariables[3]); break; case OpCodeEnum.Stloc_0: xILOpCode = new Cil.InstructionLocal(EcmaCil.IL.InstructionKindEnum.Stloc, xInstructionIndex, aMethodMeta.Body.LocalVariables[0]); break; case OpCodeEnum.Stloc_1: xILOpCode = new Cil.InstructionLocal(EcmaCil.IL.InstructionKindEnum.Stloc, xInstructionIndex, aMethodMeta.Body.LocalVariables[1]); break; case OpCodeEnum.Stloc_2: xILOpCode = new Cil.InstructionLocal(EcmaCil.IL.InstructionKindEnum.Stloc, xInstructionIndex, aMethodMeta.Body.LocalVariables[2]); break; case OpCodeEnum.Stloc_3: xILOpCode = new Cil.InstructionLocal(EcmaCil.IL.InstructionKindEnum.Stloc, xInstructionIndex, aMethodMeta.Body.LocalVariables[3]); break; default: xILOpCode = new Cil.InstructionNone((EcmaCil.IL.InstructionKindEnum)xOpCodeVal, xInstructionIndex); break; } #endregion break; } case OperandType.ShortInlineBrTarget: { #region Inline branch // By calculating target, we assume all branches are within a method // So far at least wtih csc, its true. We check it with CheckBranch // just in case. int xTarget = xPos + 1 + (sbyte)xIL[xPos]; CheckBranch(xTarget, xIL.Length); switch (xOpCodeVal) { case OpCodeEnum.Beq_S: xBranch = new Cil.InstructionBranch(EcmaCil.IL.InstructionKindEnum.Beq, xInstructionIndex); xILOpCode = xBranch; xInitSecondStage.Add(delegate { xBranch.Target = xResult[aILOffsetToInstructionIndex[xTarget]]; }); break; case OpCodeEnum.Bge_S: xBranch = new Cil.InstructionBranch(EcmaCil.IL.InstructionKindEnum.Bge, xInstructionIndex); xILOpCode = xBranch; xInitSecondStage.Add(delegate { xBranch.Target = xResult[aILOffsetToInstructionIndex[xTarget]]; }); break; case OpCodeEnum.Bge_Un_S: xBranch = new Cil.InstructionBranch(EcmaCil.IL.InstructionKindEnum.Bge_Un, xInstructionIndex); xILOpCode = xBranch; xInitSecondStage.Add(delegate { xBranch.Target = xResult[aILOffsetToInstructionIndex[xTarget]]; }); break; case OpCodeEnum.Bgt_S: xBranch = new Cil.InstructionBranch(EcmaCil.IL.InstructionKindEnum.Bgt, xInstructionIndex); xILOpCode = xBranch; xInitSecondStage.Add(delegate { xBranch.Target = xResult[aILOffsetToInstructionIndex[xTarget]]; }); break; case OpCodeEnum.Bgt_Un_S: xBranch = new Cil.InstructionBranch(EcmaCil.IL.InstructionKindEnum.Bgt_Un, xInstructionIndex); xILOpCode = xBranch; xInitSecondStage.Add(delegate { xBranch.Target = xResult[aILOffsetToInstructionIndex[xTarget]]; }); break; case OpCodeEnum.Ble_S: xBranch = new Cil.InstructionBranch(EcmaCil.IL.InstructionKindEnum.Ble, xInstructionIndex); xILOpCode = xBranch; xInitSecondStage.Add(delegate { xBranch.Target = xResult[aILOffsetToInstructionIndex[xTarget]]; }); break; case OpCodeEnum.Ble_Un_S: xBranch = new Cil.InstructionBranch(EcmaCil.IL.InstructionKindEnum.Ble_Un, xInstructionIndex); xILOpCode = xBranch; xInitSecondStage.Add(delegate { xBranch.Target = xResult[aILOffsetToInstructionIndex[xTarget]]; }); break; case OpCodeEnum.Blt_S: xBranch = new Cil.InstructionBranch(EcmaCil.IL.InstructionKindEnum.Blt, xInstructionIndex); xILOpCode = xBranch; xInitSecondStage.Add(delegate { xBranch.Target = xResult[aILOffsetToInstructionIndex[xTarget]]; }); break; case OpCodeEnum.Blt_Un_S: xBranch = new Cil.InstructionBranch(EcmaCil.IL.InstructionKindEnum.Blt_Un, xInstructionIndex); xILOpCode = xBranch; xInitSecondStage.Add(delegate { xBranch.Target = xResult[aILOffsetToInstructionIndex[xTarget]]; }); break; case OpCodeEnum.Bne_Un_S: xBranch = new Cil.InstructionBranch(EcmaCil.IL.InstructionKindEnum.Bne_Un, xInstructionIndex); xILOpCode = xBranch; xInitSecondStage.Add(delegate { xBranch.Target = xResult[aILOffsetToInstructionIndex[xTarget]]; }); break; case OpCodeEnum.Br_S: xBranch = new Cil.InstructionBranch(EcmaCil.IL.InstructionKindEnum.Br, xInstructionIndex); xILOpCode = xBranch; xInitSecondStage.Add(delegate { xBranch.Target = xResult[aILOffsetToInstructionIndex[xTarget]]; }); break; case OpCodeEnum.Brfalse_S: xBranch = new Cil.InstructionBranch(EcmaCil.IL.InstructionKindEnum.Brfalse, xInstructionIndex); xILOpCode = xBranch; xInitSecondStage.Add(delegate { xBranch.Target = xResult[aILOffsetToInstructionIndex[xTarget]]; }); break; case OpCodeEnum.Brtrue_S: xBranch = new Cil.InstructionBranch(EcmaCil.IL.InstructionKindEnum.Brtrue, xInstructionIndex); xILOpCode = xBranch; xInitSecondStage.Add(delegate { xBranch.Target = xResult[aILOffsetToInstructionIndex[xTarget]]; }); break; case OpCodeEnum.Leave_S: xBranch = new Cil.InstructionBranch(EcmaCil.IL.InstructionKindEnum.Leave, xInstructionIndex); xILOpCode = xBranch; xInitSecondStage.Add(delegate { xBranch.Target = xResult[aILOffsetToInstructionIndex[xTarget]]; }); break; default: xBranch = new Cil.InstructionBranch((EcmaCil.IL.InstructionKindEnum)xOpCodeVal, xInstructionIndex); xILOpCode = xBranch; xInitSecondStage.Add(delegate { xBranch.Target = xResult[aILOffsetToInstructionIndex[xTarget]]; }); break; } xPos = xPos + 1; break; #endregion } case OperandType.InlineBrTarget: { int xTarget = xPos + 4 + (Int32)ReadInt32(xIL, xPos); CheckBranch(xTarget, xIL.Length); xILOpCode = xBranch = new Cil.InstructionBranch((EcmaCil.IL.InstructionKindEnum)xOpCodeVal, xInstructionIndex); xInitSecondStage.Add(delegate { xBranch.Target = xResult[aILOffsetToInstructionIndex[xTarget]]; }); xPos = xPos + 4; break; } case OperandType.ShortInlineI: switch (xOpCodeVal) { case OpCodeEnum.Ldc_I4_S: xILOpCode = new Cil.InstructionInt32(EcmaCil.IL.InstructionKindEnum.Ldc_I4, xInstructionIndex, xIL[xPos]); break; default: xILOpCode = new Cil.InstructionInt32((EcmaCil.IL.InstructionKindEnum)xOpCodeVal, xInstructionIndex, xIL[xPos]); break; } xPos = xPos + 1; break; case OperandType.InlineI: xILOpCode = new Cil.InstructionInt32((Cil.InstructionKindEnum)xOpCodeVal, xInstructionIndex, ReadInt32(xIL, xPos)); xPos = xPos + 4; break; case OperandType.InlineI8: xILOpCode = new Cil.InstructionInt64((Cil.InstructionKindEnum)xOpCodeVal, xInstructionIndex, ReadInt64(xIL, xPos)); xPos = xPos + 8; break; case OperandType.ShortInlineR: // this is not correct: //xILOpCode = new Cil.InstructionSingle( //xILOpCode = new ILOpCodes.OpSingle(xOpCodeVal, xOpPos, xPos + 4, BitConverter.ToSingle(xIL, xPos), xCurrentHandler); //xPos = xPos + 4; //break; throw new NotImplementedException(); case OperandType.InlineR: // this is not correct //xILOpCode = new ILOpCodes.OpDouble(xOpCodeVal, xOpPos, xPos + 8, BitConverter.ToDouble(xIL, xPos), xCurrentHandler); //xPos = xPos + 8; //break; throw new NotImplementedException(); // The operand is a 32-bit metadata token. case OperandType.InlineField: throw new NotImplementedException(); //{ // var xValue = aMethod.Module.ResolveField((int)ReadInt32(xIL, xPos), xTypeGenArgs, xMethodGenArgs); // xILOpCode = new ILOpCodes.OpField(xOpCodeVal, xOpPos, xPos + 4, xValue, xCurrentHandler); // xPos = xPos + 4; // break; //} // The operand is a 32-bit metadata token. case OperandType.InlineMethod: var xTargetMethod = EnqueueMethod(aMethod.DeclaringType.Module.ResolveMethod(ReadInt32(xIL, xPos)), aMethod, "Method Call"); xILOpCode = new Cil.InstructionMethod((Cil.InstructionKindEnum)xOpCodeVal, xInstructionIndex, xTargetMethod); xPos = xPos + 4; break; //{ // var xValue = aMethod.Module.ResolveMethod((int)ReadInt32(xIL, xPos), xTypeGenArgs, xMethodGenArgs); // xILOpCode = new ILOpCodes.OpMethod(xOpCodeVal, xOpPos, xPos + 4, xValue, xCurrentHandler); // xPos = xPos + 4; // break; //} // 32-bit metadata signature token. case OperandType.InlineSig: throw new NotImplementedException(); case OperandType.InlineString: xILOpCode = new Cil.InstructionString(Cil.InstructionKindEnum.Ldstr, xInstructionIndex, aMethod.Module.ResolveString(ReadInt32(xIL, xPos))); xPos = xPos + 4; break; case OperandType.InlineSwitch: throw new NotImplementedException(); //{ // int xCount = (int)ReadInt32(xIL, xPos); // xPos = xPos + 4; // int xNextOpPos = xPos + xCount * 4; // int[] xBranchLocations = new int[xCount]; // for (int i = 0; i < xCount; i++) // { // xBranchLocations[i] = xNextOpPos + (int)ReadInt32(xIL, xPos + i * 4); // CheckBranch(xBranchLocations[i], xIL.Length); // } // xILOpCode = new ILOpCodes.OpSwitch(xOpCodeVal, xOpPos, xPos, xBranchLocations, xCurrentHandler); // xPos = xNextOpPos; // break; //} // The operand is a FieldRef, MethodRef, or TypeRef token. case OperandType.InlineTok: throw new NotImplementedException(); //xILOpCode = new ILOpCodes.OpToken(xOpCodeVal, xOpPos, xPos + 4, ReadInt32(xIL, xPos), aMethod.Module, xTypeGenArgs, xMethodGenArgs, xCurrentHandler); // xPos = xPos + 4; // break; // 32-bit metadata token. case OperandType.InlineType: throw new NotImplementedException(); //{ // var xValue = aMethod.Module.ResolveType((int)ReadInt32(xIL, xPos), xTypeGenArgs, xMethodGenArgs); // xILOpCode = new ILOpCodes.OpType(xOpCodeVal, xOpPos, xPos + 4, xValue, xCurrentHandler); // xPos = xPos + 4; // break; //} case OperandType.ShortInlineVar: switch (xOpCodeVal) { case OpCodeEnum.Ldloc_S: xILOpCode = new Cil.InstructionLocal(Cil.InstructionKindEnum.Ldloc, xInstructionIndex, aMethodMeta.Body.LocalVariables[xIL[xPos]]); break; case OpCodeEnum.Ldloca_S: xILOpCode = new Cil.InstructionLocal(Cil.InstructionKindEnum.Ldloca, xInstructionIndex, aMethodMeta.Body.LocalVariables[xIL[xPos]]); break; case OpCodeEnum.Ldarg_S: xILOpCode = new Cil.InstructionArgument(Cil.InstructionKindEnum.Ldarg, xInstructionIndex, aMethodMeta.Parameters[xIL[xPos]]); break; case OpCodeEnum.Ldarga_S: xILOpCode = new Cil.InstructionArgument(Cil.InstructionKindEnum.Ldarga, xInstructionIndex, aMethodMeta.Parameters[xIL[xPos]]); break; case OpCodeEnum.Starg_S: xILOpCode = new Cil.InstructionArgument(Cil.InstructionKindEnum.Starg, xInstructionIndex, aMethodMeta.Parameters[xIL[xPos]]); break; case OpCodeEnum.Stloc_S: xILOpCode = new Cil.InstructionLocal(Cil.InstructionKindEnum.Stloc, xInstructionIndex, aMethodMeta.Body.LocalVariables[xIL[xPos]]); break; default: throw new NotImplementedException(); //xILOpCode = new ILOpCodes.OpVar(xOpCodeVal, xOpPos, xPos + 1, xIL[xPos], xCurrentHandler); //break; } xPos = xPos + 1; break; case OperandType.InlineVar: //xILOpCode = new ILOpCodes.OpVar(xOpCodeVal, xOpPos, xPos + 2, ReadUInt16(xIL, xPos), xCurrentHandler); //xPos = xPos + 2; throw new NotImplementedException(); break; default: throw new Exception("Unknown OperandType"); } #endregion switch(xOpCode.OperandType) xResult.Add(xILOpCode); xInstructionIndex++; } foreach (var xAction in xInitSecondStage) { xAction(); } return xResult; }
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 void ScanArrayType(QueuedArrayType aType, EcmaCil.ArrayTypeMeta arrayTypeMeta) { arrayTypeMeta.Dimensions = aType.ArrayType.Dimensions.Count; // todo: fix? foreach (ArrayDimension xDimension in aType.ArrayType.Dimensions) { if (xDimension.LowerBound != 0 || xDimension.UpperBound != 0) { throw new Exception("Arrays with limited dimensions not supported"); } } #if DEBUG var xSB = new StringBuilder(); xSB.Append(arrayTypeMeta.ElementType.ToString()); xSB.Append("["); xSB.Append(new String(',', arrayTypeMeta.Dimensions - 1)); xSB.Append("]"); arrayTypeMeta.Data[EcmaCil.DataIds.DebugMetaId] = xSB.ToString(); #endif }
private void ScanPointerType(QueuedPointerType xType, EcmaCil.PointerTypeMeta pointerTypeMeta) { #if DEBUG pointerTypeMeta.Data[EcmaCil.DataIds.DebugMetaId] = "&" + pointerTypeMeta.ElementType.ToString(); #endif }