Beispiel #1
0
        internal static PreparedFunctions Prepare(
            TranslateContext translateContext,
            Func <MethodDefinition, bool> predict)
        {
            IPrepareContext prepareContext = translateContext;

            var allTypes = translateContext.Assembly.Modules
                           .SelectMany(module => module.Types)
                           .Where(type => type.IsValidDefinition())
                           .ToArray();
            var types = allTypes
                        .Where(type => !(type.IsPublic || type.IsNestedPublic || type.IsNestedFamily || type.IsNestedFamilyOrAssembly))
                        .ToArray();

            // Lookup type references.
            foreach (var type in types)
            {
                prepareContext.RegisterType(type);
            }

            // Lookup fields.
            foreach (var field in types.SelectMany(type => type.Fields))
            {
                prepareContext.RegisterType(field.FieldType);
            }

            // Construct result.
            return(new PreparedFunctions(allTypes
                                         .SelectMany(type => type.Methods)
                                         .Where(predict)
                                         .ToDictionary(
                                             method => method,
                                             method => PrepareMethod(prepareContext, method),
                                             CecilHelper.MemberReferenceComparer <MethodDefinition> .Instance)));
        }
Beispiel #2
0
        private static PreparedFunction PrepareMethod(
            IPrepareContext prepareContext,
            MethodDefinition method)
        {
            var methodName = method.GetFullMemberName(MethodNameTypes.Index)
                             .ManglingSymbolName();
            var returnType = method.ReturnType?.Resolve() ?? method.GetSafeVoidType();
            var parameters = method.GetSafeParameters();

            prepareContext.RegisterType(returnType);
            foreach (var parameter in parameters)
            {
                prepareContext.RegisterType(parameter.ParameterType);
            }

            if (method.IsPInvokeImpl)
            {
                var pinvokeInfo = method.PInvokeInfo;
                if (pinvokeInfo == null)
                {
                    throw new InvalidProgramSequenceException(
                              "Missing DllImport attribute at P/Invoke entry: Method={0}",
                              methodName);
                }

                return(PreparePInvokeMethod(
                           prepareContext,
                           methodName,
                           method.Name,
                           returnType,
                           parameters,
                           pinvokeInfo));
            }

            if (method.IsAbstract)
            {
                Debug.Assert(method.Body == null);

                return(PrepareAbstractMethod(
                           prepareContext,
                           methodName,
                           method.Name,
                           returnType,
                           parameters,
                           method.DeclaringType.IsInterface,
                           method.GetMethodOverloadIndex()));
            }

            Debug.Assert(method.Body != null);

            return(PrepareMethod(
                       prepareContext,
                       methodName,
                       method.Name,
                       returnType,
                       parameters,
                       method.Body));
        }
Beispiel #3
0
        internal static PreparedInformations Prepare(
            TranslateContext translateContext,
            Func <ITypeInformation, bool> predictType,
            Func <IMethodInformation, bool> predictMethod)
        {
            IPrepareContext prepareContext = translateContext;

            var allTypes = translateContext.Assembly.Modules.
                           SelectMany(module => module.Types.Concat(module.Types.SelectMany(type => type.NestedTypes))).
                           Where(predictType).
                           Distinct().
                           ToArray();

            // Lookup type references.
            foreach (var type in allTypes)
            {
                // Register used type.
                prepareContext.RegisterType(type, type.CLanguageMemberScope);

                if (type.BaseType != null)
                {
                    prepareContext.RegisterType(type.BaseType, type.CLanguageMemberScope);
                }

                foreach (var interfaceType in type.InterfaceTypes)
                {
                    prepareContext.RegisterType(type.BaseType, type.CLanguageMemberScope);
                }
            }

            // Lookup fields.
            foreach (var field in allTypes.SelectMany(type => type.Fields))
            {
                // Register field type.
                prepareContext.RegisterType(field.FieldType, field.CLanguageMemberScope);

                // Register include file from the native value.
                if (field.NativeValue != null)
                {
                    prepareContext.RegisterImportIncludeFile(field.NativeValue.IncludeFileName);
                }
            }

            // Construct result.
            return(new PreparedInformations(
                       allTypes,
                       (from type in allTypes
                        from method in type.DeclaredMethods
                        where predictMethod(method)
                        let preparedMethod = PrepareMethod(prepareContext, method)
                                             where preparedMethod != null
                                             select preparedMethod).
                       ToDictionary(
                           preparedMethod => preparedMethod.Method,
                           preparedMethod => preparedMethod)));
        }
