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