using System; using System.Collections; using System.Reflection; namespace NPhilosopher.NILC { public variant NAssembly { | Assembly { AssemblyName : string; Types : list [NAssembly]; } | Type { TypeName : string; Members : list [NAssembly]; } | Method { MethodName : string; Arguments : list [NAssembly]; ReturnType : System.Type; IL : NIL; } | Argument { ArgName : string; ArgType : System.Type; } | Other } public variant NIL { | Block { Pos : int; } | Inst { Pos : int; Prefix : NIL; Opcode : uint; Mnem : string; Argument : NIL; } | TokenArg | IntArg { Size : int; } | UIntArg { USize : int; } | Int { Value : int; } | UInt { UValue : uint; } | Object { OValue : object; } } public module Reflector { public Prefixes : list [uint * string * NIL] = [ (0xFE16U, "constrained.", NIL.TokenArg()), (0xFE19U, "no.", NIL.UIntArg(8)), (0xFE1EU, "readonly.", null), (0xFE14U, "tail.", null), (0xFE12U, "unaligned.", NIL.UIntArg(8)), (0xFE13U, "volatile.", null) ]; public Opcodes : list [uint * string * NIL] = [ (0x0000U, "nop", null), (0x0028U, "call", NIL.TokenArg()), (0x002AU, "ret", null), (0x0072U, "ldstr", NIL.TokenArg()), ]; public Reflect(file : string) : NAssembly { mutable types : list [NAssembly] = []; def assembly = Assembly.ReflectionOnlyLoadFrom(file); foreach(t in assembly.GetTypes()) types = NAssembly.Type(t.FullName, ReflectMembers(t)) :: types; NAssembly.Assembly(assembly.FullName, types); } public ReflectMembers(t : Type) : list[NAssembly] { mutable members : list [NAssembly] = []; def flags = ( BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic ); foreach(member in t.GetMembers(flags)) { def mem = match(member.MemberType) { | MemberTypes.Method => def method = member :> MethodInfo; System.Console.WriteLine("{0}", member.Name); NAssembly.Method( MethodName=member.Name, Arguments=ReflectMethodArguments(method), ReturnType=method.ReturnType, IL={ def body = method.GetMethodBody(); if(body == null) null; else ReflectMethodIL(body, t.Module); } ); | _ => NAssembly.Other(); }; members = mem :: members; } members; } public ReflectMethodArguments(m : MethodInfo) : list [NAssembly] { mutable args : list [NAssembly] = []; foreach(param in m.GetParameters()) args = NAssembly.Argument(param.Name, param.ParameterType) :: args; args; } public ReflectMethodIL(body : MethodBody, mod : Module) : NIL.Block { def blocks = Hashtable(); def il = body.GetILAsByteArray(); mutable next : int; mutable start : int; def U32() { (il[next] :> uint | (il[next + 1] :> uint << 8) | (il[next + 2] :> uint << 16) | (il[next + 3] :> uint << 24)); } def ParseArgument(arg) : NIL { | NIL.TokenArg => def token = U32() :> int; next += 4; match(token >> 24) { | 0x0A => NIL.Object(mod.ResolveMember(token)); | 0x70 => NIL.Object(mod.ResolveString(token)); | x => System.Console.WriteLine("Table: {0:X}", x); NIL.Object(null); } | NIL.IntArg(size) => def temp = match(ParseArgument(NIL.UIntArg(size))) { | NIL.UInt(val) => val :> int; | _ => 0; }; def signmask = 1U << (size - 1); NIL.Int({ if((temp :> uint & signmask) != 0) match(size) { | 8 => -(~temp & 0xFF) - 1; | 16 => -(~temp & 0xFFFF) - 1; | 24 => -(~temp) - 1; | _ => temp; } else temp; }); | NIL.UIntArg(size) => def temp = NIL.UInt( match(size) { | 8 => il[next] :> uint; | 16 => (il[next] :> uint | (il[next + 1] :> uint << 8)); | 32 => U32(); | _ => 0U; } ); next += size >> 3; temp; | _ => null; } def ParseOpcd(opcd, prefix, opcodes) { match(opcodes) { | [] => null; | (instopcd, mnem, arg) :: rest => if(opcd == instopcd) { next++; unless(opcd & 0xFF00U == 0) next++; NIL.Inst( Pos=start, Prefix=prefix, Opcode=opcd, Mnem=mnem, Argument=ParseArgument(arg) ); } else ParseOpcd(opcd, prefix, rest); } } def Parse() { def prefix = ParseOpcd( match(il[next] :> uint) { | 0xFEU => (0xFE00U | (il[next+1] :> uint)); | x => x; }, null, Prefixes ); def opcd = match(il[next] :> uint) { | 0xFEU => (0xFE00U | (il[next+1] :> uint)); | x => x; }; def inst = ParseOpcd( opcd, prefix, Opcodes ); match(inst) { | null => System.Console.WriteLine("{0}: {1:X}", next, opcd); throw Exception(); | NIL.Inst(_, _, opcd, mnem, arg) => when(opcd == 0x002AU) // ret next = -1; System.Console.WriteLine( "{0} {1}", mnem, match(arg) { | Object(obj) => obj; | x => x; } ); } inst; } def Process(pos) { if(blocks.ContainsKey(pos)) blocks[pos] :> NIL.Block; else { mutable inst : NIL.Inst; next = pos; start = pos; while(next != -1) { inst = Parse(); } def block = NIL.Block(pos); blocks[pos] = block; block; } } Process(0); } } }