using System;
using System.Collections;
using System.IO;
using System.Text;
using Girl.PEAnalyzer;

class IL2Asm16
{
	static int Main(string[] args)
	{
		IL2Asm16 il2asm = new IL2Asm16();
		string target = null, asm = null;
		foreach (string arg in args)
		{
			string u = arg.ToUpper();
			if (u.StartsWith("/MAIN:"))
			{
				il2asm.jumpTo = arg.Substring(6, arg.Length - 6);
			}
			else if (u.StartsWith("/OPT:"))
			{
				try
				{
					il2asm.optimize = int.Parse(arg.Substring(5, arg.Length - 5));
				}
				catch {}
			}
			else if (u.StartsWith("/OUT:"))
			{
				asm = arg.Substring(5, arg.Length - 5); 
			}
			else if (u == "/NOMAIN")
			{
				il2asm.noMain = true;
			}
			else if (u.StartsWith("/PRE:"))
			{
				il2asm.pre = arg.Substring(5, arg.Length - 5);
			}
			else if (u.StartsWith("/POST:"))
			{
				il2asm.post = arg.Substring(6, arg.Length - 6);
			}
			else
			{
				target = arg;
			}
		}
		if (target == null)
		{
			Console.WriteLine("usage: IL2Asm16 [/MAIN:xxx] [/NOMAIN] [/OPT:1/2] [PRE:xxx.asm] [POST:xxx.asm] [/OUT:xxx.asm] assembly.exe");
			return 1;
		}
		if (!il2asm.ReadPE(target)) return 1;
		if (asm == null) asm = Util.SwapExt(target, ".asm");
		if (!il2asm.WriteAsm(asm)) return 1;
		return 0;
	}
	
	private string jumpTo = "ILMain";
	private byte[] data;
	private PEData pedata;
	private MethodData entryPoint;
	private Hashtable hashUS;
	private ArrayList listUS;
	private int number, optimize = 0;
	private ILCode lastRet = null;
	private bool noMain = false;
	private string pre = null, post = null;
	
	public bool ReadPE(string fn)
	{
		try
		{
			FileStream fs = new FileStream(fn, FileMode.Open);
			int len = (int)fs.Length;
			this.data = new byte[len];
			fs.Read(this.data, 0, len);
			fs.Close();
		}
		catch
		{
			System.Console.WriteLine("Can not open: {0}", fn);
			return false;
		}
		this.pedata = new PEData(this.data);
		if (this.pedata.cli == null)
		{
			System.Console.WriteLine("Not CIL assembly: {0}", fn);
			return false;
		}
		return true;
	}
	
	private void InsertFile(StreamWriter sw, string fn)
	{
		sw.WriteLine();
		sw.WriteLine("; --- BEGIN: {0}", fn);
		sw.WriteLine();
		StreamReader sr = new StreamReader(fn);
		sw.Write(sr.ReadToEnd());
		sr.Close();
		sw.WriteLine();
		sw.WriteLine("; --- END");
	}
	
