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