public void Method_call_load_two_numbers_then_add() { // Arrange var builder = GetBuilder(); var pointer = 0; // Act _ = builder.GetIlProgram(); // Test reproducable property of CodeBuilder var program = builder.GetBinaryProgram(); // Assert // Entry Point Assert.Equal(0, pointer); Assert.Equal(11, BinaryConvert.GetInt32(ref pointer, program)); // two var method_two = pointer; Assert.Equal(5, ++pointer); Assert.Equal(InstructionCode.Ldc_i4, BinaryConvert.GetInstructionCode(ref pointer, program)); Assert.Equal(2, BinaryConvert.GetInt32(ref pointer, program)); Assert.Equal(InstructionCode.Ret, BinaryConvert.GetInstructionCode(ref pointer, program)); // main Assert.Equal(12, ++pointer); Assert.Equal(InstructionCode.Ldc_i4, BinaryConvert.GetInstructionCode(ref pointer, program)); Assert.Equal(1, BinaryConvert.GetInt32(ref pointer, program)); Assert.Equal(InstructionCode.Call, BinaryConvert.GetInstructionCode(ref pointer, program)); Assert.Equal(method_two, BinaryConvert.GetInt32(ref pointer, program)); Assert.Equal(InstructionCode.Add, BinaryConvert.GetInstructionCode(ref pointer, program)); Assert.Equal(InstructionCode.Ret, BinaryConvert.GetInstructionCode(ref pointer, program));
private void GetOpCodeArg(ReadOnlySpan <byte> program, out int value) { if (_pointer >= program.Length) { Throw.MissingInstructionArgument(_pointer); } value = BinaryConvert.GetInt32(ref _pointer, program); }
public void Execute(byte[] program) { _stackFrame.Clear(); var span = program.AsSpan(); var entryPointAddress = BinaryConvert.GetInt32(ref _pointer, program); _pointer = entryPointAddress + InstructionFacts.SizeOfMethodHeader; while (_pointer < span.Length) { var instruction = GetInstruction(span); DispatchInstruction(instruction, span); } }
private IlObject?ReadArguments(InstructionCode instruction, ReadOnlySpan <byte> program, ref int pointer) { var address = new IlAddress(pointer); switch (instruction) { case InstructionCode.Ldstr: { var arg = BinaryConvert.GetString(ref pointer, program); return(new IlObject(address, 0, arg)); } case InstructionCode.Ldloc: case InstructionCode.Stloc: case InstructionCode.Ldc_i4: case InstructionCode.Ldarg: case InstructionCode.Call: { var arg = BinaryConvert.GetInt32(ref pointer, program); return(new IlObject(address, 0, arg)); } case InstructionCode.Br: case InstructionCode.Brfalse: case InstructionCode.Brtrue: { var arg = BinaryConvert.GetInt32(ref pointer, program); _labelTargets.Add(new IlAddress(arg)); return(new IlObject(address, 0, arg)); } case InstructionCode.Ret: case InstructionCode.Add: case InstructionCode.Ceq: case InstructionCode.Pop: case InstructionCode.Nop: { return(null); } default: { Throw.NotSupportedInstruction(pointer, program[pointer - 1]); return(null); } } }
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)); }