예제 #1
0
        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);
        }
예제 #2
0
        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);
        }
예제 #3
0
        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);
            }
        }
예제 #4
0
        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);
        }
예제 #5
0
        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);
        }