private void HandleDictionary( Collection<VariableDefinition> variables, Collection<ExceptionHandler> exceptionHandlers, Collection<Instruction> instructions, TypeReference dictRef, Action<Collection<Instruction>> load, Action<Collection<Instruction>> store) { string fullName = dictRef.FullName; var git = (dictRef as GenericInstanceType); if (null == git || !git.HasGenericArguments || 2 != git.GenericArguments.Count) throw new Exception(String.Format("Unhandled case for type {0}.", fullName)); MethodReference enumeratorMethod = this.GetTypeMethod(dictRef, "GetEnumerator"); MethodReference comparerMethod = this.GetTypeMethod(dictRef, "get_Comparer"); MethodReference addMethod = this.GetTypeMethod(dictRef, "Add"); // Do not merge this variable with enumeratorMethod (it get's modified). var methodReference = this.GetTypeMethod(dictRef, "GetEnumerator"); var getCount = this.GetTypeMethod(dictRef, "get_Count"); var genericEnumerator = methodReference.ReturnType as GenericInstanceType; if (null != genericEnumerator) { genericEnumerator.GenericArguments.Clear(); var baseRef = dictRef as GenericInstanceType; foreach (var arg in baseRef.GenericArguments) genericEnumerator.GenericArguments.Add(arg); } MethodReference getCurrent = this.GetTypeMethod(genericEnumerator, "get_Current"); MethodReference moveNext = this.GetTypeMethod(genericEnumerator, "MoveNext"); MethodReference dispose; if (!this.ModuleDefinition.TryGetMethodReference(typeof (IDisposable), "Dispose", out dispose)) throw new Exception(String.Format("Unable to get IDisposable.Dispose() for type {0}.", fullName)); var intType = this.ModuleDefinition.Import(this.ModuleDefinition.TypeSystem.Int32).Resolve(); var dictOfObjConstructor = this.GetGenericTypeConstructorMethod(dictRef, new [] { new ParameterDefinition(intType), new ParameterDefinition(comparerMethod.ReturnType) }); var typeReference = getCurrent.ReturnType.GetElementType(); var genericDict = dictRef as GenericInstanceType; var genericKVP = typeReference.MakeGenericType(genericDict.GenericArguments.ToArray()); MethodReference getKey = this.GetTypeMethod(genericKVP, "get_Key"); MethodReference getValue = this.GetTypeMethod(genericKVP, "get_Value"); MethodDefinition keyDeepCopy = null; var keyDef = genericDict.GenericArguments[0] as TypeDefinition; if (null != keyDef) keyDef.TryGetMethod(this._deepCopyMethodName, out keyDeepCopy); MethodDefinition valueDeepCopy = null; var valueDef = genericDict.GenericArguments[1] as TypeDefinition; if (null != valueDef) valueDef.TryGetMethod(this._deepCopyMethodName, out valueDeepCopy); var newDict = variables.AddV(dictRef); var enumerator = variables.AddV(genericEnumerator); var kvp = variables.AddV(genericKVP); VariableDefinition kvpValue = null; if (null != valueDef) kvpValue = variables.AddV(valueDef); var IL_006f = Instruction.Create(OpCodes.Ldloc_0); instructions.AddI(OpCodes.Ldnull); instructions.AddI(OpCodes.Stloc, newDict); instructions.AddI(OpCodes.Ldnull); instructions.AddI(OpCodes.Ldarg_0); load(instructions); instructions.AddI(OpCodes.Ceq); instructions.AddI(OpCodes.Brtrue_S, IL_006f); instructions.AddI(OpCodes.Ldarg_0); load(instructions); instructions.AddI(OpCodes.Callvirt, getCount); instructions.AddI(OpCodes.Ldarg_0); load(instructions); instructions.AddI(OpCodes.Callvirt, comparerMethod); instructions.AddI(OpCodes.Newobj, dictOfObjConstructor); instructions.AddI(OpCodes.Stloc, newDict); instructions.AddI(OpCodes.Ldarg_0); load(instructions); instructions.AddI(OpCodes.Callvirt, enumeratorMethod); instructions.AddI(OpCodes.Stloc_S, enumerator); // try var IL_004f = Instruction.Create(OpCodes.Ldloca_S, enumerator); var tryStart = Instruction.Create(OpCodes.Br_S, IL_004f); instructions.Add(tryStart); // loop start var loopStart = Instruction.Create(OpCodes.Ldloca_S, enumerator); instructions.Add(loopStart); instructions.AddI(OpCodes.Call, getCurrent); instructions.AddI(OpCodes.Stloc, kvp); if (!genericDict.GenericArguments[1].IsPrimitiveObject()) { // store the kvp value in a local variable instructions.AddI(OpCodes.Ldloca_S, kvp); instructions.AddI(OpCodes.Call, getValue); instructions.AddI(OpCodes.Stloc, kvpValue); } instructions.AddI(OpCodes.Ldloc, newDict); instructions.AddI(OpCodes.Ldloca_S, kvp); instructions.AddI(OpCodes.Call, getKey); if (!genericDict.GenericArguments[0].IsPrimitiveObject()) instructions.AddI(OpCodes.Callvirt, keyDeepCopy); if (!genericDict.GenericArguments[1].IsPrimitiveObject()) { var loadNull = Instruction.Create(OpCodes.Ldnull); instructions.AddI(OpCodes.Ldloc, kvpValue); instructions.AddI(OpCodes.Brfalse_S, loadNull); var add = Instruction.Create(OpCodes.Callvirt, addMethod); instructions.AddI(OpCodes.Ldloc, kvpValue); instructions.AddI(OpCodes.Callvirt, valueDeepCopy); instructions.AddI(OpCodes.Br_S, add); instructions.Add(loadNull); instructions.Add(add); } else { instructions.AddI(OpCodes.Ldloca_S, kvp); instructions.AddI(OpCodes.Call, getValue); instructions.AddI(OpCodes.Callvirt, addMethod); } instructions.Add(IL_004f); instructions.AddI(OpCodes.Call, moveNext); instructions.AddI(OpCodes.Brtrue_S, loopStart); // end loop instructions.AddI(OpCodes.Leave_S, IL_006f); // end try // finally var finallyStart = Instruction.Create(OpCodes.Ldloca_S, enumerator); var finallyHandler = new ExceptionHandler(ExceptionHandlerType.Finally) { TryStart = tryStart, TryEnd = finallyStart, HandlerStart = finallyStart, HandlerEnd = IL_006f }; exceptionHandlers.Add(finallyHandler); instructions.Add(finallyStart); instructions.AddI(OpCodes.Constrained, genericEnumerator); instructions.AddI(OpCodes.Callvirt, dispose); instructions.AddI(OpCodes.Endfinally); // end handler instructions.Add(IL_006f); instructions.AddI(OpCodes.Ldloc, newDict); store(instructions); }
private void HandleListOfObjects(Collection<VariableDefinition> variables, Collection<ExceptionHandler> exceptionHandlers, Collection<Instruction> instructions, TypeReference listRef, Action<Collection<Instruction>> load, Action<Collection<Instruction>> store, TypeReference listObjectsType, MethodReference getCount, MethodReference getItem, MethodReference addMethod) { var typeDefinition = listObjectsType as TypeDefinition; if (null == typeDefinition) throw new Exception( String.Format("List object type {0} is not a TypeDefinition.", listObjectsType.FullName)); MethodDefinition deepCopy; if (!typeDefinition.TryGetMethod(this._deepCopyMethodName, out deepCopy)) throw new Exception( String.Format("Sub-type {0} does not implement DeepCopy.", typeDefinition.FullName)); var intType = this.ModuleDefinition.Import(this.ModuleDefinition.TypeSystem.Int32).Resolve(); var listOfObjConstructor = this.GetGenericTypeConstructorMethod(listRef, new[] { new ParameterDefinition(intType) }); var newList = variables.AddV(listRef); var listObject = variables.AddV(listObjectsType); var count = variables.AddV(intType); var currentIndex = variables.AddV(intType); var loadNullAndRet = Instruction.Create(OpCodes.Ldloc_0); instructions.AddI(OpCodes.Ldnull); instructions.AddI(OpCodes.Stloc, newList); instructions.AddI(OpCodes.Ldnull); instructions.AddI(OpCodes.Ldarg_0); load(instructions); instructions.AddI(OpCodes.Ceq); instructions.AddI(OpCodes.Brtrue_S, loadNullAndRet); var forLoopCondition = Instruction.Create(OpCodes.Ldloc, currentIndex); instructions.AddI(OpCodes.Ldarg_0); load(instructions); instructions.AddI(OpCodes.Callvirt, getCount); instructions.AddI(OpCodes.Stloc, count); instructions.AddI(OpCodes.Ldloc, count); instructions.AddI(OpCodes.Newobj, listOfObjConstructor); instructions.AddI(OpCodes.Stloc, newList); instructions.AddI(OpCodes.Ldc_I4_0); instructions.AddI(OpCodes.Stloc, currentIndex); instructions.AddI(OpCodes.Br_S, forLoopCondition); // loop start var storeNull = Instruction.Create(OpCodes.Ldnull); var loopStart = Instruction.Create(OpCodes.Ldarg_0); instructions.Add(loopStart); load(instructions); instructions.AddI(OpCodes.Ldloc, currentIndex); instructions.AddI(OpCodes.Callvirt, getItem); instructions.AddI(OpCodes.Stloc, listObject); instructions.AddI(OpCodes.Ldloc, newList); instructions.AddI(OpCodes.Ldloc, listObject); instructions.AddI(OpCodes.Brfalse_S, storeNull); var add = Instruction.Create(OpCodes.Callvirt, addMethod); instructions.AddI(OpCodes.Ldloc, listObject); instructions.AddI(OpCodes.Callvirt, deepCopy); instructions.AddI(OpCodes.Br_S, add); instructions.Add(storeNull); instructions.Add(add); // loop increment instructions.AddI(OpCodes.Ldloc, currentIndex); instructions.AddI(OpCodes.Ldc_I4_1); instructions.AddI(OpCodes.Add); instructions.AddI(OpCodes.Stloc, currentIndex); // check if condition instructions.Add(forLoopCondition); instructions.AddI(OpCodes.Ldloc, count); instructions.AddI(OpCodes.Clt); instructions.AddI(OpCodes.Brtrue_S, loopStart); // end loop instructions.Add(loadNullAndRet); instructions.AddI(OpCodes.Ldloc, newList); store(instructions); }
private void HandleArray( Collection<VariableDefinition> variables, Collection<ExceptionHandler> exceptionHandlers, Collection<Instruction> instructions, TypeReference arrayRef, Action<Collection<Instruction>> load, Action<Collection<Instruction>> store) { ArrayType arrayType = (ArrayType) arrayRef; TypeReference elementType = arrayType.ElementType; if (elementType.IsPrimitiveObject()) { var newArray = variables.AddV(arrayRef); var currentIndex = variables.AddV(this.ModuleDefinition.TypeSystem.Int32); // TODO replace var length = variables.AddV(this.ModuleDefinition.TypeSystem.Int32); // TODO replace var loadMainObj = Instruction.Create(OpCodes.Ldloc_0); instructions.AddI(OpCodes.Ldnull); instructions.AddI(OpCodes.Stloc, newArray); instructions.AddI(OpCodes.Ldnull); instructions.AddI(OpCodes.Ldarg_0); load(instructions); instructions.AddI(OpCodes.Ceq); instructions.AddI(OpCodes.Brtrue_S, loadMainObj); var IL_0059 = Instruction.Create(OpCodes.Ldloc, currentIndex); instructions.AddI(OpCodes.Ldarg_0); load(instructions); instructions.AddI(OpCodes.Ldlen); instructions.AddI(OpCodes.Conv_I4); // TODO replace instructions.AddI(OpCodes.Stloc, length); instructions.AddI(OpCodes.Ldloc, length); instructions.AddI(OpCodes.Newarr, elementType); instructions.AddI(OpCodes.Stloc, newArray); instructions.AddI(OpCodes.Ldc_I4_0); // TODO replace instructions.AddI(OpCodes.Stloc, currentIndex); instructions.AddI(OpCodes.Br_S, IL_0059); // loop start var IL_0025 = Instruction.Create(OpCodes.Ldloc, newArray); instructions.Add(IL_0025); instructions.AddI(OpCodes.Ldloc, currentIndex); instructions.AddI(OpCodes.Ldarg_0); load(instructions); instructions.AddI(OpCodes.Ldloc, currentIndex); // Change for each primitive. Type type = Type.GetType(elementType.FullName); if (typeof (System.Int16) == type) { instructions.AddI(OpCodes.Ldelem_I2); instructions.AddI(OpCodes.Stelem_I2); } else if (typeof (System.Int32) == type) { instructions.AddI(OpCodes.Ldelem_I4); instructions.AddI(OpCodes.Stelem_I4); } else if (typeof (System.Int64) == type) { instructions.AddI(OpCodes.Ldelem_I8); instructions.AddI(OpCodes.Stelem_I8); } else if (typeof (float) == type) { instructions.AddI(OpCodes.Ldelem_R4); instructions.AddI(OpCodes.Stelem_R4); } else if (typeof (double) == type) { instructions.AddI(OpCodes.Ldelem_R8); instructions.AddI(OpCodes.Stelem_R8); } else if (typeof (System.UInt16) == type) { instructions.AddI(OpCodes.Ldelem_U2); instructions.AddI(OpCodes.Stelem_I4); } else if (typeof (System.UInt32) == type) { instructions.AddI(OpCodes.Ldelem_U4); instructions.AddI(OpCodes.Stelem_I4); } instructions.AddI(OpCodes.Ldloc, currentIndex); instructions.AddI(OpCodes.Ldc_I4_1); // TODO replace instructions.AddI(OpCodes.Add); instructions.AddI(OpCodes.Stloc, currentIndex); // Increment the index. instructions.Add(IL_0059); instructions.AddI(OpCodes.Ldloc, length); instructions.AddI(OpCodes.Clt); instructions.AddI(OpCodes.Brtrue_S, IL_0025); // end loop instructions.Add(loadMainObj); instructions.AddI(OpCodes.Ldloc, newArray); store(instructions); } else if (elementType.IsGenericParameter) { // TODO how to handle? } else { var typeDefinition = arrayRef.Resolve(); MethodDefinition deepCopy; if (!typeDefinition.TryGetMethod(this._deepCopyMethodName, out deepCopy)) throw new Exception(String.Format("Sub-type {0} does not implement DeepCopy.", typeDefinition.FullName)); var newArray = variables.AddV(arrayRef); var currentIndex = variables.AddV(this.ModuleDefinition.TypeSystem.Int32); // TODO replace var length = variables.AddV(this.ModuleDefinition.TypeSystem.Int32); // TODO replace var loadMainObj = Instruction.Create(OpCodes.Ldloc_0); instructions.AddI(OpCodes.Ldnull); instructions.AddI(OpCodes.Stloc, newArray); instructions.AddI(OpCodes.Ldnull); instructions.AddI(OpCodes.Ldarg_0); load(instructions); instructions.AddI(OpCodes.Ceq); instructions.AddI(OpCodes.Brtrue_S, loadMainObj); var IL_0059 = Instruction.Create(OpCodes.Ldloc, currentIndex); instructions.AddI(OpCodes.Ldarg_0); load(instructions); instructions.AddI(OpCodes.Ldlen); instructions.AddI(OpCodes.Conv_I4); // TODO replace instructions.AddI(OpCodes.Stloc, length); instructions.AddI(OpCodes.Ldloc, length); instructions.AddI(OpCodes.Newarr, elementType); instructions.AddI(OpCodes.Stloc, newArray); instructions.AddI(OpCodes.Ldc_I4_0); // TODO replace instructions.AddI(OpCodes.Stloc, currentIndex); instructions.AddI(OpCodes.Br_S, IL_0059); // loop start var IL_0025 = Instruction.Create(OpCodes.Ldnull); var IL_0042 = Instruction.Create(OpCodes.Ldloc, newArray); instructions.Add(IL_0025); instructions.AddI(OpCodes.Ldarg_0); load(instructions); instructions.AddI(OpCodes.Ldloc, currentIndex); instructions.AddI(OpCodes.Ldelem_Ref); instructions.AddI(OpCodes.Ceq); instructions.AddI(OpCodes.Brfalse_S, IL_0042); var IL_0054 = Instruction.Create(OpCodes.Ldloc, currentIndex); instructions.AddI(OpCodes.Ldloc, newArray); instructions.AddI(OpCodes.Ldloc, currentIndex); instructions.AddI(OpCodes.Ldnull); instructions.AddI(OpCodes.Stelem_Ref); instructions.AddI(OpCodes.Br_S, IL_0054); instructions.Add(IL_0042); instructions.AddI(OpCodes.Ldloc, currentIndex); instructions.AddI(OpCodes.Ldarg_0); load(instructions); instructions.AddI(OpCodes.Ldloc, currentIndex); instructions.AddI(OpCodes.Ldelem_Ref); instructions.AddI(OpCodes.Callvirt, deepCopy); instructions.AddI(OpCodes.Stelem_Ref); // Increment the index. instructions.Add(IL_0054); instructions.AddI(OpCodes.Ldc_I4_1); // TODO replace instructions.AddI(OpCodes.Add); instructions.AddI(OpCodes.Stloc, currentIndex); instructions.Add(IL_0059); instructions.AddI(OpCodes.Ldloc, length); instructions.AddI(OpCodes.Clt); instructions.AddI(OpCodes.Brtrue_S, IL_0025); // end loop instructions.Add(loadMainObj); instructions.AddI(OpCodes.Ldloc, newArray); store(instructions); } }
private void HandleListOfPrimitives(Collection<VariableDefinition> variables, Collection<ExceptionHandler> exceptionHandlers, Collection<Instruction> instructions, TypeReference listRef, Action<Collection<Instruction>> load, Action<Collection<Instruction>> store, MethodReference getCount, MethodReference getItem, MethodReference addMethod) { var intType = this.ModuleDefinition.Import(this.ModuleDefinition.TypeSystem.Int32).Resolve(); var listOfObjConstructor = this.GetGenericTypeConstructorMethod(listRef, new[] { new ParameterDefinition(intType) }); var newList = variables.AddV(listRef); var count = variables.AddV(intType); var currentIndex = variables.AddV(intType); var loadNullAndRet = Instruction.Create(OpCodes.Ldloc_0); instructions.AddI(OpCodes.Ldnull); instructions.AddI(OpCodes.Stloc, newList); instructions.AddI(OpCodes.Ldnull); instructions.AddI(OpCodes.Ldarg_0); load(instructions); instructions.AddI(OpCodes.Ceq); instructions.AddI(OpCodes.Brtrue_S, loadNullAndRet); var forLoopCondition = Instruction.Create(OpCodes.Ldloc, currentIndex); instructions.AddI(OpCodes.Ldarg_0); load(instructions); instructions.AddI(OpCodes.Callvirt, getCount); instructions.AddI(OpCodes.Stloc, count); instructions.AddI(OpCodes.Ldloc, count); instructions.AddI(OpCodes.Newobj, listOfObjConstructor); instructions.AddI(OpCodes.Stloc, newList); instructions.AddI(OpCodes.Ldc_I4_0); instructions.AddI(OpCodes.Stloc, currentIndex); instructions.AddI(OpCodes.Br_S, forLoopCondition); // loop start var loopStart = Instruction.Create(OpCodes.Ldloc, newList); instructions.Add(loopStart); instructions.AddI(OpCodes.Ldarg_0); load(instructions); instructions.AddI(OpCodes.Ldloc, currentIndex); instructions.AddI(OpCodes.Callvirt, getItem); instructions.AddI(OpCodes.Callvirt, addMethod); // loop increment instructions.AddI(OpCodes.Ldloc, currentIndex); instructions.AddI(OpCodes.Ldc_I4_1); instructions.AddI(OpCodes.Add); instructions.AddI(OpCodes.Stloc, currentIndex); // check if condition instructions.Add(forLoopCondition); instructions.AddI(OpCodes.Ldloc, count); instructions.AddI(OpCodes.Clt); instructions.AddI(OpCodes.Brtrue_S, loopStart); // end loop instructions.Add(loadNullAndRet); instructions.AddI(OpCodes.Ldloc, newList); store(instructions); }
private void SafeCallDeepCopy( Collection<VariableDefinition> variables, Collection<ExceptionHandler> exceptionHandlers, Collection<Instruction> instructions, TypeDefinition typeDefinition, Action<Collection<Instruction>> load, Action<Collection<Instruction>> store) { MethodDefinition deepCopy; if (!typeDefinition.TryGetMethod(this._deepCopyMethodName, out deepCopy)) throw new Exception( String.Format("Sub-type {0} does not implement DeepCopy.", typeDefinition.FullName)); var var0 = variables.AddV(typeDefinition); // Load the object, and check to see if it's null. instructions.AddI(OpCodes.Nop); instructions.AddI(OpCodes.Ldarg_0); load(instructions); instructions.AddI(OpCodes.Stloc, var0); instructions.AddI(OpCodes.Ldloc_0); instructions.AddI(OpCodes.Ldloc, var0); var loadNull = Instruction.Create(OpCodes.Ldnull); instructions.AddI(OpCodes.Brfalse_S, loadNull); instructions.AddI(OpCodes.Ldloc, var0); instructions.AddI(OpCodes.Callvirt, deepCopy); var noOp = Instruction.Create(OpCodes.Nop); instructions.AddI(OpCodes.Br_S, noOp); instructions.Add(loadNull); instructions.Add(noOp); store(instructions); }