Beispiel #4
0
        internal static PreparedInformations Prepare(
            TranslateContext translateContext,
            Func <ITypeInformation, bool> predictType,
            Func <IMethodInformation, bool> predictMethod)
        {
            IPrepareContext prepareContext = translateContext;

            var allTypes = translateContext.Assembly.Modules.
                           SelectMany(module => module.Types).
                           Where(predictType).
                           Distinct().
                           ToArray();

            // Lookup type references.
            foreach (var type in allTypes)
            {
                prepareContext.RegisterType(type);
            }

            // Lookup fields.
            foreach (var field in allTypes.SelectMany(type => type.Fields))
            {
                prepareContext.RegisterType(field.FieldType);
            }

            // Construct result.
            return(new PreparedInformations(
                       allTypes,
                       (from type in allTypes
                        from method in type.DeclaredMethods
                        where predictMethod(method)
                        let preparedMethod = PrepareMethod(prepareContext, method)
                                             where preparedMethod != null
                                             select preparedMethod).
                       ToDictionary(
                           preparedMethod => preparedMethod.Method,
                           preparedMethod => preparedMethod)));
        }
Beispiel #5
0
        private static PreparedMethodInformation PrepareMethodBody(
            IPrepareContext prepareContext,
            IMethodInformation method)
        {
            // TODO: move into MethodInformation
            var localVariables = method.LocalVariables.
                                 // If found non named local variable, force named "local[n]__"
                                 GroupBy(variable => variable).
                                 // If contains both named symbol each different scope (in the method by C#'s block), try to named with index number.
                                 SelectMany(g =>
            {
                var list = g.ToArray();
                return((list.Length >= 2) ?
                       list.Select((variable, index) => new LocalVariableInformation(
                                       method,
                                       variable.Index,
                                       string.Format("{0}{1}", g.Key.UnsafeCLanguageSymbolName, index),
                                       variable.TargetType)) :
                       new[] { new LocalVariableInformation(
                                   method,
                                   list[0].Index,
                                   string.Format("{0}", g.Key.UnsafeCLanguageSymbolName),
                                   list[0].TargetType) });
            }).
                                 OrderBy(e => e.Index).
#if DEBUG
                                 Select((e, index) =>
            {
                Debug.Assert(e.Index == index);
                return(e);
            }).
#endif
                                 ToArray();

            foreach (var local in localVariables)
            {
                prepareContext.RegisterType(local.TargetType, method);
            }

            //////////////////////////////////////////////////////////////////////////////
            // Construct decode context

            var decodeContext = new DecodeContext(
                method,
                prepareContext);

            //////////////////////////////////////////////////////////////////////////////
            // Important:
            //   It's core decoding sequence.
            //   The flow analysis can't predict by sequential path.
            //   So, it reorders by IL offset.

            var generators = decodeContext.
                             Traverse(dc => dc.TryDequeueNextPath() ? dc : null, true).
                             SelectMany(dc =>
                                        from ilBody in DecodeAndEnumerateILBodies(dc)
                                        let generator = ilBody.ILConverter.Apply(ilBody.Code.Operand, dc)
                                                        select new PreparedILBody(
                                            ilBody.Label,
                                            generator,
                                            dc.UniqueCodeBlockIndex,
                                            ilBody.Code,
                                            dc.DecodingPathNumber)).
                             OrderBy(ilb => ilb.UniqueCodeBlockIndex).
                             ThenBy(ilb => ilb.Label.Offset).
                             ToDictionary(ilb => ilb.Label.Offset, ilb => ilb.Generator);

            //////////////////////////////////////////////////////////////////////////////

            var stacks = decodeContext.
                         ExtractStacks().
                         ToArray();

            var labelNames = decodeContext.
                             ExtractLabelNames();

            var catchVariables = decodeContext.
                                 ExtractCatchVariables();

            var leaveContinuations = decodeContext.
                                     ExtractLeaveContinuations();

            return(new PreparedMethodInformation(
                       method,
                       stacks,
                       labelNames,
                       catchVariables,
                       leaveContinuations,
                       generators));
        }