	public bool WriteAsm(string asm)
	{
		MethodDefTable m = this.pedata.idxm.GetTable(this.pedata.cli.EntryPointToken) as MethodDefTable;
		if (m == null)
		{
			System.Console.WriteLine("Can not find entry point!");
			return false;
		}
		this.entryPoint = m.Tag as MethodData;
		System.Console.WriteLine("Entry Point: {0}", this.entryPoint.FullName);
		
		bool ok = true;
		FileStream fs = new FileStream(asm, FileMode.Create);
		StreamWriter sw = new StreamWriter(fs);
		
		this.hashUS = new Hashtable();
		this.listUS = new ArrayList();
		if (this.pedata.usrstr != null)
		{
			int ad = this.pedata.usrstr.GetDataOffset(), ptr = 1;
			while (this.data[ad + ptr] != 0 && ptr < this.pedata.usrstr.Size)
			{
				DoubleInt dataSize = this.pedata.usrstr.GetDataSize(ad + ptr);
				byte[] bytes = Girl.PEAnalyzer.Util.GetBytes(this.data, ad + ptr + dataSize.A, dataSize.B);
				this.hashUS[ptr] = Encoding.Unicode.GetString(bytes, 0, dataSize.B - 1);
				ptr += dataSize.A + dataSize.B;
			}
		}
		
		this.number = 0;
		sw.WriteLine("; This file was automatically generated by IL2Asm16.");
		if (this.pre != null) this.InsertFile(sw, this.pre);
		sw.WriteLine();
		sw.WriteLine("[bits 16]");
		if (!this.noMain)
		{
			sw.WriteLine("jmp {0}", this.jumpTo);
			sw.WriteLine();
			
			sw.WriteLine("ILMain:");
			foreach (object obj in this.pedata.idxm.Tables[(int)MetadataTables.TypeDef])
			{
				TypeDefTable t = obj as TypeDefTable;
				foreach (object obj2 in t.Children[(int)Children.DefMethod])
				{
					MethodDefTable mdt = obj2 as MethodDefTable;
					MethodData md = mdt.Tag as MethodData;
					if (!md.Name.EndsWith("::.cctor")) continue;
					
					sw.WriteLine("\tcall\t{0}", Util.MangleFunction(md));
				}
			}
			sw.WriteLine("\tcall\t{0}", Util.MangleFunction(this.entryPoint));
			sw.WriteLine("\tret");
		}
		
		foreach (object obj in this.pedata.idxm.Tables[(int)MetadataTables.TypeDef])
		{
			TypeDefTable t = obj as TypeDefTable;
			sw.WriteLine();
			if (!this.WriteAsm(sw, t)) ok = false;
		}
		
		if (this.listUS.Count > 0)
		{
			sw.WriteLine();
			this.listUS.Sort();
			foreach (object obj in this.listUS)
			{
				int ptr = (int)obj;
				string str = this.hashUS[ptr] as string;
				bool instr = false;
				StringBuilder sb = new StringBuilder();
				foreach (char ch in str)
				{
					if (ch < ' ')
					{
						if (instr)
						{
							sb.Append('\"');
							instr = false;
						}
						if (sb.Length > 0) sb.Append(", ");
						sb.AppendFormat("0x{0:x2}", (int)ch);
					}
					else
					{
						if (!instr)
						{
							sb.Append('\"');
							instr = true;
						}
						sb.Append(ch);
					}
				}
				if (instr) sb.Append('\"');
				sw.WriteLine("US_{0:X8} db {1}, {2}, 0x00", ptr, str.Length, sb);
			}
		}
		
		if (this.post != null) this.InsertFile(sw, this.post);
		sw.Close();
		fs.Close();
		return ok;
	}
	
	public bool WriteAsm(StreamWriter sw, TypeDefTable t)
	{
		bool ok = true;
		sw.WriteLine("; class {0}", this.pedata.idxm.GetName(t));
		bool first = true;
		foreach (object obj in t.Children[(int)Children.DefField])
		{
			FieldTable f = obj as FieldTable;
			if ((f.Flags & (int)FieldAttributes.Static) == 0
				|| (f.Flags & (int)FieldAttributes.Literal) != 0)
			{
				continue;
			}
			
			if (first)
			{
				sw.WriteLine();
				first = false;
			}
			sw.WriteLine("{0} dw 0", MangleField(f));
		}
		foreach (object obj in t.Children[(int)Children.DefMethod])
		{
			MethodDefTable m = obj as MethodDefTable;
			MethodData md = m.Tag as MethodData;
			if (md.HasThis) continue; // static only
			
			sw.WriteLine();
			if (!this.WriteAsm(sw, md)) ok = false;
		}
		return ok;
	}
	
	public bool WriteAsm(StreamWriter sw, MethodData md)
	{
		bool ok = true;
		string name = md.FullName;
		sw.WriteLine("; {0}", name);
		sw.WriteLine("{0}:", Util.MangleFunction(md));
		ArrayList list = new ArrayList();
		if (md.LocalVars != null || md.ParamCount > 0)
		{
			list.Add(new X86Code("push", "bp"));
			list.Add(new X86Code("mov", "bp", "sp"));
			if (md.LocalVars != null) list.Add(new X86Code("sub", "sp", (md.LocalVars.Count * 2).ToString()));
		}
		foreach (object obj in ConvertNative(md))
		{
			X86Codes codes = obj as X86Codes;
			if (codes == null)
			{
				ILCode il = obj as ILCode;
				codes = ConvertIL(md, il);
				if (codes == null)
				{
					ok = false;
					Console.WriteLine("ERROR PE_{0:X8}: {1} in {2}", il.Address, il.OpCode, md.FullName);
					continue;
				}
			}
			codes.Output(list);
		}
		switch (this.optimize)
		{
			case 1:
				X86Code.Optimize(list);
				break;
			case 2:
				this.Optimize(list, md);
				break;
		}
		foreach (object obj in list)
		{
			X86Code x = obj as X86Code;
			x.Write(sw);
		}
		return ok;
	}
	
