Beispiel #1
0
        /// <summary>
        /// Gets the type of this variable.
        /// </summary>
        protected override TTypeRef GetType <TTypeRef>(ITypeResolver <TTypeRef> typeResolver)
        {
            if ((originalVariable == null) || (originalVariable.VariableType == null))
            {
                return(default(TTypeRef));
            }
            var xVarType = XBuilder.AsTypeReference(Type.Module, originalVariable.VariableType);

            return(typeResolver.GetTypeReference(xVarType));
        }
Beispiel #2
0
        /// <summary>
        /// Gets a class reference for the given type reference.
        /// </summary>
        internal static TypeReference GetReference(this JvmClassLib.TypeReference type, XTypeUsageFlags usageFlags, DexTargetPackage targetPackage, XModule module)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }

            var xType = XBuilder.AsTypeReference(module, type, usageFlags);

            return(xType.GetReference(targetPackage));
        }
Beispiel #3
0
        /// <summary>
        /// Gets a class reference for the given type reference.
        /// </summary>
        internal static TypeReference GetReference(this Mono.Cecil.TypeReference type, DexTargetPackage targetPackage, XModule module)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }

            var xType = XBuilder.AsTypeReference(module, type);

            return(xType.GetReference(targetPackage));
        }
Beispiel #4
0
        protected override XTypeDefinition CreateXType(XTypeDefinition parentXType)
        {
            var typeDef = (XBuilder.ILTypeDefinition)XBuilder.AsTypeReference(Compiler.Module, Type)
                          .Resolve();

            string name = NameConverter.GetNullableClassName(typeDef.Name);

            XSyntheticTypeFlags xflags = default(XSyntheticTypeFlags);

            return(XSyntheticTypeDefinition.Create(Compiler.Module, parentXType, xflags,
                                                   typeDef.Namespace, name,
                                                   Compiler.Module.TypeSystem.Object,
                                                   string.Join(":", Type.Scope.Name, Type.MetadataToken.ToScopeId(), "Nullable")));
        }
Beispiel #5
0
        void ConvertParameters(List <ByteCode> body)
        {
            AstVariable thisParameter = null;

            if (methodDef.HasThis)
            {
                TypeReference type = methodDef.DeclaringType;
                thisParameter = new AstILVariable("this", XBuilder.AsTypeReference(module, type.IsValueType ? new ByReferenceType(type) : type), methodDef.Body.ThisParameter);
            }
            foreach (var p in methodDef.Parameters)
            {
                Parameters.Add(new AstILVariable(p.Name, XBuilder.AsTypeReference(module, p.ParameterType), p));
            }
            if (Parameters.Count > 0 && (methodDef.IsSetter || methodDef.IsAddOn || methodDef.IsRemoveOn))
            {
                // last parameter must be 'value', so rename it
                Parameters.Last().Name = "value";
            }
            foreach (ByteCode byteCode in body)
            {
                ParameterDefinition p;
                switch (byteCode.Code)
                {
                case AstCode.__Ldarg:
                    p                = (ParameterDefinition)byteCode.Operand;
                    byteCode.Code    = AstCode.Ldloc;
                    byteCode.Operand = p.Index < 0 ? thisParameter : this.Parameters[p.Index];
                    break;

                case AstCode.__Starg:
                    p                = (ParameterDefinition)byteCode.Operand;
                    byteCode.Code    = AstCode.Stloc;
                    byteCode.Operand = p.Index < 0 ? thisParameter : this.Parameters[p.Index];
                    break;

                case AstCode.__Ldarga:
                    p                = (ParameterDefinition)byteCode.Operand;
                    byteCode.Code    = AstCode.Ldloca;
                    byteCode.Operand = p.Index < 0 ? thisParameter : this.Parameters[p.Index];
                    break;
                }
            }
            if (thisParameter != null)
            {
                this.Parameters.Add(thisParameter);
            }
        }
Beispiel #6
0
        /// <summary>
        /// Implement the class now that all classes have been created
        /// </summary>
        protected override void CreateMembers(DexTargetPackage targetPackage)
        {
            // Build ctors
            foreach (var baseCtor in GetBaseClassCtors())
            {
                // Build ctor
                var prototype = PrototypeBuilder.BuildPrototype(Compiler, targetPackage, null, baseCtor);
                var ctor      = new MethodDefinition(Class, "<init>", prototype);
                ctor.AccessFlags = AccessFlags.Public | AccessFlags.Constructor;
                Class.Methods.Add(ctor);
                // Create ctor body
                var ctorBody = CreateCtorBody(prototype);
                targetPackage.Record(new CompiledMethod {
                    DexMethod = ctor, RLBody = ctorBody
                });
            }

            // build original type field
            // Create field definition
            var dfield = new Dot42.DexLib.FieldDefinition();

            dfield.Owner       = Class;
            dfield.Name        = "underlying$";
            dfield.IsSynthetic = true;
            dfield.IsFinal     = true;
            dfield.IsStatic    = true;
            dfield.IsPublic    = true;

            dfield.Type = Compiler.Module.TypeSystem.Type.GetClassReference(targetPackage);

            // not sure if GetClassReference is the best way to go forward here.
            // might depend on the sort order of the class builders.
            var underlyingType = XBuilder.AsTypeReference(Compiler.Module, Type);

            dfield.Value = underlyingType.GetClassReference(targetPackage);

            Class.Fields.Add(dfield);
        }
