private ImmutableGraph <ProcessedSubroutine> CreateCallGraph(ProcessedType processedType) { var graph = ImmutableGraph <ProcessedSubroutine> .Empty; foreach (var subroutine in processedType.Subroutines) { graph = graph.AddNode(subroutine); } foreach (var subroutine in processedType.Subroutines) { var calls = subroutine.MethodDefinition.Body.Instructions .Where(i => i.OpCode == OpCodes.Call) .Select(i => i.Operand) .OfType <MethodDefinition>() .Where(md => processedType.Subroutines.Any(s => s.MethodDefinition == md)) .Select(md => processedType.Subroutines.Single(s => s.MethodDefinition == md)); foreach (var call in calls) { graph = graph.AddEdge(subroutine, call); } } return(graph); }
public CompiledType(ProcessedType processedType, IImmutableList <CompiledSubroutine> compiledSubroutines) : base(processedType, compiledSubroutines) { if (compiledSubroutines.Count() != processedType.Subroutines.Count()) { throw new FatalCompilationException($"Can not create CompiledType '{processedType.FullName}' with {compiledSubroutines.Count()} CompiledSubroutines because it has {processedType.Subroutines.Count()} ProcessedSubroutines!"); } }
private CompiledType CompileType(ProcessedType processedType) { var compiledSubroutines = new List <CompiledSubroutine>(); var callGraph = CreateCallGraph(processedType); var compilationOrder = callGraph.TopologicalSort(); foreach (var subroutine in compilationOrder) { Console.WriteLine($"Compiling {subroutine.FullName}"); if (subroutine.TryGetFrameworkAttribute <UseProvidedImplementationAttribute>(out var providedImplementation)) { var implementationDefinition = processedType.TypeDefinition.Methods.Single(m => m.Name == providedImplementation.ImplementationName); var implementation = FrameworkAssembly.GetType(processedType.FullName, true).GetTypeInfo().GetMethod(implementationDefinition.Name, BindingFlags.Static | BindingFlags.NonPublic); var compiledBody = (IEnumerable <AssemblyLine>)implementation.Invoke(null, null); compiledSubroutines.Add(new CompiledSubroutine(subroutine, compiledBody)); Console.WriteLine($"Implementation provided by '{implementationDefinition.FullName}':"); foreach (var line in compiledBody) { Console.WriteLine(line); } continue; } foreach (var line in subroutine.MethodDefinition.Body.Instructions) { Console.WriteLine(line); } Console.WriteLine("v Compile v"); IEnumerable <AssemblyLine> body; if (subroutine.TryGetFrameworkAttribute <IgnoreImplementationAttribute>(out _)) { body = Enumerable.Empty <AssemblyLine>(); Console.WriteLine($"Skipping CIL compilation due to {nameof(IgnoreImplementationAttribute)}, assuming an empty subroutine body."); } else { body = CilCompiler.CompileMethod(subroutine.MethodDefinition, Types.ToImmutableDictionary(), FrameworkAssembly); } if (subroutine.IsEntryPoint) { Console.WriteLine("Injecting entry point code."); body = GetEntryPointPrependedCode().Concat(body); } var compiledSubroutine = new CompiledSubroutine(subroutine, body); compiledSubroutines.Add(compiledSubroutine); Types[processedType.FullName] = Types[processedType.FullName].ReplaceSubroutine(subroutine, compiledSubroutine); Console.WriteLine($"{subroutine.FullName}, compilation finished"); } return(new CompiledType(processedType, compiledSubroutines.ToImmutableList())); }
public ProcessedType( TypeDefinition typeDefinition, ProcessedType baseType, IEnumerable <ProcessedField> fields, IImmutableDictionary <ProcessedField, byte> fieldOffsets, IImmutableList <ProcessedSubroutine> subroutines, int?size = null, bool allowedAsLValue = true) { BaseType = baseType; TypeDefinition = typeDefinition; Fields = fields; FieldOffsets = fieldOffsets; Subroutines = subroutines; AllowedAsLValue = allowedAsLValue; ThisSize = size ?? Fields.Sum(pf => pf.FieldType.TotalSize); }
public ProcessedSubroutine( MethodDefinition methodDefinition, ControlFlowGraph controlFlowGraph, bool isEntryPoint, ProcessedType returnType, IList <ProcessedType> parameters, IList <ProcessedType> locals, IEnumerable <Attribute> frameworkAttributes) { MethodDefinition = methodDefinition; ControlFlowGraph = controlFlowGraph; IsEntryPoint = isEntryPoint; ReturnType = returnType; Parameters = parameters; Locals = locals; FrameworkAttributes = frameworkAttributes; }
protected ProcessedType(ProcessedType processedType, IImmutableList <CompiledSubroutine> compiledSubroutines) : this(processedType.TypeDefinition, processedType.BaseType, processedType.Fields, processedType.FieldOffsets, compiledSubroutines.Cast <ProcessedSubroutine>().ToImmutableList(), processedType.ThisSize, processedType.AllowedAsLValue) { }
public ProcessedField(FieldDefinition fieldDefinition, ProcessedType fieldType) { FieldDefinition = fieldDefinition; FieldType = fieldType; }