	public void Optimize(ArrayList list, MethodData md)
	{
		X86Code.Optimize(list);
		
		bool bx = true;
		Hashtable locals = new Hashtable();
		int max = 0;
		string target = null;
		for (int i = 0; i < list.Count; i++)
		{
			X86Code x = list[i] as X86Code;
			if (x == null || x.ignore) continue;
			
			if (x.Mnemonic == "int" || x.Operand1 == "bx") bx = false;
			int p1a = x.Operand1.IndexOf("[ss:bp-"), p1b = x.Operand1.LastIndexOf(']');
			if (0 <= p1a && p1a < p1b)
			{
				string var = x.Operand1.Substring(p1a + 1, p1b - p1a - 1);
				int v = !locals.Contains(var) ? 1 : ((int)locals[var]) + 1;
				locals[var] = v;
				if (max < v)
				{
					max = v;
					target = var;
				}
			}
			int p2a = x.Operand2.IndexOf("[ss:bp-"), p2b = x.Operand2.LastIndexOf(']');
			if (0 <= p2a && p2a < p2b)
			{
				string var = x.Operand2.Substring(p2a + 1, p2b - p2a - 1);
				int v = !locals.Contains(var) ? 1 : ((int)locals[var]) + 1;
				locals[var] = v;
				if (max < v)
				{
					max = v;
					target = var;
				}
			}
		}
		if (bx && target != null)
		{
			for (int i = 0; i < list.Count; i++)
			{
				X86Code x = list[i] as X86Code;
				if (x == null || x.ignore) continue;
				
				string op1 = x.Operand1, op2 = x.Operand2;
				int p1 = op1.IndexOf(target), p2 = op2.IndexOf(target);
				if (p1 >= 0) op1 = "bx";
				if (p2 >= 0) op2 = "bx";
				if (p1 < 0 && p2 < 0) continue;
				
				x.Ignore();
				X86Code xx = new X86Code(x.Mnemonic, op1, op2);
				xx.Notes = "[optimize] add";
				list.Insert(i + 1, xx);
			}
			if (md.LocalVars != null && md.LocalVars.Count == 1 && target.StartsWith("ss:bp-"))
			{
				for (int i = 0; i < list.Count; i++)
				{
					X86Code x = list[i] as X86Code;
					if (x == null || x.ignore) continue;
					
					if (x.Mnemonic == "sub" && x.Operand1 == "sp")
					{
						x.Ignore();
						break;
					}
				}
				for (int i = list.Count - 1; i >= 0; i--)
				{
					X86Code x = list[i] as X86Code;
					if (x == null || x.ignore) continue;
					
					if (x.Mnemonic == "mov" && x.Operand1 == "sp")
					{
						x.Ignore();
						break;
					}
				}
			}
		}
		X86Code.Optimize(list);
		if (md.LocalVars != null || md.ParamCount > 0 || !bx)
		{
			X86Code xb1 = new X86Code("push", "bx"), xb2 = new X86Code("pop", "bx");
			xb1.Notes = xb2.Notes = "[optimize] add";
			list.Insert(0, xb1);
			for (int i = 0; i < list.Count; i++)
			{
				X86Code x = list[i] as X86Code;
				if (x == null || x.ignore) continue;
				
				if (x.Mnemonic == "ret")
				{
					list.Insert(i, xb2);
					i++;
				}
			}
		}
	}
	
