/// <summary> /// Genereates a jitted method for the given method body /// </summary> /// <param name="name">The name of the method</param> /// <param name="methodBody">The method body</param> /// <param name="isFunction">Indicates if the given method is a function or inline code.</param> /// <returns>A reference to the jited method or null if not jited</returns> public MethodInfo GenerateMethod(string name, Instruction[] methodBody, bool isFunction = false) { var jitedMethod = new DynamicMethod( name, typeof(void), new Type[] { typeof(InternalVMData) }, typeof(PartialJITCompiler)); var generatorData = new MethodGeneratorData(jitedMethod.GetILGenerator(), methodBody.Length); for (int i = 0; i < methodBody.Length; i++) { generatorData.ILGenerator.MarkLabel(generatorData.GetLabel(i)); bool emited = this.EmitInstruction(i, methodBody[i].Data, generatorData); if (!emited) { return(null); } } if (!isFunction) { jitedMethod.GetILGenerator().Emit(OpCodes.Ret); } return(jitedMethod); }
/// <summary> /// Emites the given instruction /// </summary> /// <param name="index">The index of the instruction</param> /// <param name="instructionData">The data of the instruction</param> /// <param name="generatorData">The generator data</param> /// <returns>True if emited else false</returns> public bool EmitInstruction(int index, int instructionData, MethodGeneratorData generatorData) { //Read the opcode OperationCodes opCode = (OperationCodes)(instructionData & 0x3F); //Find the emiter InstructionEmiter emiter = null; if (this.instructionEmiters.TryGetValue(opCode, out emiter)) { switch (emiter.InstructionFormat) { case InstructionFormat.IFormat: this.DecodeAndEmitIFormat(index, instructionData, generatorData, emiter); break; case InstructionFormat.RFormat: this.DecodeAndEmitRFormat(index, instructionData, generatorData, emiter); break; case InstructionFormat.JFormat: this.DecodeAndEmitJFormat(index, instructionData, generatorData, emiter); break; } return(true); } else { return(false); } }
/// <summary> /// Decodes and emites the given J-format instruction /// </summary> /// <param name="index">The index of the instruction</param> /// <param name="instructionData">The instruction data</param> /// <param name="generatorData">The generator data</param> /// <param name="emiter">The emiter</param> private void DecodeAndEmitJFormat(int index, int instructionData, MethodGeneratorData generatorData, InstructionEmiter emiter) { //Decode and execute it JFormatInstruction instruction = JFormatInstruction.Decode(instructionData); emiter.JFormatInstructionEmiter(index, instruction, generatorData); }
/// <summary> /// Decodes and emits the given R-format instruction /// </summary> /// <param name="index">The index of the instruction</param> /// <param name="instructionData">The instruction data</param> /// <param name="generatorData">The method generator data</param> /// <param name="emiter">The executor</param> private void DecodeAndEmitRFormat(int index, int instructionData, MethodGeneratorData generatorData, InstructionEmiter emiter) { //Decode it RFormatInstruction instruction = RFormatInstruction.Decode(instructionData); //Find the R-format emiter RFormatInstructionEmiter opxEmiter = null; //Check if maskers exists if (emiter.RFormatOpxMaskers.Count == 0) { if (emiter.RFormatInstructionEmiters.TryGetValue(instruction.OpxCode, out opxEmiter)) { opxEmiter(index, instruction, generatorData); } } else { //Loop until an executor is found foreach (int currentMask in emiter.RFormatOpxMaskers) { int opxCode = instruction.OpxCode & currentMask; if (emiter.RFormatInstructionEmiters.TryGetValue(opxCode, out opxEmiter)) { opxEmiter(index, instruction, generatorData); break; } } } }
/// <summary> /// Generates the body for the given function /// </summary> /// <param name="funcRef">The function reference</param> /// <param name="funcBody">The function body</param> private void GenerateFunctionBody(DynamicMethod funcRef, Instruction[] funcBody) { var generatorData = new MethodGeneratorData(funcRef.GetILGenerator(), funcBody.Length); var gen = generatorData.ILGenerator; for (int i = 0; i < funcBody.Length; i++) { generatorData.ILGenerator.MarkLabel(generatorData.GetLabel(i)); this.EmitInstruction(i, funcBody[i].Data, generatorData); } }
/// <summary> /// Generates a jitted program for the given instructions /// </summary> /// <param name="name">The name of the program</param> /// <param name="instructions">The instructions</param> /// <param name="functionTable">The function entry points and their sizes</param> /// <returns>A reference to the jitted method or null if not jitted</returns> public MethodInfo GenerateProgram(string name, Instruction[] instructions, IDictionary <uint, int> functionTable) { var jittedProgram = new DynamicMethod( name, typeof(void), new Type[] { typeof(InternalVMData) }, typeof(FullJITCompiler)); var generatorData = new MethodGeneratorData(jittedProgram.GetILGenerator(), instructions.Length); //Generate func ref for all functions foreach (int currentFunc in functionTable.Keys) { //Create the new function var funcRef = new DynamicMethod( "func_at_" + currentFunc, typeof(void), new Type[] { typeof(InternalVMData) }, typeof(FullJITCompiler)); generatorData.FunctionTable.Add(currentFunc, funcRef); } for (int i = 0; i < instructions.Length; i++) { uint currentInstNum = (uint)i; //Check if function if (functionTable.ContainsKey(currentInstNum)) { int funcSize = functionTable[currentInstNum]; //Get the func ref and jit its body var funcRef = (DynamicMethod)generatorData.FunctionTable[i]; Instruction[] funcBody = new Instruction[funcSize]; Array.Copy(instructions, i, funcBody, 0, funcSize); this.GenerateFunctionBody(funcRef, funcBody); i += funcSize - 1; } else { generatorData.ILGenerator.MarkLabel(generatorData.GetLabel(i)); this.EmitInstruction(i, instructions[i].Data, generatorData); } } jittedProgram.GetILGenerator().Emit(OpCodes.Ret); return(jittedProgram); }