Beispiel #6
0
        private static PreparedMethodInformation PrepareMethod(
            IPrepareContext prepareContext,
            IMethodInformation method)
        {
            var returnType = method.ReturnType;
            var parameters = method.Parameters;

            prepareContext.RegisterType(returnType, method.CLanguageMemberScope);
            foreach (var parameter in parameters)
            {
                prepareContext.RegisterType(parameter.TargetType, method.CLanguageMemberScope);
            }

            // Pure abstract method (ignored.)
            if (method.IsVirtual && method.IsAbstract)
            {
                Debug.Assert(!method.HasBody);
                return(null);
            }

            // Delegate constructor (ignored, it will be handled by the AssemblyWriter.)
            if (method.IsConstructor && method.DeclaringType.IsDelegate &&
                (method.Parameters.Length == 3) &&
                method.Parameters[1].TargetType.IsObjectType &&
                method.Parameters[2].TargetType.IsIntPtrType)
            {
                // Debug.Assert(!method.HasBody);  // Depended for the compiler (it has no body for Roslyn)
                return(null);
            }

            // internalcall or DllImport
            if (method.IsExtern)
            {
                Debug.Assert(!method.HasBody);

                if (method.NativeMethod != null)
                {
                    if (string.IsNullOrWhiteSpace(method.NativeMethod.IncludeFileName))
                    {
                        throw new InvalidProgramSequenceException(
                                  "Not given FunctionImport attribute argument. Name={0}",
                                  method.FriendlyName);
                    }

                    // TODO: register library name.
                    prepareContext.RegisterImportIncludeFile(method.NativeMethod.IncludeFileName);
                    if (method.ReturnType.NativeType != null)
                    {
                        prepareContext.RegisterImportIncludeFile(method.ReturnType.NativeType.IncludeFileName);
                    }
                    foreach (var parameter in method.Parameters)
                    {
                        if (parameter.TargetType.NativeType != null)
                        {
                            prepareContext.RegisterImportIncludeFile(parameter.TargetType.NativeType.IncludeFileName);
                        }
                    }
                }
                else if (method.PInvokeInformation != null)
                {
                    if (string.IsNullOrWhiteSpace(method.PInvokeInformation.Module.Name))
                    {
                        throw new InvalidProgramSequenceException(
                                  "Not given DllImport attribute argument. Name={0}",
                                  method.FriendlyName);
                    }

                    // TODO: register library name.
                    //prepareContext.RegisterPrivateIncludeFile(method.PInvokeInformation.Module.Name);
                }

                // Construct dummy information.
                return(new PreparedMethodInformation(
                           method,
                           null,
                           null,
                           null,
                           null,
                           null));
            }

            Debug.Assert(method.HasBody);

            return(PrepareMethodBody(
                       prepareContext,
                       method));
        }
Beispiel #7
0
        private static PreparedFunction PrepareMethod(
            IPrepareContext prepareContext,
            string methodName,
            string rawMethodName,
            TypeReference returnType,
            Parameter[] parameters,
            MethodBody body)
        {
            var localVariables = body.Variables
                                 // If found non named local variable, force named "local[n]__"
                                 .GroupBy(v => body.Method.DebugInformation.TryGetName(v, out var name) ? name : "local")
                                 // If contains both named symbol each different scope (in the method by C#'s block), try to named with index number.
                                 .SelectMany(g =>
            {
                var list = g.ToArray();
                return((list.Length >= 2)
                        ? list.Select((v, index) => new {
                    Name = string.Format("{0}{1}", g.Key, index),
                    Type = v.VariableType,
                    Index = v.Index
                })
                        : new[] { new {
                                      Name = string.Format("{0}", g.Key),
                                      Type = list[0].VariableType,
                                      Index = list[0].Index
                                  } });
            })
                                 .OrderBy(e => e.Index)
                                 .Select((e, index) =>
            {
                Debug.Assert(e.Index == index);
                return(new SymbolInformation(e.Name, e.Type));
            })
                                 .ToArray();

            foreach (var local in localVariables)
            {
                prepareContext.RegisterType(local.TargetType);
            }

            var decodeContext = new DecodeContext(
                body.Method.Module,
                methodName,
                returnType,
                parameters,
                localVariables,
                body.Instructions.ToArray(),
                prepareContext);

            // It gathers sequence point informations.
            // It will use writing the line preprocessor directive.
            var sequencePoints =
                (from sp in body.Method.DebugInformation.SequencePoints
                 where !sp.IsHidden
                 group sp by sp.Offset into g
                 let sps = g.OrderBy(sp => sp.Offset).ToArray()
                           where sps.Length >= 1
                           select new { g.Key, sps })
                .ToDictionary(g => g.Key, g => g.sps);

            // Important:
            //   It's core decoding sequence.
            //   The flow analysis can't predict by sequential path.
            //   So, it reorders by IL offset.
            var preparedILBodies = decodeContext
                                   .Traverse(dc => dc.TryDequeueNextPath() ? dc : null, true)
                                   .SelectMany(dc =>
                                               from ilBody in DecodeAndEnumerateILBodies(dc)
                                               let sps = sequencePoints.UnsafeGetValue(ilBody.Label.Offset, empty)
                                                         let generator = ilBody.ILConverter.Apply(ilBody.Operand, dc)
                                                                         select new PreparedILBody(
                                                   ilBody.Label,
                                                   generator,
                                                   dc.UniqueCodeBlockIndex,
                                                   sps,
                                                   ilBody.ILConverter.OpCode,
                                                   ilBody.Operand,
                                                   dc.DecodingPathNumber))
                                   .OrderBy(ilb => ilb.UniqueCodeBlockIndex)
                                   .ThenBy(ilb => ilb.Label.Offset)
                                   .ToArray();

            var stacks = decodeContext
                         .ExtractStacks()
                         .ToArray();

            var labelNames = decodeContext
                             .ExtractLabelNames();

            return(new PreparedFunction(
                       methodName,
                       rawMethodName,
                       returnType,
                       parameters,
                       preparedILBodies,
                       localVariables,
                       stacks,
                       labelNames,
                       body.Method.IsVirtual ? (int?)body.Method.GetMethodOverloadIndex() : null));
        }