public string Create(OpValue[] prog) { string ePath = Path.GetTempFileName(); ProcessStartInfo info = new ProcessStartInfo("gcc", "-O2 -x c -o " + ePath + " -") { RedirectStandardInput = true, UseShellExecute = false, CreateNoWindow = true }; using (var process = Process.Start(info)) { process.StandardInput.WriteLine(Pre); foreach (OpValue op in prog) { this.Append(process.StandardInput, op); } process.StandardInput.WriteLine(Post); process.StandardInput.Flush(); process.StandardInput.Close(); process.WaitForExit(); } return ePath; }
private static void RunCompiled(OpValue[] prog) { Stopwatch sw = Stopwatch.StartNew(); string exe = new NativeCreator().Create(prog); long compileTimeTicks = sw.ElapsedTicks; using (var process = Process.Start(exe)) { process.WaitForExit(); sw.Stop(); } Console.WriteLine("Compiled to " + exe); double freq = (double)Stopwatch.Frequency; Console.WriteLine("Time to compile and run: {0:N5} seconds", sw.ElapsedTicks / freq); Console.WriteLine("Time to compile: {0:N5} seconds", compileTimeTicks / freq); Console.WriteLine("Time to run: {0:N5} seconds", (sw.ElapsedTicks - compileTimeTicks) / freq); }
private void Append(StreamWriter sw, OpValue op) { switch (op.OpCode) { case OpCode.ShiftRight: sw.WriteLine("ptr += " + op.Data + ";"); break; case OpCode.ShiftLeft: sw.WriteLine("ptr -= " + op.Data + ";"); break; case OpCode.Increment: sw.WriteLine("*ptr += " + op.Data + ";"); break; case OpCode.Decrement: sw.WriteLine("*ptr -= " + op.Data + ";"); break; case OpCode.CondLeft: sw.WriteLine("while (*ptr) {"); break; case OpCode.CondRight: sw.WriteLine("}"); break; case OpCode.Output: sw.WriteLine("putchar(*ptr);"); break; case OpCode.Input: sw.WriteLine("*ptr = getchar();"); break; case OpCode.Assign: sw.WriteLine("*ptr = " + op.Data + ";"); break; } }
private static void Emit(ILProcessor ip, ModuleDefinition mod, VariableDefinition arrayVar, VariableDefinition indexVar, Dictionary<int, Instruction> braces, OpValue[] ops, int i) { OpValue op = ops[i]; switch (op.OpCode) { case BFOpCode.Increment: ip.Emit(OpCodes.Ldloc, arrayVar); ip.Emit(OpCodes.Ldloc, indexVar); ip.Emit(OpCodes.Ldloc, arrayVar); ip.Emit(OpCodes.Ldloc, indexVar); ip.Emit(OpCodes.Ldelem_I4); ip.Emit(OpCodes.Ldc_I4, op.Data); ip.Emit(OpCodes.Add); ip.Emit(OpCodes.Stelem_I4); break; case BFOpCode.Decrement: ip.Emit(OpCodes.Ldloc, arrayVar); ip.Emit(OpCodes.Ldloc, indexVar); ip.Emit(OpCodes.Ldloc, arrayVar); ip.Emit(OpCodes.Ldloc, indexVar); ip.Emit(OpCodes.Ldelem_I4); ip.Emit(OpCodes.Ldc_I4, op.Data); ip.Emit(OpCodes.Sub); ip.Emit(OpCodes.Stelem_I4); break; case BFOpCode.ShiftRight: ip.Emit(OpCodes.Ldloc, indexVar); ip.Emit(OpCodes.Ldc_I4, op.Data); ip.Emit(OpCodes.Add); ip.Emit(OpCodes.Stloc, indexVar); break; case BFOpCode.ShiftLeft: ip.Emit(OpCodes.Ldloc, indexVar); ip.Emit(OpCodes.Ldc_I4, op.Data); ip.Emit(OpCodes.Sub); ip.Emit(OpCodes.Stloc, indexVar); break; case BFOpCode.Output: ip.Emit(OpCodes.Ldloc, arrayVar); ip.Emit(OpCodes.Ldloc, indexVar); ip.Emit(OpCodes.Ldelem_I4); ip.Emit(OpCodes.Conv_I1); ip.Emit(OpCodes.Call, mod.Import(typeof(Console).GetMethod("Write", new[] { typeof(char) }))); break; case BFOpCode.Input: ip.Emit(OpCodes.Call, mod.Import(typeof(Console).GetMethod("Read", new Type[0]))); ip.Emit(OpCodes.Ldloc, arrayVar); ip.Emit(OpCodes.Ldloc, indexVar); ip.Emit(OpCodes.Ldelem_I4); ip.Emit(OpCodes.Conv_I1); break; case BFOpCode.CondLeft: var leftB = ip.Create(OpCodes.Ldloc, arrayVar); var rightB = ip.Create(OpCodes.Nop); ip.Append(leftB); braces[i] = leftB; braces[op.Data] = rightB; ip.Emit(OpCodes.Ldloc, indexVar); ip.Emit(OpCodes.Ldelem_I4); ip.Emit(OpCodes.Brfalse, rightB); ip.Emit(OpCodes.Nop); break; case BFOpCode.CondRight: ip.Emit(OpCodes.Br, braces[op.Data]); ip.Append(braces[i]); break; case BFOpCode.Assign: ip.Emit(OpCodes.Ldloc, arrayVar); ip.Emit(OpCodes.Ldloc, indexVar); ip.Emit(OpCodes.Ldc_I4, op.Data); ip.Emit(OpCodes.Stelem_I4); break; } }
public MethodInfo Create(OpValue[] prog) { const string OutNamespace = "BF"; const string OutTypeName = "CompiledProgram"; const string OutMethodName = "Main"; var name = new AssemblyNameDefinition(OutNamespace, new Version(1, 0, 0, 0)); var asm = AssemblyDefinition.CreateAssembly(name, OutNamespace + ".dll", ModuleKind.Dll); asm.MainModule.Import(typeof(int)); var voidret = asm.MainModule.Import(typeof(void)); var method = new MethodDefinition(OutMethodName, MethodAttributes.Static | MethodAttributes.Public, voidret); var arrayVar = new VariableDefinition("array", asm.MainModule.Import(typeof(int[]))); var indexVar = new VariableDefinition("idx", asm.MainModule.Import(typeof(int))); method.Body.Variables.Add(arrayVar); method.Body.Variables.Add(indexVar); var ip = method.Body.GetILProcessor(); ip.Emit(OpCodes.Ldc_I4_0); ip.Emit(OpCodes.Stloc, indexVar); ip.Emit(OpCodes.Ldc_I4, 300000); ip.Emit(OpCodes.Newarr, asm.MainModule.Import(typeof(int))); ip.Emit(OpCodes.Stloc, arrayVar); Dictionary<int, Instruction> braces = new Dictionary<int, Instruction>(); for (int i = 0; i < prog.Length; i++) { Emit(ip, asm.MainModule, arrayVar, indexVar, braces, prog, i); } ip.Emit(OpCodes.Ret); var type = new TypeDefinition(OutNamespace, OutTypeName, TypeAttributes.AutoClass | TypeAttributes.Public | TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit, asm.MainModule.Import(typeof(object))); asm.MainModule.Types.Add(type); type.Methods.Add(method); asm.EntryPoint = method; byte[] rawAsm; using (var ms = new MemoryStream()) { asm.Write(ms); rawAsm = ms.ToArray(); } var reflected = Assembly.Load(rawAsm); return reflected.GetType(OutNamespace + "." + OutTypeName) .GetMethod(OutMethodName); }
/// <summary> /// Fails when called. /// </summary> /// <param name="opData">Stack object (won't be used)</param> /// <param name="error">Error message (contains name of the operation that caused the failure)</param> /// <returns>False (always failing)</returns> public sealed override bool Run(IOpData opData, out string error) { error = $"Can not run an OP_{OpValue.ToString()} operation."; return(false); }
private static void RunInterpreter(OpValue[] prog) { Stopwatch sw = Stopwatch.StartNew(); int[] b = new int[30000]; int next = 0; int idx = 0; while (next < prog.Length) { OpValue op = prog[next]; switch (op.OpCode) { case OpCode.ShiftRight: idx += op.Data; next++; break; case OpCode.ShiftLeft: idx -= op.Data; next++; break; case OpCode.Increment: b[idx] += op.Data; next++; break; case OpCode.Decrement: b[idx] -= op.Data; next++; break; case OpCode.Output: char oCh = (char)b[idx]; Console.Write(oCh); next++; break; case OpCode.Input: b[idx] = (char)Console.Read(); next++; break; case OpCode.CondLeft: if (b[idx] == 0) { next = op.Data; } next++; break; case OpCode.CondRight: next = op.Data; break; case OpCode.Assign: b[idx] = op.Data; next++; break; default: next++; break; } } sw.Stop(); Console.WriteLine("Time to interpret: {0:N5} seconds", sw.ElapsedTicks / (double)Stopwatch.Frequency); }
private static void RunJIT(OpValue[] prog) { Stopwatch sw = Stopwatch.StartNew(); System.Reflection.MethodInfo compiled = new AssemblyCreator().Create(prog); long compileTimeTicks = sw.ElapsedTicks; compiled.Invoke(null, null); sw.Stop(); double freq = (double)Stopwatch.Frequency; Console.WriteLine("Time to JIT and run: {0:N5} seconds", sw.ElapsedTicks / freq); Console.WriteLine("Time to JIT: {0:N5} seconds", compileTimeTicks / freq); Console.WriteLine("Time to run: {0:N5} seconds", (sw.ElapsedTicks - compileTimeTicks) / freq); }