public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { StackItem itemToConvert = conversionState.CurrentStackFrame.Stack.Pop(); int numBytesToConvertTo = 0; switch ((OpCodes)theOp.opCode.Value) { case OpCodes.Conv_U: numBytesToConvertTo = 4; break; case OpCodes.Conv_U1: numBytesToConvertTo = 1; break; case OpCodes.Conv_U2: numBytesToConvertTo = 2; break; case OpCodes.Conv_U4: numBytesToConvertTo = 4; break; case OpCodes.Conv_U8: numBytesToConvertTo = 8; break; } bool pushEDX = numBytesToConvertTo == 8; conversionState.CurrentStackFrame.Stack.Push(new StackItem() { sizeOnStackInBytes = (pushEDX ? 8 : 4), isFloat = false, isGCManaged = false }); }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { StackItem addressItem = conversionState.CurrentStackFrame.Stack.Pop(); int bytesToLoad = 0; switch ((OpCodes)theOp.opCode.Value) { case OpCodes.Ldind_U1: case OpCodes.Ldind_I1: bytesToLoad = 1; break; case OpCodes.Ldind_U2: case OpCodes.Ldind_I2: bytesToLoad = 2; break; case OpCodes.Ldind_U4: case OpCodes.Ldind_I4: case OpCodes.Ldind_I: bytesToLoad = 4; break; case OpCodes.Ldind_I8: bytesToLoad = 8; break; case OpCodes.Ldind_Ref: bytesToLoad = Options.AddressSizeInBytes; break; } conversionState.CurrentStackFrame.Stack.Push(new StackItem() { sizeOnStackInBytes = bytesToLoad == 8 ? 8 : 4, isFloat = false, isGCManaged = false }); }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { MethodBase constructorMethod = theOp.MethodToCall; Type objectType = constructorMethod.DeclaringType; if (typeof(Delegate).IsAssignableFrom(objectType)) { StackItem funcPtrItem = conversionState.CurrentStackFrame.Stack.Pop(); ; conversionState.CurrentStackFrame.Stack.Pop(); conversionState.CurrentStackFrame.Stack.Push(funcPtrItem); return; } Types.MethodInfo constructorMethodInfo = conversionState.TheILLibrary.GetMethodInfo(constructorMethod); ParameterInfo[] allParams = constructorMethod.GetParameters(); foreach (ParameterInfo aParam in allParams) { conversionState.CurrentStackFrame.Stack.Pop(); } conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isNewGCObject = true, isGCManaged = true, isValue = false }); }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); FieldInfo theField = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveField(metadataToken); bool valueisFloat = Utilities.IsFloat(theField.FieldType); Types.TypeInfo fieldTypeInfo = conversionState.TheILLibrary.GetTypeInfo(theField.FieldType); int stackSize = fieldTypeInfo.SizeOnStackInBytes; StackItem objPointer = conversionState.CurrentStackFrame.Stack.Pop(); if ((OpCodes)theOp.opCode.Value == OpCodes.Ldflda) { conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false }); } else { conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = valueisFloat, sizeOnStackInBytes = stackSize, isGCManaged = fieldTypeInfo.IsGCManaged }); } }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { StackItem itemB = conversionState.CurrentStackFrame.Stack.Pop(); StackItem itemA = conversionState.CurrentStackFrame.Stack.Pop(); if (itemA.sizeOnStackInBytes == 4 && itemB.sizeOnStackInBytes == 4) { conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false, isValue = true }); } else if (itemA.sizeOnStackInBytes == 8 && itemB.sizeOnStackInBytes == 8) { conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false, isValue = true }); } else { throw new NotSupportedException("Unsupported number of bytes for compare equal to!"); } }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { StackItem itemB = conversionState.CurrentStackFrame.Stack.Pop(); StackItem itemA = conversionState.CurrentStackFrame.Stack.Pop(); if (itemA.sizeOnStackInBytes == 4 && itemB.sizeOnStackInBytes == 4) { conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false }); } else if (itemA.sizeOnStackInBytes == 8 && itemB.sizeOnStackInBytes == 8) { conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 8, isGCManaged = false }); } }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); FieldInfo theField = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveField(metadataToken); switch ((OpCodes)theOp.opCode.Value) { case OpCodes.Ldsfld: { Types.TypeInfo theTypeInfo = conversionState.TheILLibrary.GetTypeInfo(theField.FieldType); int size = theTypeInfo.SizeOnStackInBytes; bool isFloat = Utilities.IsFloat(theField.FieldType); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = isFloat, sizeOnStackInBytes = (size == 8 ? 8 : 4), isGCManaged = theTypeInfo.IsGCManaged, isValue = theTypeInfo.IsValueType }); } break; case OpCodes.Ldsflda: conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false, isValue = false }); break; } }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { //Pop in reverse order to push StackItem itemB = conversionState.CurrentStackFrame.Stack.Pop(); StackItem itemA = conversionState.CurrentStackFrame.Stack.Pop(); if (itemA.sizeOnStackInBytes == 4 && itemB.sizeOnStackInBytes == 4) { conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false, isValue = itemA.isValue && itemB.isValue }); } else if (itemA.sizeOnStackInBytes == 8 && itemB.sizeOnStackInBytes == 8) { conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, isNewGCObject = false, sizeOnStackInBytes = 8, isGCManaged = false, isValue = itemA.isValue && itemB.isValue }); } }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { Int16 index = 0; switch ((OpCodes)theOp.opCode.Value) { case OpCodes.Ldarg: index = Utilities.ReadInt16(theOp.ValueBytes, 0); break; case OpCodes.Ldarg_0: index = 0; break; case OpCodes.Ldarg_1: index = 1; break; case OpCodes.Ldarg_2: index = 2; break; case OpCodes.Ldarg_3: index = 3; break; case OpCodes.Ldarg_S: index = (Int16)theOp.ValueBytes[0]; break; case OpCodes.Ldarga: index = Utilities.ReadInt16(theOp.ValueBytes, 0); break; case OpCodes.Ldarga_S: index = (Int16)theOp.ValueBytes[0]; break; } List<Type> allParams = conversionState.Input.TheMethodInfo.UnderlyingInfo.GetParameters().Select(x => x.ParameterType).ToList(); if (!conversionState.Input.TheMethodInfo.IsStatic) { allParams.Insert(0, conversionState.Input.TheMethodInfo.UnderlyingInfo.DeclaringType); } if ((OpCodes)theOp.opCode.Value == OpCodes.Ldarga || (OpCodes)theOp.opCode.Value == OpCodes.Ldarga_S) { conversionState.CurrentStackFrame.Stack.Push(new StackItem() { sizeOnStackInBytes = 4, isFloat = false, isGCManaged = false }); } else { Types.TypeInfo paramTypeInfo = conversionState.TheILLibrary.GetTypeInfo(allParams[index]); int bytesForArg = paramTypeInfo.SizeOnStackInBytes; conversionState.CurrentStackFrame.Stack.Push(new StackItem() { sizeOnStackInBytes = bytesForArg, isFloat = false, isGCManaged = paramTypeInfo.IsGCManaged }); } }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false }); }
public override void Preprocess(ILPreprocessState preprocessState, ILOp theOp) { for (int i = 0; i < theOp.ValueBytes.Length / 4; i++) { int branchOffset = theOp.NextOffset + Utilities.ReadInt32(theOp.ValueBytes, i * 4); ILOp opToGoTo = preprocessState.Input.At(branchOffset); opToGoTo.LabelRequired = true; } }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { MethodBase methodToCall = theOp.MethodToCall; Types.MethodInfo methodToCallInfo = conversionState.TheILLibrary.GetMethodInfo(methodToCall); if (methodToCall is MethodInfo) { Type retType = ((MethodInfo)methodToCall).ReturnType; Types.TypeInfo retTypeInfo = conversionState.TheILLibrary.GetTypeInfo(retType); StackItem returnItem = new StackItem() { isFloat = Utilities.IsFloat(retType), sizeOnStackInBytes = retTypeInfo.SizeOnStackInBytes, isGCManaged = retTypeInfo.IsGCManaged, isValue = retTypeInfo.IsValueType }; int bytesToAdd = 0; List<Type> allParams = ((MethodInfo)methodToCall).GetParameters().Select(x => x.ParameterType).ToList(); if (!methodToCall.IsStatic) { allParams.Insert(0, methodToCall.DeclaringType); } foreach (Type aParam in allParams) { conversionState.CurrentStackFrame.Stack.Pop(); bytesToAdd += conversionState.TheILLibrary.GetTypeInfo(aParam).SizeOnStackInBytes; } if (bytesToAdd > 0) { if (returnItem.sizeOnStackInBytes != 0) { conversionState.CurrentStackFrame.Stack.Push(returnItem); } } else if (returnItem.sizeOnStackInBytes != 0) { conversionState.CurrentStackFrame.Stack.Push(returnItem); } } else if (methodToCall is ConstructorInfo) { ConstructorInfo aConstructor = (ConstructorInfo)methodToCall; if (aConstructor.IsStatic) { //Static constructors do not have parameters or return values } else { ParameterInfo[] allParams = methodToCall.GetParameters(); foreach (ParameterInfo aParam in allParams) { conversionState.CurrentStackFrame.Stack.Pop(); } } } }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { Int16 index = 0; switch ((OpCodes)theOp.opCode.Value) { case OpCodes.Ldarg: index = Utilities.ReadInt16(theOp.ValueBytes, 0); break; case OpCodes.Ldarg_0: index = 0; break; case OpCodes.Ldarg_1: index = 1; break; case OpCodes.Ldarg_2: index = 2; break; case OpCodes.Ldarg_3: index = 3; break; case OpCodes.Ldarg_S: index = (Int16)theOp.ValueBytes[0]; break; case OpCodes.Ldarga: index = Utilities.ReadInt16(theOp.ValueBytes, 0); break; case OpCodes.Ldarga_S: index = (Int16)theOp.ValueBytes[0]; break; } if ((OpCodes)theOp.opCode.Value == OpCodes.Ldarga || (OpCodes)theOp.opCode.Value == OpCodes.Ldarga_S) { conversionState.CurrentStackFrame.Stack.Push(new StackItem() { sizeOnStackInBytes = 4, isFloat = false, isGCManaged = false, isValue = false }); } else { Types.VariableInfo argInfo = conversionState.Input.TheMethodInfo.ArgumentInfos[index]; Types.TypeInfo paramTypeInfo = argInfo.TheTypeInfo; int bytesForArg = paramTypeInfo.SizeOnStackInBytes; conversionState.CurrentStackFrame.Stack.Push(new StackItem() { sizeOnStackInBytes = bytesForArg, isFloat = false, isGCManaged = paramTypeInfo.IsGCManaged, isValue = paramTypeInfo.IsValueType }); } }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { Type retType = (conversionState.Input.TheMethodInfo.IsConstructor ? typeof(void) : ((MethodInfo)conversionState.Input.TheMethodInfo.UnderlyingInfo).ReturnType); Types.TypeInfo retTypeInfo = conversionState.TheILLibrary.GetTypeInfo(retType); if (retTypeInfo.SizeOnStackInBytes != 0) { conversionState.CurrentStackFrame.Stack.Pop(); } }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { bool loadAddr = (ILOp.OpCodes)theOp.opCode.Value == OpCodes.Ldloca || (ILOp.OpCodes)theOp.opCode.Value == OpCodes.Ldloca_S; UInt16 localIndex = 0; switch ((ILOp.OpCodes)theOp.opCode.Value) { case OpCodes.Ldloc: case OpCodes.Ldloca: localIndex = (UInt16)Utilities.ReadInt16(theOp.ValueBytes, 0); break; case OpCodes.Ldloc_0: localIndex = 0; break; case OpCodes.Ldloc_1: localIndex = 1; break; case OpCodes.Ldloc_2: localIndex = 2; break; case OpCodes.Ldloc_3: localIndex = 3; break; case OpCodes.Ldloc_S: case OpCodes.Ldloca_S: localIndex = (UInt16)theOp.ValueBytes[0]; break; } Types.VariableInfo theLoc = conversionState.Input.TheMethodInfo.LocalInfos.ElementAt(localIndex); if (loadAddr) { conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false, isValue = false }); } else { int pushedLocalSizeVal = theLoc.TheTypeInfo.SizeOnStackInBytes; conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = Utilities.IsFloat(theLoc.UnderlyingType), sizeOnStackInBytes = pushedLocalSizeVal, isGCManaged = theLoc.TheTypeInfo.IsGCManaged, isValue = theLoc.TheTypeInfo.IsValueType }); } }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); Type theType = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveType(metadataToken); Types.TypeInfo theTypeInfo = conversionState.TheILLibrary.GetTypeInfo(theType); int size = theTypeInfo.SizeOnStackInBytes; conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = size, isGCManaged = false }); }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { try { conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false }); } catch { throw new NotSupportedException("The metadata token specifies a fieldref or methodref which isn't supported yet!"); } }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { StackItem itemA = conversionState.CurrentStackFrame.Stack.Pop(); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = itemA.isFloat, sizeOnStackInBytes = itemA.sizeOnStackInBytes, isGCManaged = itemA.isGCManaged }); conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = itemA.isFloat, sizeOnStackInBytes = itemA.sizeOnStackInBytes, isGCManaged = itemA.isGCManaged }); }
public override void Preprocess(ILPreprocessState preprocessState, ILOp theOp) { Types.MethodInfo methodInfo = preprocessState.TheILLibrary.GetMethodInfo(theOp.MethodToCall); if (theOp.LoadAtILOpAfterOp != null) { ILBlock anILBlock = preprocessState.TheILLibrary.GetILBlock(methodInfo); int index = anILBlock.ILOps.IndexOf(theOp.LoadAtILOpAfterOp); index++; anILBlock.ILOps[index].LabelRequired = true; } else if (theOp.LoadAtILOffset != int.MaxValue) { int offset = theOp.LoadAtILOffset; ILOp theLoadedOp = preprocessState.TheILLibrary.GetILBlock(methodInfo).At(offset); theLoadedOp.LabelRequired = true; } }
private static void rotateStackItems(ILPreprocessState state, int items, int distance) { if (distance >= items) { throw new IndexOutOfRangeException("IlPreprocessor.rotateStackItems: distance >= items invalid!"); } List<StackItem> poppedItems = new List<StackItem>(); for (int i = 0; i < items; i++) { poppedItems.Add(state.CurrentStackFrame.Stack.Pop()); } for (int i = distance; i > -1; i--) { state.CurrentStackFrame.Stack.Push(poppedItems[i]); } for (int i = items - 1; i > distance; i--) { state.CurrentStackFrame.Stack.Push(poppedItems[i]); } }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { //Weirdly this is not a true/false returning op - it actually returns a null or object ref. }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { conversionState.CurrentStackFrame.Stack.Pop(); }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { rotateStackItems(conversionState, theOp.StackSwitch_Items, 1); }
/// <summary> /// Preprocesses the IL ops of the specified method/IL block. /// </summary> /// <param name="TheLibrary">The library being compiled.</param> /// <param name="theMethodInfo">The method to preprocess.</param> /// <param name="theILBlock">The IL block for the method to preprocess.</param> private static void PreprocessILOps(ILLibrary TheLibrary, Types.MethodInfo theMethodInfo, ILBlock theILBlock) { StaticConstructorDependency staticConstructorDependencyRoot = null; if (theMethodInfo.UnderlyingInfo is System.Reflection.ConstructorInfo && theMethodInfo.IsStatic) { System.Reflection.ConstructorInfo aConstructor = (System.Reflection.ConstructorInfo)theMethodInfo.UnderlyingInfo; staticConstructorDependencyRoot = ILLibrary.TheStaticConstructorDependencyTree[aConstructor]; if (staticConstructorDependencyRoot == null) { staticConstructorDependencyRoot = new StaticConstructorDependency() { TheConstructor = aConstructor }; ILLibrary.TheStaticConstructorDependencyTree.Children.Add(staticConstructorDependencyRoot); } } ILPreprocessState preprosState = new ILPreprocessState() { TheILLibrary = TheLibrary, Input = theILBlock }; for (int i = 0; i < theILBlock.ILOps.Count; i++) { ILOp theOp = theILBlock.ILOps[i]; // Remove cast class ops if ((ILOp.OpCodes)theOp.opCode.Value == ILOp.OpCodes.Castclass) { theILBlock.ILOps.RemoveAt(i); i--; continue; } else if ((ILOp.OpCodes)theOp.opCode.Value == ILOp.OpCodes.Call) { if (theOp.MethodToCall != null && theOp.MethodToCall.DeclaringType.AssemblyQualifiedName.Contains("mscorlib")) { //We do not want to process ops which attempt to call methods in mscorlib! theILBlock.ILOps.RemoveAt(i); i--; //We do not allow calls to methods declared in MSCorLib. //Some of these calls can just be ignored (e.g. GetTypeFromHandle is // called by typeof operator). //Ones which can't be ignored, will result in an error...by virtue of // the fact that they were ignored when they were required. //But just to make sure we save ourselves a headache later when // runtime debugging, output a message saying we ignored the call. // TODO - IL level comments // result.ASM.AppendLine("; Call to method defined in MSCorLib ignored:"); // DEBUG INFO // result.ASM.AppendLine("; " + anILOpInfo.MethodToCall.DeclaringType.FullName + "." + anILOpInfo.MethodToCall.Name); // DEBUG INFO //If the method is a call to a constructor in MsCorLib: if (theOp.MethodToCall is System.Reflection.ConstructorInfo) { //Then we can presume it was a call to a base-class constructor (e.g. the Object constructor) // and so we just need to remove any args that were loaded onto the stack. // TODO: result.ASM.AppendLine("; Method to call was constructor so removing params"); // DEBUG INFO //Remove args from stack //If the constructor was non-static, then the first arg is the instance reference. if (!theOp.MethodToCall.IsStatic) { i++; theILBlock.ILOps.Insert(i, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Pop }); } foreach (System.Reflection.ParameterInfo anInfo in theOp.MethodToCall.GetParameters()) { i++; theILBlock.ILOps.Insert(i, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Pop }); } } } } try { ILOp ConverterOp = TargetArchitecture.TargetILOps[(ILOp.OpCodes)theOp.opCode.Value]; ConverterOp.Preprocess(preprosState, theOp); if (staticConstructorDependencyRoot != null) { //Create our static constructor dependency tree //Each of these ops could try to access a static method or field switch ((ILOp.OpCodes)theOp.opCode.Value) { case ILOp.OpCodes.Call: //Check if the method to call is static and not a constructor itself //If so, we must add the declaring type's static constructors to the tree if(theOp.ValueBytes != null && theOp.ValueBytes.Length > 0) { int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); System.Reflection.MethodBase methodBaseInf = theMethodInfo.UnderlyingInfo.Module.ResolveMethod(metadataToken); if (!(methodBaseInf.IsConstructor || methodBaseInf is System.Reflection.ConstructorInfo)) { System.Reflection.MethodInfo methodInf = (System.Reflection.MethodInfo)methodBaseInf; System.Reflection.ConstructorInfo[] staticConstructors = methodInf.DeclaringType.GetConstructors(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public) .Concat(methodInf.DeclaringType.GetConstructors(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic)) .ToArray(); if (staticConstructors.Length > 0) { System.Reflection.ConstructorInfo TheConstructor = staticConstructors[0]; if (staticConstructorDependencyRoot[TheConstructor] == null) { staticConstructorDependencyRoot.Children.Add(new StaticConstructorDependency() { TheConstructor = TheConstructor }); } } } } break; case ILOp.OpCodes.Ldsfld: case ILOp.OpCodes.Ldsflda: case ILOp.OpCodes.Stsfld: { int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); System.Reflection.FieldInfo fieldInf = theMethodInfo.UnderlyingInfo.Module.ResolveField(metadataToken); System.Reflection.ConstructorInfo[] staticConstructors = fieldInf.DeclaringType.GetConstructors(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public) .Concat(fieldInf.DeclaringType.GetConstructors(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic)) .ToArray(); if (staticConstructors.Length > 0) { System.Reflection.ConstructorInfo TheConstructor = staticConstructors[0]; if (staticConstructorDependencyRoot[TheConstructor] == null) { staticConstructorDependencyRoot.Children.Add(new StaticConstructorDependency() { TheConstructor = TheConstructor }); } } } break; } } } catch (KeyNotFoundException) { //Ignore - will be caught by Il scanner } catch (Exception ex) { Logger.LogError("ILPRE", theILBlock.TheMethodInfo.ToString(), 0, "Il Preprocessor error: PreprocessILOps: " + ex.Message); } } }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { //No effect }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { bool isFloat = false; int numBytes = 0; switch ((OpCodes)theOp.opCode.Value) { case OpCodes.Ldc_I4: numBytes = 4; break; case OpCodes.Ldc_I4_0: numBytes = 4; break; case OpCodes.Ldc_I4_1: numBytes = 4; break; case OpCodes.Ldc_I4_2: numBytes = 4; break; case OpCodes.Ldc_I4_3: numBytes = 4; break; case OpCodes.Ldc_I4_4: numBytes = 4; break; case OpCodes.Ldc_I4_5: numBytes = 4; break; case OpCodes.Ldc_I4_6: numBytes = 4; break; case OpCodes.Ldc_I4_7: numBytes = 4; break; case OpCodes.Ldc_I4_8: numBytes = 4; break; case OpCodes.Ldc_I4_M1: numBytes = 4; break; case OpCodes.Ldc_I4_S: numBytes = 4; break; case OpCodes.Ldc_I8: numBytes = 8; break; case OpCodes.Ldc_R4: numBytes = 4; isFloat = true; break; case OpCodes.Ldc_R8: numBytes = 8; isFloat = true; break; } conversionState.CurrentStackFrame.Stack.Push(new StackItem() { sizeOnStackInBytes = numBytes, isFloat = isFloat, isGCManaged = false, isValue = true }); }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { //Pop in reverse order to push StackItem itemB = conversionState.CurrentStackFrame.Stack.Pop(); StackItem itemA = conversionState.CurrentStackFrame.Stack.Pop(); if (itemA.sizeOnStackInBytes == 4 && itemB.sizeOnStackInBytes == 4) { conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 4, isGCManaged = false }); } else if ((itemA.sizeOnStackInBytes == 8 && itemB.sizeOnStackInBytes == 4)) { if ((OpCodes)theOp.opCode.Value == OpCodes.Shr_Un) { conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 8, isGCManaged = false }); } else { conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 8, isGCManaged = false }); } } else if (itemA.sizeOnStackInBytes == 8 && itemB.sizeOnStackInBytes == 8) { if ((OpCodes)theOp.opCode.Value == OpCodes.Shr_Un) { conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 8, isGCManaged = false }); } else { conversionState.CurrentStackFrame.Stack.Push(new StackItem() { isFloat = false, sizeOnStackInBytes = 8, isGCManaged = false }); } } }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { Type elementType = null; bool pushValue = true; int sizeToPush = 4; bool isFloat = false; switch ((OpCodes)theOp.opCode.Value) { case OpCodes.Ldelem: { int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); elementType = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveType(metadataToken); } break; case OpCodes.Ldelema: { int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); elementType = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveType(metadataToken); pushValue = false; } break; case OpCodes.Ldelem_R4: case OpCodes.Ldelem_R8: throw new NotSupportedException("Ldelem op variant not supported yet!"); case OpCodes.Ldelem_I1: sizeToPush = 1; elementType = typeof(sbyte); break; case OpCodes.Ldelem_I2: sizeToPush = 2; elementType = typeof(Int16); break; case OpCodes.Ldelem_U1: sizeToPush = 1; elementType = typeof(byte); break; case OpCodes.Ldelem_U2: sizeToPush = 2; elementType = typeof(UInt16); break; case OpCodes.Ldelem_Ref: elementType = null; break; case OpCodes.Ldelem_U4: elementType = typeof(UInt32); break; case OpCodes.Ldelem_I4: elementType = typeof(Int32); break; case OpCodes.Ldelem_I8: sizeToPush = 8; elementType = typeof(Int64); break; } Types.TypeInfo elemTypeInfo = elementType == null ? null : conversionState.TheILLibrary.GetTypeInfo(elementType); // 5.2. Pop index and array ref from our stack conversionState.CurrentStackFrame.Stack.Pop(); conversionState.CurrentStackFrame.Stack.Pop(); // 5.3. Push element onto our stack conversionState.CurrentStackFrame.Stack.Push(new StackItem() { sizeOnStackInBytes = sizeToPush > 4 ? 8 : 4, isFloat = isFloat, isNewGCObject = false, isGCManaged = pushValue ? (elementType == null || elemTypeInfo.IsGCManaged) : false, isValue = pushValue ? (elementType != null && elemTypeInfo.IsValueType) : false }); }
/// <summary> /// Performs only the op's stack operations on the specified conversion state. /// </summary> /// <param name="conversionState">The conversion state to perform stack operations on.</param> /// <param name="theOp">The op being processed.</param> public virtual void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { }
/// <summary> /// Preprocesses the specified IL op. /// </summary> /// <param name="preprocessState">The preprocessor state to perform preprocessing on.</param> /// <param name="theOp">The op being processed.</param> public virtual void Preprocess(ILPreprocessState preprocessState, ILOp theOp) { }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { base.PerformStackOperations(conversionState, theOp); }
/// <summary> /// Injects the garbage collector related IL ops into the specified method. /// </summary> /// <param name="TheLibrary">The library being compiled.</param> /// <param name="theMethodInfo">The method to inject ops into.</param> /// <param name="theILBlock">The IL block for the method to inject ops into.</param> private static void InjectGC(ILLibrary TheLibrary, Types.MethodInfo theMethodInfo, ILBlock theILBlock) { if (theMethodInfo.ApplyGC) { // Find the index of the MethodStart op int MethodStartOpPos = theILBlock.PositionOf(theILBlock.ILOps.Where(x => x is ILOps.MethodStart).First()); // Inject ops for incrementing ref. count of args at start of method int InjectIncArgsRefCountPos = MethodStartOpPos + 1; foreach (Types.VariableInfo argInfo in theMethodInfo.ArgumentInfos) { if (argInfo.TheTypeInfo.IsGCManaged) { theILBlock.ILOps.Insert(InjectIncArgsRefCountPos, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Ldarg, ValueBytes = BitConverter.GetBytes(argInfo.Position) }); theILBlock.ILOps.Insert(InjectIncArgsRefCountPos + 1, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Call, MethodToCall = ILLibrary.SpecialMethods[typeof(Attributes.IncrementRefCountMethodAttribute)].First().UnderlyingInfo }); } } // The following two things can be done within the same loop: // Inject ops for inc./dec. ref. counts of objects when written to: // - Arguments / Locals // - Fields / Static Fields // - Elements of Arrays // Add Cleanup Block and Inject finally-block ops for it // - Also remember the op for storing return value (if any) ILPreprocessState preprocessState = new ILPreprocessState() { TheILLibrary = TheLibrary, Input = theILBlock, CurrentStackFrame = new StackFrame() }; ExceptionHandledBlock CleanupExBlock = new ExceptionHandledBlock(); for (int opIndx = 0; opIndx < theILBlock.ILOps.Count; opIndx++) { ILOp currOp = theILBlock.ILOps[opIndx]; bool IncRefCount = false; int incOpIndexBy = 0; switch ((ILOp.OpCodes)currOp.opCode.Value) { case ILOp.OpCodes.Stsfld: #region Stsfld { int metadataToken = Utilities.ReadInt32(currOp.ValueBytes, 0); System.Reflection.FieldInfo theField = theMethodInfo.UnderlyingInfo.Module.ResolveField(metadataToken); Types.TypeInfo theFieldTypeInfo = TheLibrary.GetTypeInfo(theField.FieldType); if (theFieldTypeInfo.IsGCManaged) { theILBlock.ILOps.Insert(opIndx, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Ldsfld, ValueBytes = currOp.ValueBytes }); theILBlock.ILOps.Insert(opIndx + 1, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Call, MethodToCall = ILLibrary.SpecialMethods[typeof(Attributes.DecrementRefCountMethodAttribute)].First().UnderlyingInfo }); IncRefCount = true; incOpIndexBy = 2; } } #endregion break; case ILOp.OpCodes.Stloc: case ILOp.OpCodes.Stloc_0: case ILOp.OpCodes.Stloc_1: case ILOp.OpCodes.Stloc_2: case ILOp.OpCodes.Stloc_3: case ILOp.OpCodes.Stloc_S: #region Stloc { UInt16 localIndex = 0; switch ((ILOp.OpCodes)currOp.opCode.Value) { case ILOp.OpCodes.Stloc: localIndex = (UInt16)Utilities.ReadInt16(currOp.ValueBytes, 0); break; case ILOp.OpCodes.Stloc_0: localIndex = 0; break; case ILOp.OpCodes.Stloc_1: localIndex = 1; break; case ILOp.OpCodes.Stloc_2: localIndex = 2; break; case ILOp.OpCodes.Stloc_3: localIndex = 3; break; case ILOp.OpCodes.Stloc_S: localIndex = (UInt16)currOp.ValueBytes[0]; break; } Types.TypeInfo LocalTypeInfo = theMethodInfo.LocalInfos[localIndex].TheTypeInfo; if (LocalTypeInfo.IsGCManaged) { theILBlock.ILOps.Insert(opIndx, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Ldloc, ValueBytes = BitConverter.GetBytes(localIndex) }); theILBlock.ILOps.Insert(opIndx + 1, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Call, MethodToCall = ILLibrary.SpecialMethods[typeof(Attributes.DecrementRefCountMethodAttribute)].First().UnderlyingInfo }); IncRefCount = true; incOpIndexBy = 2; } } #endregion break; case ILOp.OpCodes.Stfld: #region Stfld { int metadataToken = Utilities.ReadInt32(currOp.ValueBytes, 0); System.Reflection.FieldInfo theField = theMethodInfo.UnderlyingInfo.Module.ResolveField(metadataToken); Types.TypeInfo theFieldTypeInfo = TheLibrary.GetTypeInfo(theField.FieldType); if (theFieldTypeInfo.IsGCManaged) { // Items on stack: // - Object reference // - (New) Value to store // // We want to load the current value of the field // for which we must duplicate the object ref // But first, we must remove the (new) value to store // off the stack, while also storing it to put back // on the stack after so the store can continue // // So: // 1. Switch value to store and object ref on stack // 3. Duplicate the object ref // 4. Load the field value // 5. Call dec ref count // 6. Switch value to store and object ref back again //USE A SWITCH STACK ITEMS OP!! theILBlock.ILOps.Insert(opIndx, new ILOps.StackSwitch() { StackSwitch_Items = 2 }); theILBlock.ILOps.Insert(opIndx + 1, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Dup }); theILBlock.ILOps.Insert(opIndx + 2, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Ldfld, ValueBytes = currOp.ValueBytes }); theILBlock.ILOps.Insert(opIndx + 3, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Call, MethodToCall = ILLibrary.SpecialMethods[typeof(Attributes.DecrementRefCountMethodAttribute)].First().UnderlyingInfo }); theILBlock.ILOps.Insert(opIndx + 4, new ILOps.StackSwitch() { StackSwitch_Items = 2 }); IncRefCount = true; incOpIndexBy = 5; } } #endregion break; case ILOp.OpCodes.Stelem: case ILOp.OpCodes.Stelem_Ref: #region Stelem / Stelem_Ref { bool doDecrement = false; bool isRefOp = false; if ((ILOp.OpCodes)currOp.opCode.Value == ILOp.OpCodes.Stelem_Ref) { doDecrement = preprocessState.CurrentStackFrame.Stack.Peek().isGCManaged; isRefOp = true; } else { int metadataToken = Utilities.ReadInt32(currOp.ValueBytes, 0); Type elementType = theMethodInfo.UnderlyingInfo.Module.ResolveType(metadataToken); doDecrement = TheLibrary.GetTypeInfo(elementType).IsGCManaged; } if (doDecrement) { // Items on stack: // - Array reference // - Index // - (New) Value to store // // We want to load the current value of the element at Index in the array // for which we must duplicate the array ref and index // But first, we must remove the (new) value to store // off the stack, while also storing it to put back // on the stack after so the store can continue // // So: // 1. Switch (rotate) 1 times the top 3 values so that index is on top // 2. Duplicate the index // 3. Switch (rotate) 2 times the top 4 values so that array ref is on top // 4. Duplicate the array ref // 5. Switch (rotate) 4 times the top 5 values so that duplicate array ref and index are on top // 6. Do LdElem op to load existing element value // 7. Call GC.DecrementRefCount // 8. Switch (rotate) 1 times the top 3 values so that the stack is in its original state // (9. Continue to increment ref count as normal) // // The following is a diagram of the stack manipulation occurring here: // Key: A=Array ref, I=Index, V=Value to store, E=Loaded element // Top-most stack item appears last // // 1) Rotate x 1 2) Duplicate 3) Rot x 2 4) Dup // A,I,V ---------> V,A,I ---------> V,A,I,I ---------> I,I,V,A ---------> I,I,V,A,A // // // 5) Rot x 4 6) Ldelem 7) Call GC (Dec) // I,I,V,A,A ---------> I,V,A,A,I ---------> I,V,A,E ---------> I,V,A // // // 8) Rot x 1 9) Dup 10) Call GC (Inc) // I,V,A ---------> A,I,V ---------> A,I,V,V ---------> A,I,V #region 1. theILBlock.ILOps.Insert(opIndx, new ILOps.StackSwitch() { ValueBytes = BitConverter.GetBytes(3), StackSwitch_Items = 3 }); incOpIndexBy++; #endregion #region 2. theILBlock.ILOps.Insert(opIndx + incOpIndexBy, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Dup }); incOpIndexBy++; #endregion #region 3. theILBlock.ILOps.Insert(opIndx + incOpIndexBy, new ILOps.StackSwitch() { ValueBytes = BitConverter.GetBytes(4), StackSwitch_Items = 4 }); incOpIndexBy++; theILBlock.ILOps.Insert(opIndx + incOpIndexBy, new ILOps.StackSwitch() { ValueBytes = BitConverter.GetBytes(4), StackSwitch_Items = 4 }); incOpIndexBy++; #endregion #region 4. theILBlock.ILOps.Insert(opIndx + incOpIndexBy, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Dup }); incOpIndexBy++; #endregion #region 5. theILBlock.ILOps.Insert(opIndx + incOpIndexBy, new ILOps.StackSwitch() { ValueBytes = BitConverter.GetBytes(5), StackSwitch_Items = 5 }); incOpIndexBy++; theILBlock.ILOps.Insert(opIndx + incOpIndexBy, new ILOps.StackSwitch() { ValueBytes = BitConverter.GetBytes(5), StackSwitch_Items = 5 }); incOpIndexBy++; theILBlock.ILOps.Insert(opIndx + incOpIndexBy, new ILOps.StackSwitch() { ValueBytes = BitConverter.GetBytes(5), StackSwitch_Items = 5 }); incOpIndexBy++; theILBlock.ILOps.Insert(opIndx + incOpIndexBy, new ILOps.StackSwitch() { ValueBytes = BitConverter.GetBytes(5), StackSwitch_Items = 5 }); incOpIndexBy++; #endregion #region 6. theILBlock.ILOps.Insert(opIndx + incOpIndexBy, new ILOp() { opCode = isRefOp ? System.Reflection.Emit.OpCodes.Ldelem_Ref : System.Reflection.Emit.OpCodes.Ldelem, ValueBytes = currOp.ValueBytes }); incOpIndexBy++; #endregion #region 7. theILBlock.ILOps.Insert(opIndx + incOpIndexBy, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Call, MethodToCall = ILLibrary.SpecialMethods[typeof(Attributes.DecrementRefCountMethodAttribute)].First().UnderlyingInfo }); incOpIndexBy++; #endregion #region 8. theILBlock.ILOps.Insert(opIndx + incOpIndexBy, new ILOps.StackSwitch() { ValueBytes = BitConverter.GetBytes(3), StackSwitch_Items = 3 }); incOpIndexBy++; #endregion IncRefCount = true; } } #endregion break; case ILOp.OpCodes.Starg: case ILOp.OpCodes.Starg_S: #region Starg { UInt16 index = (ILOp.OpCodes)currOp.opCode.Value == ILOp.OpCodes.Starg_S ? (UInt16)currOp.ValueBytes[0] : (UInt16)Utilities.ReadInt16(currOp.ValueBytes, 0); if (theMethodInfo.ArgumentInfos[index].TheTypeInfo.IsGCManaged) { theILBlock.ILOps.Insert(opIndx, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Ldarg, ValueBytes = BitConverter.GetBytes(index) }); theILBlock.ILOps.Insert(opIndx + 1, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Call, MethodToCall = ILLibrary.SpecialMethods[typeof(Attributes.DecrementRefCountMethodAttribute)].First().UnderlyingInfo }); IncRefCount = true; incOpIndexBy = 2; } } #endregion break; } if (IncRefCount && !preprocessState.CurrentStackFrame.Stack.Peek().isNewGCObject) { theILBlock.ILOps.Insert(opIndx + incOpIndexBy, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Dup }); incOpIndexBy++; theILBlock.ILOps.Insert(opIndx + incOpIndexBy, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Call, MethodToCall = ILLibrary.SpecialMethods[typeof(Attributes.IncrementRefCountMethodAttribute)].First().UnderlyingInfo }); incOpIndexBy++; } // If op changed if (theILBlock.ILOps[opIndx] != currOp) { theILBlock.ILOps[opIndx].Offset = currOp.Offset; theILBlock.ILOps[opIndx].BytesSize = currOp.BytesSize; } // <= is correct. E.g. if 1 extra op added, incOpIndex=1 so <= results in currOp processed // + extra op processed bool UseNextOpAsCleanupStart = false; for (int i = 0; i <= incOpIndexBy; i++) { currOp = theILBlock.ILOps[opIndx]; if (UseNextOpAsCleanupStart) { UseNextOpAsCleanupStart = false; CleanupExBlock.Offset = currOp.Offset; } if (currOp is ILOps.MethodStart) { TargetArchitecture.MethodStartOp.PerformStackOperations(preprocessState, theILBlock.ILOps[opIndx]); UseNextOpAsCleanupStart = true; } else if (currOp is ILOps.MethodEnd) { TargetArchitecture.MethodEndOp.PerformStackOperations(preprocessState, theILBlock.ILOps[opIndx]); } else if (currOp is ILOps.StackSwitch) { TargetArchitecture.StackSwitchOp.PerformStackOperations(preprocessState, theILBlock.ILOps[opIndx]); } else { // Leave unsupported ops for the IL Scanner to deal with (or later code e.g. castclass op) if (TargetArchitecture.TargetILOps.ContainsKey((ILOp.OpCodes)currOp.opCode.Value)) { ILOp ConverterOp = TargetArchitecture.TargetILOps[(ILOp.OpCodes)currOp.opCode.Value]; ConverterOp.PerformStackOperations(preprocessState, currOp); } } if (i > 0) { opIndx++; } } } if (theMethodInfo.ArgumentInfos.Count > 0 || theMethodInfo.LocalInfos.Count > 0) { bool AddCleanupBlock = false; foreach (Types.VariableInfo anArgInfo in theMethodInfo.ArgumentInfos) { if (anArgInfo.TheTypeInfo.IsGCManaged) { AddCleanupBlock = true; break; } } if (!AddCleanupBlock) { foreach (Types.VariableInfo aLocInfo in theMethodInfo.LocalInfos) { if (aLocInfo.TheTypeInfo.IsGCManaged) { AddCleanupBlock = true; break; } } } if (AddCleanupBlock) { ILOp lastOp = theILBlock.ILOps.Last(); int lastOpOffset = lastOp.Offset; int lastOpIndex = theILBlock.ILOps.Count - 1; bool MethodHasReturnValue = false; // If there is a return value, we will need to temp store it if (theMethodInfo.UnderlyingInfo is System.Reflection.MethodInfo) { Type returnType = ((System.Reflection.MethodInfo)theMethodInfo.UnderlyingInfo).ReturnType; //Void return type = no return value if (returnType != typeof(void)) { // Add local variable for storing return value int lastLocalOffset = theMethodInfo.LocalInfos.Count > 0 ? theMethodInfo.LocalInfos.Last().Offset : 0; int lastLocalSize = theMethodInfo.LocalInfos.Count > 0 ? theMethodInfo.LocalInfos.Last().TheTypeInfo.SizeOnStackInBytes : 0; theMethodInfo.LocalInfos.Add(new Types.VariableInfo() { UnderlyingType = returnType, TheTypeInfo = TheLibrary.GetTypeInfo(returnType), Position = theMethodInfo.LocalInfos.Count, Offset = lastLocalOffset + lastLocalSize }); // Add op for storing return value, update op offsets theILBlock.ILOps.Insert(lastOpIndex, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Stloc, Offset = lastOpOffset, BytesSize = lastOp.BytesSize, ValueBytes = BitConverter.GetBytes(theMethodInfo.LocalInfos.Count - 1) }); lastOpIndex++; MethodHasReturnValue = true; } } ILOp leaveOp; // Add the Leave op of the try-block theILBlock.ILOps.Insert(lastOpIndex, leaveOp = new ILOp() { opCode = System.Reflection.Emit.OpCodes.Leave, Offset = lastOpOffset, BytesSize = lastOp.BytesSize, ValueBytes = BitConverter.GetBytes(0) }); lastOpIndex++; FinallyBlock CleanupFinallyBlock = new FinallyBlock() { Offset = lastOpOffset + lastOp.BytesSize, Length = 0 }; CleanupExBlock.Length = lastOpOffset - CleanupExBlock.Offset; CleanupExBlock.FinallyBlocks.Add(CleanupFinallyBlock); int cleanupOpsOffset = lastOpOffset + 1; // Add cleanup code for local variables (including the return value local) foreach (Types.VariableInfo aLocInfo in theMethodInfo.LocalInfos) { if (aLocInfo.TheTypeInfo.IsGCManaged) { theILBlock.ILOps.Insert(lastOpIndex, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Ldloc, Offset = cleanupOpsOffset, BytesSize = 1, ValueBytes = BitConverter.GetBytes(aLocInfo.Position) }); cleanupOpsOffset++; lastOpIndex++; theILBlock.ILOps.Insert(lastOpIndex, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Call, Offset = cleanupOpsOffset, BytesSize = 1, MethodToCall = ILLibrary.SpecialMethods[typeof(Attributes.DecrementRefCountMethodAttribute)].First().UnderlyingInfo }); cleanupOpsOffset++; lastOpIndex++; CleanupFinallyBlock.Length += 2; } } // Add cleanup code for arguments foreach (Types.VariableInfo anArgInfo in theMethodInfo.ArgumentInfos) { if (anArgInfo.TheTypeInfo.IsGCManaged) { theILBlock.ILOps.Insert(lastOpIndex, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Ldarg, Offset = cleanupOpsOffset, BytesSize = 1, ValueBytes = BitConverter.GetBytes(anArgInfo.Position) }); cleanupOpsOffset++; lastOpIndex++; theILBlock.ILOps.Insert(lastOpIndex, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Call, Offset = cleanupOpsOffset, BytesSize = 1, MethodToCall = ILLibrary.SpecialMethods[typeof(Attributes.DecrementRefCountMethodAttribute)].First().UnderlyingInfo }); cleanupOpsOffset++; lastOpIndex++; CleanupFinallyBlock.Length += 2; } } // Add end finally op theILBlock.ILOps.Insert(lastOpIndex, leaveOp.LoadAtILOpAfterOp = new ILOp() { opCode = System.Reflection.Emit.OpCodes.Endfinally, Offset = cleanupOpsOffset, BytesSize = 1 }); cleanupOpsOffset++; lastOpIndex++; CleanupFinallyBlock.Length++; // Add restore return value op if (MethodHasReturnValue) { theILBlock.ILOps.Insert(lastOpIndex, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Ldloc, Offset = cleanupOpsOffset, BytesSize = 1, ValueBytes = BitConverter.GetBytes(theMethodInfo.LocalInfos.Count - 1) }); cleanupOpsOffset++; lastOpIndex++; } // Add ex block to the method theILBlock.ExceptionHandledBlocks.Add(CleanupExBlock); // Replace any Ret ops contained within Cleanup Block with: // - Op to store return value (if any) // - Leave op bool Inside = false; for(int opIndx = 0; opIndx < theILBlock.ILOps.Count; opIndx++) { if (theILBlock.ILOps[opIndx].Offset > CleanupExBlock.Offset + CleanupExBlock.Length) { break; } else if (theILBlock.ILOps[opIndx].Offset >= CleanupExBlock.Offset) { Inside = true; } if (Inside && (ILOp.OpCodes)theILBlock.ILOps[opIndx].opCode.Value == ILOp.OpCodes.Ret) { ILOp ARetOp = theILBlock.ILOps[opIndx]; theILBlock.ILOps.RemoveAt(opIndx); if (MethodHasReturnValue) { theILBlock.ILOps.Insert(opIndx, new ILOp() { opCode = System.Reflection.Emit.OpCodes.Stloc, Offset = ARetOp.Offset, ValueBytes = BitConverter.GetBytes(theMethodInfo.LocalInfos.Count - 1) }); theILBlock.ILOps.Insert(opIndx + 1, new ILOp() { Offset = ARetOp.Offset, opCode = System.Reflection.Emit.OpCodes.Leave, ValueBytes = BitConverter.GetBytes(0), LoadAtILOpAfterOp = leaveOp.LoadAtILOpAfterOp }); } else { theILBlock.ILOps.Insert(opIndx, new ILOp() { Offset = ARetOp.Offset, opCode = System.Reflection.Emit.OpCodes.Leave, ValueBytes = BitConverter.GetBytes(0), LoadAtILOpAfterOp = leaveOp.LoadAtILOpAfterOp }); } } } } } } }