private IReadOnlyList <IlMethod> LinkMethods(int startAddress, CallTree callTree) { var result = new List <IlMethod>(); var methods = callTree.Flatten().Select(m => m.Method).OrderBy(m => m.Order).ToList(); GetMethodAddressLookup(_methodTableBuilder, startAddress, methods); foreach (var method in methods) { var address = _methodTableBuilder.Targets[method.Name]; var methdoBodyAddress = address.Value + InstructionFacts.SizeOfMethodHeader; var ilObjects = LinkNodes(methdoBodyAddress, method.Nodes); var ilMethod = new IlMethod(address, method.Args, ilObjects); if (method.IsEntryPoint) { _entryPoint = ilMethod.Address; } result.Add(ilMethod); } return(result);
private IlProgram GetProgram(ReadOnlySpan <byte> program) { var pointer = 0; var ilMethods = new List <IlMethod>(); var methodNames = new Dictionary <IlAddress, string>(); var entryPointValue = BinaryConvert.GetInt32(ref pointer, program); var callTargets = new Stack <int>(); callTargets.Push(entryPointValue); var visitedTargets = new HashSet <int> { entryPointValue }; while (callTargets.Count > 0) { var ilObjects = new List <IlObject>(); pointer = callTargets.Pop(); var argCount = program[pointer]; var method = new IlMethod(pointer, argCount, ilObjects); ilMethods.Add(method); methodNames.Add(method.Address, $"m{ilMethods.Count}"); pointer += InstructionFacts.SizeOfMethodHeader; while (pointer < program.Length) { var instructionAddress = pointer; var instruction = GetInstruction(program, ref pointer); ilObjects.Add(new IlObject(instructionAddress, 0, instruction)); var arg = ReadArguments(instruction, program, ref pointer); if (instruction == InstructionCode.Ret) { break; } if (arg is null) { continue; } ilObjects.Add(arg); if (instruction != InstructionCode.Call) { continue; } var callTarget = (int)arg.Obj; if (!visitedTargets.Add(callTarget)) { continue; } callTargets.Push(callTarget); } } return(new IlProgram(entryPointValue, ilMethods.OrderBy(m => m.Address).ToArray(), methodNames, _labelTargets)); }