Beispiel #7
0
        private static MethodDefinition CreateFactoryMethod(AssemblyCompiler compiler, DexTargetPackage targetPackage, CustomAttribute attribute, AttributeAnnotationMapping mapping)
        {
            var             targetClass      = mapping.AttributeClass; // is this really the right place for the factory methods?
            ISourceLocation seqp             = null;
            var             attributeTypeDef = attribute.AttributeType.Resolve();

            // create method
            string           methodName = CreateAttributeFactoryMethodName(targetClass);
            MethodDefinition method     = new MethodDefinition(targetClass, methodName, new Prototype(mapping.AttributeClass));

            method.AccessFlags = AccessFlags.Public | AccessFlags.Static | AccessFlags.Synthetic;
            targetClass.Methods.Add(method);

            // create method body
            MethodBody body = new MethodBody(null);
            // Allocate attribute
            Register attributeReg = body.AllocateRegister(RCategory.Temp, RType.Object);

            body.Instructions.Add(seqp, RCode.New_instance, mapping.AttributeClass, attributeReg);

            // collect ctor arguments
            List <Register> ctorArgRegs = new List <Register>()
            {
                attributeReg
            };

            foreach (var p in attribute.ConstructorArguments)
            {
                XTypeReference xType     = XBuilder.AsTypeReference(compiler.Module, p.Type);
                Register[]     valueRegs = CreateInitializeValueInstructions(seqp, body, xType, p, compiler, targetPackage);
                ctorArgRegs.AddRange(valueRegs);
            }
            // Invoke ctor
            DexLib.MethodReference dctor = attribute.Constructor.GetReference(targetPackage, compiler.Module);
            body.Instructions.Add(seqp, RCode.Invoke_direct, dctor, ctorArgRegs.ToArray());

            // set field values
            foreach (var p in attribute.Fields)
            {
                var field  = GetField(attributeTypeDef, p.Name);
                var xField = XBuilder.AsFieldReference(compiler.Module, field);

                Register[] valueRegs = CreateInitializeValueInstructions(seqp, body, xField.FieldType, p.Argument, compiler, targetPackage);
                body.Instructions.Add(seqp, xField.FieldType.IPut(), xField.GetReference(targetPackage),
                                      valueRegs[0], attributeReg);
            }

            // set property values
            foreach (var p in attribute.Properties)
            {
                PropertyDefinition property = GetSettableProperty(attributeTypeDef, p.Name);
                XTypeReference     xType    = XBuilder.AsTypeReference(compiler.Module, property.PropertyType);

                Register[]        valueRegs  = CreateInitializeValueInstructions(seqp, body, xType, p.Argument, compiler, targetPackage);
                XMethodDefinition xSetMethod = XBuilder.AsMethodDefinition(compiler.Module, property.SetMethod);
                body.Instructions.Add(seqp, xSetMethod.Invoke(xSetMethod, null),
                                      xSetMethod.GetReference(targetPackage),
                                      new[] { attributeReg }.Concat(valueRegs).ToArray());
            }

            // Return attribute
            body.Instructions.Add(seqp, RCode.Return_object, attributeReg);

            // Register method body
            targetPackage.Record(new CompiledMethod()
            {
                DexMethod = method, RLBody = body
            });

            // Return method
            return(method);
        }