	public X86Codes ConvertIL(MethodData md, ILCode il)
	{
		string mne = il.OpCode.Name;
		if (mne == null) return null;
		
		X86Codes ret = new X86Codes();
		ret.Address = il.Address;
		ret.IsBrTarget = il.IsBrTarget;
		if (il.Operand is byte)
		{
			ret.Comment = string.Format("{0} {1:X2}", mne, il.Operand);
		}
		else if (il.Operand is short)
		{
			ret.Comment = string.Format("{0} {1:X4}", mne, il.Operand);
		}
		else if (il.Operand is int)
		{
			ret.Comment = string.Format("{0} {1:X8}", mne, il.Operand);
		}
		else
		{
			ret.Comment = mne;
		}
		
		int mne_last = mne.Length < 1 ? 0 : (int)(mne[mne.Length - 1] - '0');
		int nOp = Util.GetOperandValue(il);
		switch (mne)
		{
			case "ldc.i4":
			case "ldc.i4.s":
			case "ldc.i4.0":
			case "ldc.i4.1":
			case "ldc.i4.2":
			case "ldc.i4.3":
			case "ldc.i4.4":
			case "ldc.i4.5":
			case "ldc.i4.6":
			case "ldc.i4.7":
			case "ldc.i4.8":
				ret.Codes.Add(new X86Code("mov", "ax", nOp.ToString()));
				ret.Codes.Add(new X86Code("push", "ax"));
				break;
			case "ldloc":
			case "ldloc.s":
			case "ldloc.0":
			case "ldloc.1":
			case "ldloc.2":
			case "ldloc.3":
				ret.Codes.Add(new X86Code("push", string.Format("word [ss:bp-{0}]", (nOp + 1) * 2)));
				break;
			case "ldloca":
			case "ldloca.s":
				ret.Codes.Add(new X86Code("mov", "ax", "bp"));
				ret.Codes.Add(new X86Code("sub", string.Format("ax, {0}", (nOp + 1) * 2)));
				ret.Codes.Add(new X86Code("push", "ax"));
				break;
			case "stloc":
			case "stloc.s":
			case "stloc.0":
			case "stloc.1":
			case "stloc.2":
			case "stloc.3":
				ret.Codes.Add(new X86Code("pop", string.Format("word [ss:bp-{0}]", (nOp + 1) * 2)));
				break;
			case "ldarg":
			case "ldarg.s":
			case "ldarg.0":
			case "ldarg.1":
			case "ldarg.2":
			case "ldarg.3":
				ret.Codes.Add(new X86Code("push", string.Format("word [ss:bp+{0}]", Util.GetArgPos(md, nOp, this.optimize))));
				break;
			case "starg":
			case "starg.s":
				ret.Codes.Add(new X86Code("pop", string.Format("word [ss:bp+{0}]", Util.GetArgPos(md, nOp, this.optimize))));
				break;
			case "ldstr":
			{
				int us = ((int)il.Operand) & 0xffffff;
				if (!this.listUS.Contains(us)) this.listUS.Add(us);
				ret.Codes.Add(new X86Code("mov", "ax", string.Format("US_{0:X8}", us)));
				ret.Codes.Add(new X86Code("push", "ax"));
				break;
			}
			case "ldsfld":
			{
				TableBase tb = this.pedata.idxm.GetTable((int)il.Operand);
				ret.Codes.Add(new X86Code("push", string.Format("word [cs:{0}]", MangleField(tb as FieldTable))));
				break;
			}
			case "stsfld":
			{
				TableBase tb = this.pedata.idxm.GetTable((int)il.Operand);
				ret.Codes.Add(new X86Code("pop", string.Format("word [cs:{0}]", MangleField(tb as FieldTable))));
				break;
			}
			case "pop":
				ret.Codes.Add(new X86Code("pop", "ax"));
				break;
			case "br":
			case "br.s":
				ret.Codes.Add(new X86Code("jmp", string.Format("PE_{0:X8}", Girl.PEAnalyzer.Util.GetBrTarget(il))));
				if (this.optimize > 0 && nOp == 0) ret.Ignore();
				break;
			case "beq":
			case "beq.s":
				ret.Codes.Add(new X86Code("pop", "ax"));
				ret.Codes.Add(new X86Code("pop", "dx"));
				ret.Codes.Add(new X86Code("cmp", "ax", "dx"));
				ret.Codes.Add(new X86Code("je", string.Format("PE_{0:X8}", Girl.PEAnalyzer.Util.GetBrTarget(il))));
				if (this.optimize > 0 && nOp == 0) ret.Ignore();
				break;
			case "bne.un":
			case "bne.un.s":
				ret.Codes.Add(new X86Code("pop", "ax"));
				ret.Codes.Add(new X86Code("pop", "dx"));
				ret.Codes.Add(new X86Code("cmp", "ax", "dx"));
				ret.Codes.Add(new X86Code("jne", string.Format("PE_{0:X8}", Girl.PEAnalyzer.Util.GetBrTarget(il))));
				if (this.optimize > 0 && nOp == 0) ret.Ignore();
				break;
			case "bgt":
			case "bgt.s":
				ret.Codes.Add(new X86Code("pop", "ax"));
				ret.Codes.Add(new X86Code("pop", "dx"));
				ret.Codes.Add(new X86Code("cmp", "ax", "dx"));
				ret.Codes.Add(new X86Code("jc", string.Format("PE_{0:X8}", Girl.PEAnalyzer.Util.GetBrTarget(il))));
				if (this.optimize > 0 && nOp == 0) ret.Ignore();
				break;
			case "blt":
			case "blt.s":
				ret.Codes.Add(new X86Code("pop", "ax"));
				ret.Codes.Add(new X86Code("pop", "dx"));
				ret.Codes.Add(new X86Code("cmp", "dx", "ax"));
				ret.Codes.Add(new X86Code("jc", string.Format("PE_{0:X8}", Girl.PEAnalyzer.Util.GetBrTarget(il))));
				if (this.optimize > 0 && nOp == 0) ret.Ignore();
				break;
			case "ble":
			case "ble.s":
				ret.Codes.Add(new X86Code("pop", "ax"));
				ret.Codes.Add(new X86Code("pop", "dx"));
				ret.Codes.Add(new X86Code("cmp", "ax", "dx"));
				ret.Codes.Add(new X86Code("jnc", string.Format("PE_{0:X8}", Girl.PEAnalyzer.Util.GetBrTarget(il))));
				if (this.optimize > 0 && nOp == 0) ret.Ignore();
				break;
			case "bge":
			case "bge.s":
				ret.Codes.Add(new X86Code("pop", "ax"));
				ret.Codes.Add(new X86Code("pop", "dx"));
				ret.Codes.Add(new X86Code("cmp", "dx", "ax"));
				ret.Codes.Add(new X86Code("jnc", string.Format("PE_{0:X8}", Girl.PEAnalyzer.Util.GetBrTarget(il))));
				if (this.optimize > 0 && nOp == 0) ret.Ignore();
				break;
			case "brfalse":
			case "brfalse.s":
				ret.Codes.Add(new X86Code("pop", "ax"));
				ret.Codes.Add(new X86Code("or", "ax", "ax"));
				ret.Codes.Add(new X86Code("jz", string.Format("PE_{0:X8}", Girl.PEAnalyzer.Util.GetBrTarget(il))));
				if (this.optimize > 0 && nOp == 0) ret.Ignore();
				break;
			case "brtrue":
			case "brtrue.s":
				ret.Codes.Add(new X86Code("pop", "ax"));
				ret.Codes.Add(new X86Code("or", "ax", "ax"));
				ret.Codes.Add(new X86Code("jnz", string.Format("PE_{0:X8}", Girl.PEAnalyzer.Util.GetBrTarget(il))));
				if (this.optimize > 0 && nOp == 0) ret.Ignore();
				break;
			case "call":
			{
				TableBase tb = this.pedata.idxm.GetTable((int)il.Operand);
				MethodData tb_md = tb.Tag as MethodData;
				ret.Codes.Add(new X86Code("call", string.Format("{0}", Util.MangleFunction(tb_md))));
				if (tb_md.RetType.Element != ELEMENT_TYPE.VOID) ret.Codes.Add(new X86Code("push", "ax"));
				break;
			}
			//case "callvirt":
			//{
			//	TableBase tb = this.pedata.idxm.GetTable((int)il.Operand);
			//	MethodData tb_md = tb.Tag as MethodData;
			//	string func = Util.MangleFunction(tb_md);
			//	if (func.StartsWith("instance__")) func = func.Substring(10, func.Length - 10);
			//	sw.WriteLine("\tcall _virtual__{0}", func);
			//	if (tb_md.RetType.Element != ELEMENT_TYPE.VOID) sw.WriteLine("\tpush ax");
			//	break;
			//}
			case "ret":
				if (this.optimize == 0 || il == this.lastRet)
				{
					if (md.RetType.Element != ELEMENT_TYPE.VOID)
					{
						ret.Codes.Add(new X86Code("pop", "ax"));
					}
					if (md.LocalVars != null || md.ParamCount > 0)
					{
						if (md.LocalVars != null) ret.Codes.Add(new X86Code("mov", "sp", "bp"));
						ret.Codes.Add(new X86Code("pop", "bp"));
					}
					int st = Util.GetStackSize(md);
					if (st == 0)
					{
						ret.Codes.Add(new X86Code("ret"));
					}
					else
					{
						ret.Codes.Add(new X86Code("ret", st.ToString()));
					}
				}
				else
				{
					X86Code x = new X86Code("jmp", string.Format("PE_{0:X8}", this.lastRet.Address));
					x.Notes = "[optimize] modify";
					ret.Codes.Add(x);
					this.lastRet.IsBrTarget = true;
				}
				break;
			case "ceq":
				ret.Codes.Add(new X86Code("pop", "ax"));
				ret.Codes.Add(new X86Code("pop", "dx"));
				ret.Codes.Add(new X86Code("cmp", "ax", "dx"));
				ret.Codes.Add(new X86Code("je", string.Format("NM_{0:X8}", this.number)));
				ret.Codes.Add(new X86Code("xor", "ax", "ax"));
				ret.Codes.Add(new X86Code("jmp", string.Format("NM_{0:X8}", this.number + 1)));
				ret.Codes.Add(new X86Code(string.Format("NM_{0:X8}", this.number), true, "ceq internal", "mov", "ax", "1"));
				ret.Codes.Add(new X86Code(string.Format("NM_{0:X8}", this.number + 1), true, "ceq internal", "push", "ax"));
				this.number += 2;
				break;
			case "add":
			case "and":
			case "or":
				ret.Codes.Add(new X86Code("pop", "ax"));
				ret.Codes.Add(new X86Code("pop", "dx"));
				ret.Codes.Add(new X86Code(mne, "ax", "dx"));
				ret.Codes.Add(new X86Code("push", "ax"));
				break;
			case "sub":
				ret.Codes.Add(new X86Code("pop", "dx"));
				ret.Codes.Add(new X86Code("pop", "ax"));
				ret.Codes.Add(new X86Code("sub", "ax", "dx"));
				ret.Codes.Add(new X86Code("push", "ax"));
				break;
			case "mul":
				ret.Codes.Add(new X86Code("pop", "ax"));
				ret.Codes.Add(new X86Code("pop", "dx"));
				ret.Codes.Add(new X86Code("mul", "dx"));
				ret.Codes.Add(new X86Code("push", "ax"));
				break;
			case "div":
				ret.Codes.Add(new X86Code("pop", "cx"));
				ret.Codes.Add(new X86Code("pop", "ax"));
				ret.Codes.Add(new X86Code("xor", "dx", "dx"));
				ret.Codes.Add(new X86Code("div", "cx"));
				ret.Codes.Add(new X86Code("push", "ax"));
				break;
			case "rem":
				ret.Codes.Add(new X86Code("pop", "cx"));
				ret.Codes.Add(new X86Code("pop", "ax"));
				ret.Codes.Add(new X86Code("xor", "dx", "dx"));
				ret.Codes.Add(new X86Code("div", "cx"));
				ret.Codes.Add(new X86Code("push", "dx"));
				break;
			case "neg":
				ret.Codes.Add(new X86Code("pop", "ax"));
				ret.Codes.Add(new X86Code("neg", "ax"));
				ret.Codes.Add(new X86Code("push", "ax"));
				break;
			case "shr":
			case "shl":
				ret.Codes.Add(new X86Code("pop", "cx"));
				ret.Codes.Add(new X86Code("pop", "ax"));
				ret.Codes.Add(new X86Code(mne, "ax", "cl"));
				ret.Codes.Add(new X86Code("push", "ax"));
				break;
			case "conv.u1":
				ret.Codes.Add(new X86Code("pop", "ax"));
				ret.Codes.Add(new X86Code("mov", "ah", "0"));
				ret.Codes.Add(new X86Code("push", "ax"));
				break;
			case "conv.i2":
			case "conv.u2":
			case "conv.i4":
			case "conv.u4":
				// ignore in 16bit
				return ret;
			//case "box":
			//{
			//	TypeRefTable t = this.pedata.idxm.GetTable((int)il.Operand) as TypeRefTable;
			//	sw.WriteLine("\tcall _box__{0}@4", GetTypeName(this.pedata.idxm.GetName(t)));
			//	sw.WriteLine("\tpush ax");
			//	break;
			//}
		}
		if (ret.Codes.Count < 1) return null;
		return ret;
	}
	
