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)); }
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)); }