Beispiel #8
0
        /// <summary>
        /// Create all annotations for this method
        /// </summary>
        internal virtual void CreateAnnotations(DexTargetPackage targetPackage)
        {
            // Build method annotations
            AttributeAnnotationInstanceBuilder.CreateAttributeAnnotations(compiler, method, dmethod, targetPackage);

            // only add generics annotation for getters or setters or constructors
            if (method.IsGetter)
            {
                // Note that the return type might has been
                // changed above, to compensate for interface
                // inheritance and generic specialization.
                // We need to use the original declaration.
                // TODO: why not get rid of "OriginalReturnType"
                //       and use the IL's return type??
                var returnType = xMethod.OriginalReturnType;
                var xType      = XBuilder.AsTypeReference(compiler.Module, returnType);
                dmethod.AddGenericDefinitionAnnotationIfGeneric(xType, compiler, targetPackage);
            }
            else if (method.IsSetter)
            {
                for (int i = 0; i < xMethod.Parameters.Count; ++i)
                {
                    var dp = dmethod.Prototype.Parameters[i];
                    dp.AddGenericDefinitionAnnotationIfGeneric(xMethod.Parameters[i].ParameterType, compiler,
                                                               targetPackage);
                }
            }
            else if (method.IsConstructor && !method.IsStatic)
            {
                // Add parameter names and original access flags, as these might be important
                // in serialization and/or dependency injection.

                var reflectionInfo = compiler.GetDot42InternalType(InternalConstants.ReflectionInfoAnnotation)
                                     .GetClassReference(targetPackage);
                var annotation = new Annotation {
                    Type = reflectionInfo, Visibility = AnnotationVisibility.Runtime
                };

                bool isPublic = (method.OriginalAttributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Public;

                // Not sure if it makes any sense to remap the access flags.
                bool isProtected = (method.OriginalAttributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Family ||
                                   (method.OriginalAttributes & MethodAttributes.MemberAccessMask) == MethodAttributes.FamANDAssem ||
                                   (method.OriginalAttributes & MethodAttributes.MemberAccessMask) == MethodAttributes.FamORAssem;

                bool isInternal = (method.OriginalAttributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Assembly ||
                                  (method.OriginalAttributes & MethodAttributes.MemberAccessMask) == MethodAttributes.FamANDAssem ||
                                  (method.OriginalAttributes & MethodAttributes.MemberAccessMask) == MethodAttributes.FamORAssem;

                bool isPrivate = (method.OriginalAttributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Private;

                // only create accessFlags if they differs from java's
                if (isPublic != dmethod.IsPublic ||
                    isProtected != dmethod.IsProtected ||
                    isPrivate != dmethod.IsPrivate ||
                    isInternal)
                {
                    int accessFlags = 0;
                    if (isPublic)
                    {
                        accessFlags |= 0x01;
                    }
                    if (isProtected)
                    {
                        accessFlags |= 0x02;
                    }
                    if (isPrivate)
                    {
                        accessFlags |= 0x04;
                    }
                    if (isInternal)
                    {
                        accessFlags |= 0x08;
                    }
                    annotation.Arguments.Add(new AnnotationArgument(InternalConstants.ReflectionInfoAccessFlagsField, accessFlags));
                }

                if (method.Parameters.Count > 0)
                {
                    annotation.Arguments.Add(new AnnotationArgument(InternalConstants.ReflectionInfoParameterNamesField,
                                                                    method.Parameters.Select(p => p.Name).ToArray()));
                }

                if (annotation.Arguments.Count > 0)
                {
                    dmethod.Annotations.Add(annotation);
                }

                //for (int i = 0; i < xMethod.Parameters.Count; ++i)
                //{
                //    var dp = dmethod.Prototype.Parameters[i];
                //    dp.AddGenericDefinitionAnnotationIfGeneric(xMethod.Parameters[i].ParameterType, compiler,
                //        targetPackage);
                //}
            }
        }
Beispiel #9
0
 /// <summary>
 /// Make a xtype reference for a java class name.
 /// </summary>
 private XTypeReference AsTypeReference(string className, XTypeUsageFlags usageFlags)
 {
     return(XBuilder.AsTypeReference(module, className, usageFlags));
 }
Beispiel #10
0
 /// <summary>
 /// Make a .NET type reference for a java type reference.
 /// </summary>
 private XTypeReference AsTypeReference(JvmClassLib.TypeReference javaRef, XTypeUsageFlags usageFlags)
 {
     return(XBuilder.AsTypeReference(module, javaRef, usageFlags));
 }
Beispiel #11
0
 /// <summary>
 /// Make a .NET type reference for a java class file.
 /// </summary>
 private XTypeReference AsTypeReference(ClassFile classFile, XTypeUsageFlags usageFlags)
 {
     return(XBuilder.AsTypeReference(module, classFile, usageFlags));
 }
Beispiel #12
0
            /// <summary>
            /// Convert the given interface method if it has explicit implementations.
            /// </summary>
            private void ConvertInterfaceMethod(TypeDefinition iType, MethodDefinition iMethod)
            {
                var implementations = GetImplementations(iMethod);
                var iMethodIsJavaWithGenericParams = iMethod.IsJavaMethodWithGenericParams();
                var iMethodContainsGenericParams   = iMethod.ContainsGenericParameter;

                if (!iMethodIsJavaWithGenericParams && !iMethodContainsGenericParams && (!implementations.Any(x => x.IsExplicitImplementation())))
                {
                    // There are no explicit implementation.
                    // No need to convert
                    return;
                }

                // Rename method
                string newName;
                bool   createExplicitStubs = true;
                var    oldName             = iMethod.Name;
                var    attr = iMethod.GetDexOrJavaImportAttribute();

                if (attr != null)
                {
                    string className;
                    string memberName;
                    string descriptor;
                    attr.GetDexOrJavaImportNames(iMethod, out memberName, out descriptor, out className);
                    newName = memberName;
                }
                else if ((attr = iMethod.GetDexNameAttribute()) != null)
                {
                    newName             = (string)(attr.ConstructorArguments[0].Value);
                    createExplicitStubs = false;
                }
                else
                {
                    var module = reachableContext.Compiler.Module;
                    var xiType = XBuilder.AsTypeReference(module, iType);
                    newName = methodNames.GetUniqueName(NameConverter.GetConvertedName(xiType) + "_" + iMethod.Name);
                    oldName = newName;
                }
                Rename(iMethod, newName);


                // Update implementations
                foreach (var impl in implementations)
                {
                    if (impl.IsExplicitImplementation())
                    {
                        // Convert to implicit
                        impl.IsPublic = true;

                        // Rename
                        Rename(impl, newName);
                        // Update names of overrides
                        foreach (var @override in impl.Overrides)
                        {
                            @override.Name = newName;
                        }
                    }
                    else if (!(impl.HasDexImportAttribute() || impl.HasJavaImportAttribute()))
                    {
                        // Add stub redirecting explicit implementation to implicit implementation
                        if (createExplicitStubs)
                        {
                            CreateExplicitStub(impl, newName, oldName, iMethod, iMethodIsJavaWithGenericParams /*|| iMethodContainsGenericParams*/);
                        }
                    }
                }
            }
Beispiel #13
0
 /// <summary>
 /// Create the XType for this builder.
 /// </summary>
 protected virtual XTypeDefinition CreateXType(XTypeDefinition parentXType)
 {
     return(XBuilder.AsTypeReference(compiler.Module, typeDef).Resolve());
 }
Beispiel #14
0
        /// <summary>
        /// Create a method definition for the builder method that builds a custom attribute from an annotation.
        /// </summary>
        private static MethodDefinition CreateBuildMethod(
            ISourceLocation seqp,
            Mono.Cecil.MethodDefinition ctor,
            List <MethodDefinition> paramGetMethods,
            AssemblyCompiler compiler,
            DexTargetPackage targetPackage,
            ClassDefinition attributeClass,
            AttributeAnnotationInterface mapping)
        {
            // Create method definition
            string           name             = CreateBuildMethodName(attributeClass);
            TypeReference    attributeTypeRef = ctor.DeclaringType.GetReference(targetPackage, compiler.Module);
            MethodDefinition method           = new MethodDefinition(attributeClass, name, new Prototype(attributeTypeRef, new Parameter(mapping.AnnotationInterfaceClass, "ann")));

            method.AccessFlags = AccessFlags.Public | AccessFlags.Static | AccessFlags.Synthetic;
            attributeClass.Methods.Add(method);

            // Create method body
            MethodBody body          = new MethodBody(null);
            Register   annotationReg = body.AllocateRegister(RCategory.Argument, RType.Object);
            //body.Instructions.Add(seqp, RCode.Check_cast, mapping.AnnotationInterfaceClass, annotationReg);

            // Allocate attribute
            Register attributeReg = body.AllocateRegister(RCategory.Temp, RType.Object);

            body.Instructions.Add(seqp, RCode.New_instance, attributeClass, attributeReg);

            // Get ctor arguments
            List <Register> ctorArgRegs = new List <Register>();

            foreach (MethodDefinition p in paramGetMethods)
            {
                TypeReference paramType = p.Prototype.ReturnType;
                Register[]    valueRegs = CreateLoadValueSequence(seqp, body, paramType, annotationReg, p);
                ctorArgRegs.AddRange(valueRegs);
            }

            // Invoke ctor
            DexLib.MethodReference dctor = ctor.GetReference(targetPackage, compiler.Module);
            body.Instructions.Add(seqp, RCode.Invoke_direct, dctor, new[] { attributeReg }.Concat(ctorArgRegs).ToArray());

            // Get field values
            foreach (var fieldMap in mapping.FieldToGetMethodMap)
            {
                Mono.Cecil.FieldDefinition field  = fieldMap.Key;
                MethodDefinition           getter = fieldMap.Value;
                Register[]            valueRegs   = CreateLoadValueSequence(seqp, body, getter.Prototype.ReturnType, annotationReg, getter);
                DexLib.FieldReference dfield      = field.GetReference(targetPackage, compiler.Module);
                XModel.XTypeReference xFieldType  = XBuilder.AsTypeReference(compiler.Module, field.FieldType);
                body.Instructions.Add(seqp, xFieldType.IPut(), dfield, valueRegs[0], attributeReg);
            }

            // Get property values
            foreach (var propertyMap in mapping.PropertyToGetMethodMap)
            {
                PropertyDefinition       property   = propertyMap.Key;
                MethodDefinition         getter     = propertyMap.Value;
                Register[]               valueRegs  = CreateLoadValueSequence(seqp, body, getter.Prototype.ReturnType, annotationReg, getter);
                DexLib.MethodReference   dmethod    = property.SetMethod.GetReference(targetPackage, compiler.Module);
                XModel.XMethodDefinition xSetMethod = XBuilder.AsMethodDefinition(compiler.Module, property.SetMethod);
                body.Instructions.Add(seqp, xSetMethod.Invoke(xSetMethod, null), dmethod, new[] { attributeReg }.Concat(valueRegs).ToArray());
            }

            // Return attribute
            body.Instructions.Add(seqp, RCode.Return_object, attributeReg);

            // Register method body
            targetPackage.Record(new CompiledMethod()
            {
                DexMethod = method, RLBody = body
            });

            // Return method
            return(method);
        }
Beispiel #15
0
        private List <AstNode> ConvertToAst(IEnumerable <ByteCode> body)
        {
            var ast = new List <AstNode>();

            // Convert stack-based IL code to ILAst tree
            foreach (var byteCode in body)
            {
                var ilRange = new InstructionRange(byteCode.Offset, byteCode.EndOffset);

                if (byteCode.StackBefore == null)
                {
                    // Unreachable code
                    continue;
                }

                var expr = new AstExpression(byteCode.SequencePoint, byteCode.Code, byteCode.Operand);
                expr.ILRanges.Add(ilRange);
                if (byteCode.Prefixes != null && byteCode.Prefixes.Length > 0)
                {
                    var prefixes = new AstExpressionPrefix[byteCode.Prefixes.Length];
                    for (var i = 0; i < prefixes.Length; i++)
                    {
                        var operand = byteCode.Prefixes[i].Operand;
                        if (operand is FieldReference)
                        {
                            operand = XBuilder.AsFieldReference(module, (FieldReference)operand);
                        }
                        else if (operand is MethodReference)
                        {
                            operand = XBuilder.AsMethodReference(module, (MethodReference)operand);
                        }
                        else if (operand is TypeReference)
                        {
                            operand = XBuilder.AsTypeReference(module, (TypeReference)operand);
                        }
                        prefixes[i] = new AstExpressionPrefix((AstCode)byteCode.Prefixes[i].OpCode.Code, operand);
                    }
                    expr.Prefixes = prefixes;
                }

                // Label for this instruction
                if (byteCode.Label != null)
                {
                    ast.Add(byteCode.Label);
                }

                // Reference arguments using temporary variables
                var popCount = byteCode.PopCount ?? byteCode.StackBefore.Length;
                for (var i = byteCode.StackBefore.Length - popCount; i < byteCode.StackBefore.Length; i++)
                {
                    var slot = byteCode.StackBefore[i];
                    expr.Arguments.Add(new AstExpression(byteCode.SequencePoint, AstCode.Ldloc, slot.LoadFrom));
                }

                // Store the result to temporary variable(s) if needed
                if (byteCode.StoreTo == null || byteCode.StoreTo.Count == 0)
                {
                    ast.Add(expr);
                }
                else if (byteCode.StoreTo.Count == 1)
                {
                    ast.Add(new AstExpression(byteCode.SequencePoint, AstCode.Stloc, byteCode.StoreTo[0], expr));
                }
                else
                {
                    var tmpVar = new AstGeneratedVariable("expr_" + byteCode.Offset.ToString("X2"), byteCode.StoreTo.Select(x => x.OriginalName).FirstOrDefault());
                    ast.Add(new AstExpression(byteCode.SequencePoint, AstCode.Stloc, tmpVar, expr));
                    foreach (var storeTo in byteCode.StoreTo.AsEnumerable().Reverse())
                    {
                        ast.Add(new AstExpression(byteCode.SequencePoint, AstCode.Stloc, storeTo, new AstExpression(byteCode.SequencePoint, AstCode.Ldloc, tmpVar)));
                    }
                }
            }

            return(ast);
        }
Beispiel #16
0
        List <AstNode> ConvertToAst(List <ByteCode> body, HashSet <ExceptionHandler> ehs)
        {
            var ast = new List <AstNode>();

            while (ehs.Any())
            {
                var tryCatchBlock = new AstTryCatchBlock(null);

                // Find the first and widest scope
                var tryStart = ehs.Min(eh => eh.TryStart.Offset);
                var tryEnd   = ehs.Where(eh => eh.TryStart.Offset == tryStart).Max(eh => eh.TryEnd.Offset);
                var handlers = ehs.Where(eh => eh.TryStart.Offset == tryStart && eh.TryEnd.Offset == tryEnd).OrderBy(eh => eh.TryStart.Offset).ToList();

                // Remember that any part of the body migt have been removed due to unreachability

                // Cut all instructions up to the try block
                {
                    var tryStartIdx = 0;
                    while (tryStartIdx < body.Count && body[tryStartIdx].Offset < tryStart)
                    {
                        tryStartIdx++;
                    }
                    ast.AddRange(ConvertToAst(CollectionExtensions.CutRange(body, 0, tryStartIdx)));
                }

                // Cut the try block
                {
                    var nestedEHs = new HashSet <ExceptionHandler>(
                        ehs.Where(eh => (tryStart <= eh.TryStart.Offset && eh.TryEnd.Offset < tryEnd) || (tryStart < eh.TryStart.Offset && eh.TryEnd.Offset <= tryEnd)));
                    ehs.ExceptWith(nestedEHs);
                    var tryEndIdx = 0;
                    while (tryEndIdx < body.Count && body[tryEndIdx].Offset < tryEnd)
                    {
                        tryEndIdx++;
                    }
                    var converted = ConvertToAst(CollectionExtensions.CutRange(body, 0, tryEndIdx), nestedEHs);
                    tryCatchBlock.TryBlock = new AstBlock(converted.Select(x => x.SourceLocation).FirstOrDefault(), converted);
                }

                // Cut all handlers
                tryCatchBlock.CatchBlocks.Clear();
                foreach (var eh in handlers)
                {
                    var handlerEndOffset = eh.HandlerEnd == null ? methodDef.Body.CodeSize : eh.HandlerEnd.Offset;
                    var startIdx         = 0;
                    while (startIdx < body.Count && body[startIdx].Offset < eh.HandlerStart.Offset)
                    {
                        startIdx++;
                    }
                    var endIdx = 0;
                    while (endIdx < body.Count && body[endIdx].Offset < handlerEndOffset)
                    {
                        endIdx++;
                    }
                    var nestedEHs = new HashSet <ExceptionHandler>(ehs.Where(e => (eh.HandlerStart.Offset <= e.TryStart.Offset && e.TryEnd.Offset < handlerEndOffset) || (eh.HandlerStart.Offset < e.TryStart.Offset && e.TryEnd.Offset <= handlerEndOffset)));
                    ehs.ExceptWith(nestedEHs);
                    var handlerAst = ConvertToAst(CollectionExtensions.CutRange(body, startIdx, endIdx - startIdx), nestedEHs);
                    if (eh.HandlerType == ExceptionHandlerType.Catch)
                    {
                        var catchType  = eh.CatchType.IsSystemObject() ? module.TypeSystem.Exception : XBuilder.AsTypeReference(module, eh.CatchType);
                        var catchBlock = new AstTryCatchBlock.CatchBlock(handlerAst.Select(x => x.SourceLocation).FirstOrDefault(), tryCatchBlock)
                        {
                            ExceptionType = catchType,
                            Body          = handlerAst
                        };
                        // Handle the automatically pushed exception on the stack
                        var ldexception = ldexceptions[eh];
                        if (ldexception.StoreTo == null || ldexception.StoreTo.Count == 0)
                        {
                            // Exception is not used
                            catchBlock.ExceptionVariable = null;
                        }
                        else if (ldexception.StoreTo.Count == 1)
                        {
                            var first = catchBlock.Body[0] as AstExpression;
                            if (first != null &&
                                first.Code == AstCode.Pop &&
                                first.Arguments[0].Code == AstCode.Ldloc &&
                                first.Arguments[0].Operand == ldexception.StoreTo[0])
                            {
                                // The exception is just poped - optimize it all away;
                                if (context.Settings.AlwaysGenerateExceptionVariableForCatchBlocks)
                                {
                                    catchBlock.ExceptionVariable = new AstGeneratedVariable("ex_" + eh.HandlerStart.Offset.ToString("X2"), null);
                                }
                                else
                                {
                                    catchBlock.ExceptionVariable = null;
                                }
                                catchBlock.Body.RemoveAt(0);
                            }
                            else
                            {
                                catchBlock.ExceptionVariable = ldexception.StoreTo[0];
                            }
                        }
                        else
                        {
                            var exTemp = new AstGeneratedVariable("ex_" + eh.HandlerStart.Offset.ToString("X2"), null);
                            catchBlock.ExceptionVariable = exTemp;
                            foreach (var storeTo in ldexception.StoreTo)
                            {
                                catchBlock.Body.Insert(0, new AstExpression(catchBlock.SourceLocation, AstCode.Stloc, storeTo, new AstExpression(catchBlock.SourceLocation, AstCode.Ldloc, exTemp)));
                            }
                        }
                        tryCatchBlock.CatchBlocks.Add(catchBlock);
                    }
                    else if (eh.HandlerType == ExceptionHandlerType.Finally)
                    {
                        tryCatchBlock.FinallyBlock = new AstBlock(handlerAst);
                    }
                    else if (eh.HandlerType == ExceptionHandlerType.Fault)
                    {
                        tryCatchBlock.FaultBlock = new AstBlock(handlerAst);
                    }
                    else
                    {
                        // TODO: ExceptionHandlerType.Filter
                    }
                }

                ehs.ExceptWith(handlers);

                ast.Add(tryCatchBlock);
            }

            // Add whatever is left
            ast.AddRange(ConvertToAst(body));

            return(ast);
        }
Beispiel #17
0
        /// <summary>
        /// Analyse the instructions in the method code and convert them to a ByteCode list.
        /// </summary>
        private List <ByteCode> StackAnalysis()
        {
            var instrToByteCode = new Dictionary <Instruction, ByteCode>();

            // Create temporary structure for the stack analysis
            var body = new List <ByteCode>(methodDef.Body.Instructions.Count);
            List <Instruction> prefixes = null;

            foreach (var inst in methodDef.Body.Instructions)
            {
                if (inst.OpCode.OpCodeType == OpCodeType.Prefix)
                {
                    if (prefixes == null)
                    {
                        prefixes = new List <Instruction>(1);
                    }
                    prefixes.Add(inst);
                    continue;
                }
                var code    = (AstCode)inst.OpCode.Code;
                var operand = inst.Operand;
                AstCodeUtil.ExpandMacro(ref code, ref operand, methodDef.Body);
                var byteCode = new ByteCode
                {
                    Offset        = inst.Offset,
                    EndOffset     = inst.Next != null ? inst.Next.Offset : methodDef.Body.CodeSize,
                    Code          = code,
                    Operand       = operand,
                    PopCount      = inst.GetPopDelta(methodDef),
                    PushCount     = inst.GetPushDelta(),
                    SequencePoint = SequencePointWrapper.Wrap(inst.SequencePoint)
                };
                if (prefixes != null)
                {
                    instrToByteCode[prefixes[0]] = byteCode;
                    byteCode.Offset   = prefixes[0].Offset;
                    byteCode.Prefixes = prefixes.ToArray();
                    prefixes          = null;
                }
                else
                {
                    instrToByteCode[inst] = byteCode;
                }
                body.Add(byteCode);
            }
            for (int i = 0; i < body.Count - 1; i++)
            {
                body[i].Next = body[i + 1];
            }

            var agenda   = new Stack <ByteCode>();
            var varCount = methodDef.Body.Variables.Count;

            var exceptionHandlerStarts = new HashSet <ByteCode>(methodDef.Body.ExceptionHandlers.Select(eh => instrToByteCode[eh.HandlerStart]));

            // Add known states
            if (methodDef.Body.HasExceptionHandlers)
            {
                foreach (var ex in methodDef.Body.ExceptionHandlers)
                {
                    var handlerStart = instrToByteCode[ex.HandlerStart];
                    handlerStart.StackBefore     = new StackSlot[0];
                    handlerStart.VariablesBefore = VariableSlot.MakeUknownState(varCount);
                    if (ex.HandlerType == ExceptionHandlerType.Catch || ex.HandlerType == ExceptionHandlerType.Filter)
                    {
                        // Catch and Filter handlers start with the exeption on the stack
                        var ldexception = new ByteCode()
                        {
                            Code      = AstCode.Ldexception,
                            Operand   = ex.CatchType,
                            PopCount  = 0,
                            PushCount = 1
                        };
                        ldexceptions[ex]         = ldexception;
                        handlerStart.StackBefore = new[] { new StackSlot(new[] { ldexception }, null) };
                    }
                    agenda.Push(handlerStart);

                    if (ex.HandlerType == ExceptionHandlerType.Filter)
                    {
                        var filterStart = instrToByteCode[ex.FilterStart];
                        var ldexception = new ByteCode
                        {
                            Code      = AstCode.Ldexception,
                            Operand   = ex.CatchType,
                            PopCount  = 0,
                            PushCount = 1
                        };
                        // TODO: ldexceptions[ex] = ldexception;
                        filterStart.StackBefore     = new[] { new StackSlot(new[] { ldexception }, null) };
                        filterStart.VariablesBefore = VariableSlot.MakeUknownState(varCount);
                        agenda.Push(filterStart);
                    }
                }
            }

            body[0].StackBefore     = new StackSlot[0];
            body[0].VariablesBefore = VariableSlot.MakeUknownState(varCount);
            agenda.Push(body[0]);

            // Process agenda
            while (agenda.Count > 0)
            {
                var byteCode = agenda.Pop();

                // Calculate new stack
                var newStack = StackSlot.ModifyStack(byteCode.StackBefore, byteCode.PopCount ?? byteCode.StackBefore.Length, byteCode.PushCount, byteCode);

                // Calculate new variable state
                var newVariableState = VariableSlot.CloneVariableState(byteCode.VariablesBefore);
                if (byteCode.IsVariableDefinition)
                {
                    newVariableState[((VariableReference)byteCode.Operand).Index] = new VariableSlot(new[] { byteCode }, false);
                }

                // After the leave, finally block might have touched the variables
                if (byteCode.Code == AstCode.Leave)
                {
                    newVariableState = VariableSlot.MakeUknownState(varCount);
                }

                // Find all successors
                var branchTargets = new List <ByteCode>();
                if (!byteCode.Code.IsUnconditionalControlFlow())
                {
                    if (exceptionHandlerStarts.Contains(byteCode.Next))
                    {
                        // Do not fall though down to exception handler
                        // It is invalid IL as per ECMA-335 §12.4.2.8.1, but some obfuscators produce it
                    }
                    else
                    {
                        branchTargets.Add(byteCode.Next);
                    }
                }
                if (byteCode.Operand is Instruction[])
                {
                    foreach (var inst in (Instruction[])byteCode.Operand)
                    {
                        var target = instrToByteCode[inst];
                        branchTargets.Add(target);
                        // The target of a branch must have label
                        if (target.Label == null)
                        {
                            target.Label = new AstLabel(target.SequencePoint, target.Name);
                        }
                    }
                }
                else if (byteCode.Operand is Instruction)
                {
                    var target = instrToByteCode[(Instruction)byteCode.Operand];
                    branchTargets.Add(target);
                    // The target of a branch must have label
                    if (target.Label == null)
                    {
                        target.Label = new AstLabel(target.SequencePoint, target.Name);
                    }
                }

                // Apply the state to successors
                foreach (var branchTarget in branchTargets)
                {
                    if (branchTarget.StackBefore == null && branchTarget.VariablesBefore == null)
                    {
                        if (branchTargets.Count == 1)
                        {
                            branchTarget.StackBefore     = newStack;
                            branchTarget.VariablesBefore = newVariableState;
                        }
                        else
                        {
                            // Do not share data for several bytecodes
                            branchTarget.StackBefore     = StackSlot.ModifyStack(newStack, 0, 0, null);
                            branchTarget.VariablesBefore = VariableSlot.CloneVariableState(newVariableState);
                        }
                        agenda.Push(branchTarget);
                    }
                    else
                    {
                        if (branchTarget.StackBefore.Length != newStack.Length)
                        {
                            throw new Exception("Inconsistent stack size at " + byteCode.Name);
                        }

                        // Be careful not to change our new data - it might be reused for several branch targets.
                        // In general, be careful that two bytecodes never share data structures.

                        bool modified = false;

                        // Merge stacks - modify the target
                        for (int i = 0; i < newStack.Length; i++)
                        {
                            var oldDefs = branchTarget.StackBefore[i].Definitions;
                            var newDefs = oldDefs.Union(newStack[i].Definitions);
                            if (newDefs.Length > oldDefs.Length)
                            {
                                branchTarget.StackBefore[i] = new StackSlot(newDefs, null);
                                modified = true;
                            }
                        }

                        // Merge variables - modify the target
                        for (int i = 0; i < newVariableState.Length; i++)
                        {
                            var oldSlot = branchTarget.VariablesBefore[i];
                            var newSlot = newVariableState[i];
                            if (!oldSlot.UnknownDefinition)
                            {
                                if (newSlot.UnknownDefinition)
                                {
                                    branchTarget.VariablesBefore[i] = newSlot;
                                    modified = true;
                                }
                                else
                                {
                                    ByteCode[] oldDefs = oldSlot.Definitions;
                                    ByteCode[] newDefs = CollectionExtensions.Union(oldDefs, newSlot.Definitions);
                                    if (newDefs.Length > oldDefs.Length)
                                    {
                                        branchTarget.VariablesBefore[i] = new VariableSlot(newDefs, false);
                                        modified = true;
                                    }
                                }
                            }
                        }

                        if (modified)
                        {
                            agenda.Push(branchTarget);
                        }
                    }
                }
            }

            // Occasionally the compilers or obfuscators generate unreachable code (which might be intentonally invalid)
            // I belive it is safe to just remove it
            body.RemoveAll(b => b.StackBefore == null);

            // Genertate temporary variables to replace stack
            foreach (var byteCode in body)
            {
                int argIdx   = 0;
                int popCount = byteCode.PopCount ?? byteCode.StackBefore.Length;
                for (int i = byteCode.StackBefore.Length - popCount; i < byteCode.StackBefore.Length; i++)
                {
                    var tmpVar = new AstGeneratedVariable(string.Format("arg_{0:X2}_{1}", byteCode.Offset, argIdx), null);
                    byteCode.StackBefore[i] = new StackSlot(byteCode.StackBefore[i].Definitions, tmpVar);
                    foreach (ByteCode pushedBy in byteCode.StackBefore[i].Definitions)
                    {
                        if (pushedBy.StoreTo == null)
                        {
                            pushedBy.StoreTo = new List <AstVariable>(1);
                        }
                        pushedBy.StoreTo.Add(tmpVar);
                    }
                    argIdx++;
                }
            }

            // Try to use single temporary variable insted of several if possilbe (especially useful for dup)
            // This has to be done after all temporary variables are assigned so we know about all loads
            foreach (var byteCode in body)
            {
                if (byteCode.StoreTo != null && byteCode.StoreTo.Count > 1)
                {
                    var locVars = byteCode.StoreTo;
                    // For each of the variables, find the location where it is loaded - there should be preciesly one
                    var loadedBy = locVars.Select(locVar => body.SelectMany(bc => bc.StackBefore).Single(s => s.LoadFrom == locVar)).ToList();
                    // We now know that all the variables have a single load,
                    // Let's make sure that they have also a single store - us
                    if (loadedBy.All(slot => slot.Definitions.Length == 1 && slot.Definitions[0] == byteCode))
                    {
                        // Great - we can reduce everything into single variable
                        var tmpVar = new AstGeneratedVariable(string.Format("expr_{0:X2}", byteCode.Offset), locVars.Select(x => x.OriginalName).FirstOrDefault());
                        byteCode.StoreTo = new List <AstVariable>()
                        {
                            tmpVar
                        };
                        foreach (var bc in body)
                        {
                            for (int i = 0; i < bc.StackBefore.Length; i++)
                            {
                                // Is it one of the variable to be merged?
                                if (locVars.Contains(bc.StackBefore[i].LoadFrom))
                                {
                                    // Replace with the new temp variable
                                    bc.StackBefore[i] = new StackSlot(bc.StackBefore[i].Definitions, tmpVar);
                                }
                            }
                        }
                    }
                }
            }

            // Split and convert the normal local variables
            ConvertLocalVariables(body);

            // Convert branch targets to labels and references to xreferences
            foreach (var byteCode in body)
            {
                if (byteCode.Operand is Instruction[])
                {
                    byteCode.Operand = (from target in (Instruction[])byteCode.Operand select instrToByteCode[target].Label).ToArray();
                }
                else if (byteCode.Operand is Instruction)
                {
                    byteCode.Operand = instrToByteCode[(Instruction)byteCode.Operand].Label;
                }
                else if (byteCode.Operand is FieldReference)
                {
                    byteCode.Operand = XBuilder.AsFieldReference(module, (FieldReference)byteCode.Operand);
                }
                else if (byteCode.Operand is MethodReference)
                {
                    byteCode.Operand = XBuilder.AsMethodReference(module, (MethodReference)byteCode.Operand);
                }
                else if (byteCode.Operand is TypeReference)
                {
                    byteCode.Operand = XBuilder.AsTypeReference(module, (TypeReference)byteCode.Operand);
                }
            }

            // Convert parameters to ILVariables
            ConvertParameters(body);

            return(body);
        }
Beispiel #18
0
        /// <summary>
        /// Create code to initialize a value from an attribute.
        /// </summary>
        /// <returns>The register(s) holding the value</returns>
        private static Register[] CreateInitializeValueInstructions(ISourceLocation seqp, MethodBody body, XTypeReference targetType, CustomAttributeArgument value, AssemblyCompiler compiler, DexTargetPackage targetPackage)
        {
            List <Register> result = new List <Register>();

            // allocate result, initialize to default value.
            if (targetType.IsWide())
            {
                Tuple <Register, Register> regs = body.AllocateWideRegister(RCategory.Temp);
                //body.Instructions.Add(seqp, RCode.Const_wide, 0, regs.Item1);
                result.Add(regs.Item1);
                result.Add(regs.Item2);
            }
            else if (targetType.IsPrimitive)
            {
                Register reg = body.AllocateRegister(RCategory.Temp, RType.Value);
                //body.Instructions.Add(seqp, RCode.Const, 0, reg);
                result.Add(reg);
            }
            else // object
            {
                Register reg = body.AllocateRegister(RCategory.Temp, RType.Object);
                //body.Instructions.Add(seqp, RCode.Const, 0, reg);
                result.Add(reg);
            }

            // load data

            if (value.Value == null) // must be a reference type
            {
                body.Instructions.Add(seqp, RCode.Const, 0, result[0]);
                body.Instructions.Add(seqp, RCode.Check_cast, targetType.GetReference(targetPackage), result[0]);
                return(result.ToArray());
            }

            var valueType = XBuilder.AsTypeReference(compiler.Module, value.Type);

            if (value.Value is CustomAttributeArgument)
            {
                // this happens if a type conversion is neccessary
                var nestedValue = (CustomAttributeArgument)value.Value;
                valueType = XBuilder.AsTypeReference(compiler.Module, nestedValue.Type);

                var rOrigValue = CreateInitializeValueInstructions(seqp, body, valueType, nestedValue, compiler, targetPackage);

                if (!nestedValue.Type.IsPrimitive)
                {
                    body.Instructions.Add(seqp, RCode.Move_object, result[0], rOrigValue[0]);
                    body.Instructions.Add(seqp, RCode.Check_cast, targetType.GetReference(targetPackage), result[0]);
                }
                else if (!targetType.IsPrimitive)
                {
                    body.Instructions.Add(seqp, RCode.Invoke_static, valueType.GetBoxValueOfMethod(), rOrigValue);
                    body.Instructions.Add(seqp, RCode.Move_result_object, result[0]);
                    body.Instructions.Add(seqp, RCode.Check_cast, targetType.GetReference(targetPackage), result[0]);
                }
                else
                {
                    throw new Exception(string.Format("type converstion in attribute {0}=>{1} not yet supported", valueType.FullName, targetType.FullName));
                }
            }
            else if (valueType.IsArray)
            {
                var array       = (CustomAttributeArgument[])value.Value;
                var elementType = valueType.ElementType;

                Register rIndex = body.AllocateRegister(RCategory.Temp, RType.Value);
                body.Instructions.Add(seqp, RCode.Const, array.Length, rIndex);
                body.Instructions.Add(seqp, RCode.New_array, valueType.GetReference(targetPackage), result[0], rIndex);

                // iterate through each value
                for (int i = 0; i < array.Length; i++)
                {
                    Register rLoaded = CreateInitializeValueInstructions(seqp, body, elementType, array[i], compiler, targetPackage)[0];

                    body.Instructions.Add(seqp, RCode.Const, i, rIndex);
                    body.Instructions.Add(seqp, valueType.APut(), rLoaded, result[0], rIndex);
                }
            }
            else if (targetType.IsEnum())
            {
                var enumClass = (targetType.IsEnum()? targetType:valueType).GetReference(targetPackage);

                Register rEnumClass = body.AllocateRegister(RCategory.Temp, RType.Object);
                body.Instructions.Add(seqp, RCode.Const_class, enumClass, rEnumClass);

                long lVal = Convert.ToInt64(value.Value);
                if (lVal <= int.MaxValue && lVal >= int.MinValue)
                {
                    Register regTmp = body.AllocateRegister(RCategory.Temp, RType.Value);
                    body.Instructions.Add(seqp, RCode.Const, (int)lVal, regTmp);
                    var get = compiler.GetDot42InternalType("Enum").Resolve()
                              .Methods.Single(p => p.Name == "Get" && p.Parameters.Count == 2 && !p.Parameters[1].ParameterType.IsWide())
                              .GetReference(targetPackage);
                    body.Instructions.Add(seqp, RCode.Invoke_static, get, rEnumClass, regTmp);
                    body.Instructions.Add(seqp, targetType.MoveResult(), result[0]);
                }
                else
                {
                    var regTmp = body.AllocateWideRegister(RCategory.Temp);
                    body.Instructions.Add(seqp, RCode.Const, (long)lVal, regTmp.Item1);
                    var get = compiler.GetDot42InternalType("Enum").Resolve()
                              .Methods.Single(p => p.Name == "Get" && p.Parameters.Count == 2 && p.Parameters[1].ParameterType.IsWide())
                              .GetReference(targetPackage);
                    body.Instructions.Add(seqp, RCode.Invoke_static, get, rEnumClass, regTmp.Item1);
                    body.Instructions.Add(seqp, targetType.MoveResult(), result[0]);
                }
                body.Instructions.Add(seqp, RCode.Check_cast, targetType.GetReference(targetPackage), result[0]);
            }
            else if (valueType.IsSystemString())
            {
                body.Instructions.Add(seqp, RCode.Const_string, (string)value.Value, result[0]);
            }
            else if (valueType.IsSystemType())
            {
                var type = XBuilder.AsTypeReference(compiler.Module, (TypeReference)value.Value);
                // TODO: this might not work with typeof(void) on ART runtime.
                body.Instructions.Add(seqp, RCode.Const_class, type.GetReference(targetPackage), result[0]);
            }
            else if (!valueType.IsPrimitive)
            {
                // can this happen?
                throw new Exception("invalid value type in attribute: " + targetType.FullName);
            }
            else
            {
                if (targetType.IsSystemObject())
                {
                    // can this happen? or is this always handled above?

                    // boxing required.
                    var rUnboxed = CreateInitializeValueInstructions(seqp, body, valueType, value, compiler, targetPackage);
                    body.Instructions.Add(seqp, RCode.Invoke_static, valueType.GetBoxValueOfMethod(), rUnboxed);
                    body.Instructions.Add(seqp, RCode.Move_result_object, result[0]);
                }
                else if (targetType.IsDouble())
                {
                    body.Instructions.Add(seqp, RCode.Const_wide, Convert.ToDouble(value.Value), result[0]);
                }
                else if (targetType.IsWide() && valueType.IsUInt64())
                {
                    body.Instructions.Add(seqp, RCode.Const_wide, (long)Convert.ToUInt64(value.Value), result[0]);
                }
                else if (targetType.IsWide())
                {
                    body.Instructions.Add(seqp, RCode.Const_wide, Convert.ToInt64(value.Value), result[0]);
                }
                else if (targetType.IsFloat())
                {
                    body.Instructions.Add(seqp, RCode.Const, Convert.ToSingle(value.Value), result[0]);
                }
                else
                {
                    body.Instructions.Add(seqp, RCode.Const, (int)Convert.ToInt64(value.Value), result[0]);
                }
            }

            return(result.ToArray());
        }
Beispiel #19
0
        /// <summary>
        /// If possible, separates local variables into several independent variables.
        /// It should undo any compilers merging.
        /// </summary>
        void ConvertLocalVariables(List <ByteCode> body)
        {
            foreach (var varDef in methodDef.Body.Variables)
            {
                // Find all definitions and uses of this variable
                var defs = body.Where(b => b.Operand == varDef && b.IsVariableDefinition).ToList();
                var uses = body.Where(b => b.Operand == varDef && !b.IsVariableDefinition).ToList();

                List <VariableInfo> newVars;

                // If the variable is pinned, use single variable.
                // If any of the uses is from unknown definition, use single variable
                // If any of the uses is ldloca with a nondeterministic usage pattern, use  single variable
                if (!optimize || varDef.IsPinned || uses.Any(b => b.VariablesBefore[varDef.Index].UnknownDefinition || (b.Code == AstCode.Ldloca && !IsDeterministicLdloca(b))))
                {
                    newVars = new List <VariableInfo>(1)
                    {
                        new VariableInfo()
                        {
                            Variable = new AstILVariable(
                                string.IsNullOrEmpty(varDef.Name) ? "var_" + varDef.Index : varDef.Name,
                                XBuilder.AsTypeReference(module, varDef.IsPinned ? ((PinnedType)varDef.VariableType).ElementType : varDef.VariableType),
                                varDef),
                            Defs = defs,
                            Uses = uses
                        }
                    };
                }
                else
                {
                    // Create a new variable for each definition
                    newVars = defs.Select(def => new VariableInfo()
                    {
                        Variable = new AstILVariable(
                            (string.IsNullOrEmpty(varDef.Name) ? "var_" + varDef.Index : varDef.Name) + "_" + def.Offset.ToString("X2"),
                            XBuilder.AsTypeReference(module, varDef.VariableType),
                            varDef),
                        Defs = new List <ByteCode> {
                            def
                        },
                        Uses = new List <ByteCode>()
                    }).ToList();

                    // VB.NET uses the 'init' to allow use of uninitialized variables.
                    // We do not really care about them too much - if the original variable
                    // was uninitialized at that point it means that no store was called and
                    // thus all our new variables must be uninitialized as well.
                    // So it does not matter which one we load.

                    // TODO: We should add explicit initialization so that C# code compiles.
                    // Remember to handle cases where one path inits the variable, but other does not.

                    // Add loads to the data structure; merge variables if necessary
                    foreach (ByteCode use in uses)
                    {
                        ByteCode[] useDefs = use.VariablesBefore[varDef.Index].Definitions;
                        if (useDefs.Length == 1)
                        {
                            VariableInfo newVar = newVars.Single(v => v.Defs.Contains(useDefs[0]));
                            newVar.Uses.Add(use);
                        }
                        else
                        {
                            List <VariableInfo> mergeVars = newVars.Where(v => v.Defs.Intersect(useDefs).Any()).ToList();
                            VariableInfo        mergedVar = new VariableInfo()
                            {
                                Variable = mergeVars[0].Variable,
                                Defs     = mergeVars.SelectMany(v => v.Defs).ToList(),
                                Uses     = mergeVars.SelectMany(v => v.Uses).ToList()
                            };
                            mergedVar.Uses.Add(use);
                            newVars = newVars.Except(mergeVars).ToList();
                            newVars.Add(mergedVar);
                        }
                    }
                }

                // Set bytecode operands
                foreach (VariableInfo newVar in newVars)
                {
                    foreach (ByteCode def in newVar.Defs)
                    {
                        def.Operand = newVar.Variable;
                    }
                    foreach (ByteCode use in newVar.Uses)
                    {
                        use.Operand = newVar.Variable;
                    }
                }
            }
        }