All pastes #974136 Raw Edit

Untitled

public text v1 · immutable
·published 2008-04-06 16:14 UTC
rendered paste body
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),
			(0x0001U, "break", null),
			(0x0025U, "dup", null),
			(0x0027U, "jmp", NIL.TokenArg()),
			(0x0028U, "call", NIL.TokenArg()),
			(0x0029U, "calli", NIL.TokenArg()),
			(0x002AU, "ret", null),
			(0x002BU, "br.s", NIL.Int(8)),
			(0x002CU, "brfalse.s", NIL.Int(8)),
			(0x002DU, "brtrue.s", NIL.Int(8)),
			(0x002EU, "beq.s", NIL.Int(8)),
			(0x002FU, "bge.s", NIL.Int(8)),
			(0x0030U, "bgt.s", NIL.Int(8)),
			(0x0031U, "ble.s", NIL.Int(8)),
			(0x0032U, "blt.s", NIL.Int(8)),
			(0x0033U, "bne.s", NIL.Int(8)),
			(0x0034U, "bge.un.s", NIL.Int(8)),
			(0x0035U, "bgt.un.s", NIL.Int(8)),
			(0x0036U, "ble.un.s", NIL.Int(8)),
			(0x0037U, "ble.un.s", NIL.Int(8)),
			(0x0038U, "br", NIL.Int(32)),
			(0x0039U, "brfalse", NIL.Int(32)),
			(0x003AU, "brtrue", NIL.Int(32)),
			(0x003BU, "beq", NIL.Int(32)),
			(0x003CU, "bge", NIL.Int(32)),
			(0x003DU, "bgt", NIL.Int(32)),
			(0x003EU, "ble", NIL.Int(32)),
			(0x003FU, "blt", NIL.Int(32)),
			(0x0040U, "bne", NIL.Int(32)),
			(0x0041U, "bge.un", NIL.Int(32)),
			(0x0042U, "bgt.un", NIL.Int(32)),
			(0x0043U, "ble.un", NIL.Int(32)),
			(0x0044U, "blt.un", NIL.Int(32)),
			(0x0058U, "add", null),
			(0x005BU, "div", null),
			(0x005CU, "div.un", null),
			(0x005FU, "and", null),
			(0x0067U, "conv.i1", null),
			(0x0068U, "conv.i2", null),
			(0x0069U, "conv.i4", null),
			(0x006AU, "conv.i8", null),
			(0x006BU, "conv.r4", null),
			(0x006CU, "conv.r8", null),
			(0x006DU, "conv.u4", null),
			(0x006EU, "conv.u8", null),
			(0x0072U, "ldstr", NIL.TokenArg()),
			(0x0076U, "conv.r.un", null),
			(0x0082U, "conv.ovf.i1.un", null),
			(0x0083U, "conv.ovf.i2.un", null),
			(0x0084U, "conv.ovf.i4.un", null),
			(0x0085U, "conv.ovf.i8.un", null),
			(0x0086U, "conv.ovf.u1.un", null),
			(0x0087U, "conv.ovf.u2.un", null),
			(0x0088U, "conv.ovf.u4.un", null),
			(0x0089U, "conv.ovf.u8.un", null),
			(0x008AU, "conv.ovf.i.un", null),
			(0x008BU, "conv.ovf.u.un", null),
			(0x00B3U, "conv.ovf.i1", null),
			(0x00B4U, "conv.ovf.u1", null),
			(0x00B5U, "conv.ovf.i2", null),
			(0x00B6U, "conv.ovf.u2", null),
			(0x00B7U, "conv.ovf.i4", null),
			(0x00B8U, "conv.ovf.u4", null),
			(0x00B9U, "conv.ovf.i8", null),
			(0x00BAU, "conv.ovf.u8", null),
			(0x00C3U, "ckfinite", null),
			(0x00D1U, "conv.u2", null),
			(0x00D2U, "conv.u1", null),
			(0x00D3U, "conv.i", null),
			(0x00D4U, "conv.ovf.i", null),
			(0x00D5U, "conv.ovf.u", null),
			(0x00D6U, "add.ovf", null),
			(0x00D7U, "add.ovf.un", null),
			(0x00DCU, "endfinally", null),
			(0x00E0U, "conv.u", null),
			(0xFE00U, "arglist", null),
			(0xFE01U, "ceq", null),
			(0xFE02U, "cgt", null),
			(0xFE03U, "cgt.un", null),
			(0xFE04U, "clt", null),
			(0xFE05U, "clt.un", null),
			(0xFE11U, "endfilter", null),
			(0xFE18U, "initblk", null), // Once you go block, you never go back
		];
		
		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);
		}
	}
}