	public object[] ConvertNative(MethodData md)
	{
		Stack st1 = new Stack();
		foreach (ILCode il in md.ILCodes) st1.Push(il);
		
		this.lastRet = null;
		Stack st2 = new Stack();
		while (st1.Count > 0)
		{
			ILCode il = st1.Pop() as ILCode;
			if (il.OpCode.Name == "ret" && this.lastRet == null)
			{
				this.lastRet = il;
			}
			else if (il.OpCode.Name == "pop" && st1.Count > 0)
			{
				ILCode il2 = st1.Peek() as ILCode;
				if (il2.OpCode.Name == "newobj")
				{
					TableBase tb = this.pedata.idxm.GetTable((int)il2.Operand);
					MethodData tb_md = tb.Tag as MethodData;
					if (tb_md.Name == "[I8086]I8086.Inline::.ctor" && st1.Count > 1)
					{
						st1.Pop();
						ILCode il3 = st1.Peek() as ILCode;
						if (il3 != null && il3.OpCode.Name == "ldstr")
						{
							st1.Pop();
							X86Codes nc = new X86Codes();
							nc.Address = il3.Address;
							nc.IsBrTarget = il3.IsBrTarget;
							nc.Comment = "[native] inline";
							nc.Codes.Add(X86Code.Parse(this.hashUS[((int)il3.Operand) & 0xffffff] as string));
							st2.Push(nc);
							continue;
						}
						st1.Push(il2);
					}
				}
			}
			if (il.OpCode.Name == "call")
			{
				TableBase tb = this.pedata.idxm.GetTable((int)il.Operand);
				MethodData tb_md = tb.Tag as MethodData;
				string name = tb_md.Name;
				if (name.StartsWith("[I8086]I8086.Registers::set_"))
				{
					string reg = name.Substring(name.Length - 2, 2).ToLower();
					if (st1.Count > 0 && !name.EndsWith("S"))
					{
						ILCode il2 = st1.Peek() as ILCode;
						string mne = il2.OpCode.Name;
						int nOp = Util.GetOperandValue(il2);
						if (mne.StartsWith("ldc.i4"))
						{
							st1.Pop();
							X86Codes nc = new X86Codes();
							nc.Address = il2.Address;
							nc.IsBrTarget = il2.IsBrTarget;
							nc.Comment = "[native] set register";
							nc.Codes.Add(new X86Code("mov", reg, nOp.ToString()));
							st2.Push(nc);
							continue;
						}
						else if (mne.StartsWith("ldloc"))
						{
							st1.Pop();
							X86Codes nc = new X86Codes();
							nc.Address = il2.Address;
							nc.IsBrTarget = il2.IsBrTarget;
							nc.Comment = "[native] set register";
							nc.Codes.Add(new X86Code("mov", reg, string.Format("[ss:bp-{0}]", (nOp + 1) * 2)));
							st2.Push(nc);
							continue;
						}
						else if (mne.StartsWith("ldarg"))
						{
							st1.Pop();
							X86Codes nc = new X86Codes();
							nc.Address = il2.Address;
							nc.IsBrTarget = il2.IsBrTarget;
							nc.Comment = "[native] set register";
							nc.Codes.Add(new X86Code("mov", reg, string.Format("[ss:bp+{0}]", Util.GetArgPos(md, nOp, this.optimize))));
							st2.Push(nc);
							continue;
						}
					}
					if (name.EndsWith("X") || name.EndsWith("I") || name.EndsWith("S"))
					{
						X86Codes nc = new X86Codes();
						nc.Address = il.Address;
						nc.IsBrTarget = il.IsBrTarget;
						nc.Comment = "[native] set register";
						nc.Codes.Add(new X86Code("pop", reg));
						st2.Push(nc);
						continue;
					}
				}
				else if (name.StartsWith("[I8086]I8086.Registers::get_"))
				{
					X86Codes nc = new X86Codes();
					nc.Address = il.Address;
					nc.IsBrTarget = il.IsBrTarget;
					nc.Comment = "[native] get register";
					nc.Codes.Add(new X86Code("push", name.Substring(name.Length - 2, 2).ToLower()));
					st2.Push(nc);
					continue;
				}
				else if (name == "[I8086]I8086.IO::In" && st1.Count > 0)
				{
					ILCode il2 = st1.Peek() as ILCode;
					string mne = il2.OpCode.Name;
					int nOp = Util.GetOperandValue(il2);
					X86Codes nc = new X86Codes();
					nc.Comment = "[native] in";
					if (mne.StartsWith("ldc.i4"))
					{
						st1.Pop();
						nc.Address = il2.Address;
						nc.IsBrTarget = il2.IsBrTarget;
						nc.Codes.Add(new X86Code("in", "al", nOp.ToString()));
					}
					else
					{
						nc.Address = il.Address;
						nc.IsBrTarget = il.IsBrTarget;
						nc.Codes.Add(new X86Code("pop", "dx"));
						nc.Codes.Add(new X86Code("in", "al", "dx"));
					}
					nc.Codes.Add(new X86Code("mov", "ah", "0"));
					nc.Codes.Add(new X86Code("push", "ax"));
					st2.Push(nc);
					continue;
				}
				else if (name == "[I8086]I8086.IO::Out")
				{
					X86Codes nc = new X86Codes();
					nc.Address = il.Address;
					nc.IsBrTarget = il.IsBrTarget;
					nc.Comment = "[native] out";
					nc.Codes.Add(new X86Code("pop", "ax"));
					nc.Codes.Add(new X86Code("pop", "dx"));
					nc.Codes.Add(new X86Code("out", "dx", "al"));
					st2.Push(nc);
					continue;
				}
				else if (name == "[I8086]I8086.StringPtr::Get")
				{
					continue;
				}
				else if (name.StartsWith("[I8086]I8086.Flags::get_"))
				{
					string mne = "jz";
					int p = name.IndexOf('_') + 1;
					switch (name.Substring(p, name.Length - p))
					{
						case "NZ":
						case "NE":
							mne = "jnz";
							break;
						case "C":
							mne = "jc";
							break;
						case "NC":
							mne = "jnc";
							break;
					}
					X86Codes nc = new X86Codes();
					nc.Address = il.Address;
					nc.IsBrTarget = il.IsBrTarget;
					nc.Comment = "[native] get flag";
					nc.Codes.Add(new X86Code(mne, string.Format("NM_{0:X8}", this.number)));
					nc.Codes.Add(new X86Code("xor", "ax", "ax"));
					nc.Codes.Add(new X86Code("jmp", string.Format("NM_{0:X8}", this.number + 1)));
					nc.Codes.Add(new X86Code(string.Format("NM_{0:X8}", this.number), true, "[native] get flag internal", "mov", "ax", "1"));
					nc.Codes.Add(new X86Code(string.Format("NM_{0:X8}", this.number + 1), true, "[native] get flag internal", "push", "ax"));
					st2.Push(nc);
					this.number += 2;
					continue;
				}
			}
			st2.Push(il);
		}
		return st2.ToArray();
	}
	
	public string MangleField(FieldTable f)
	{
		return Util.MangleName(string.Format("{0}::{1}",
			this.pedata.idxm.GetName(f.ParentTable as TypeDefTable),
			this.pedata.idxm.GetStringsString(f.Name)));
	}
}
