OpCodes

Namespace: Paket.PowerShell
We found 10 examples in language CSharp for this search. You will see 33 fragments of code.
/*
 * Tencent is pleased to support the open source community by making xLua available.
 * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
 * Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
 * http://opensource.org/licenses/MIT
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
*/

#if UNITY_EDITOR || XLUA_GENERAL
using System.Collections.Generic;
using System.Reflection.Emit;
using System.Reflection;
using System;
using System.Linq;

#if USE_UNI_LUA
using LuaAPI = UniLua.Lua;
using RealStatePtr = UniLua.ILuaState;
using LuaCSFunction = UniLua.CSharpFunctionDelegate;
#else
using LuaAPI = XLua.LuaDLL.Lua;
using RealStatePtr = System.IntPtr;
using LuaCSFunction = XLua.LuaDLL.lua_CSFunction;
#endif

namespace XLua
{
    public class CodeEmit
    {
        private ModuleBuilder codeEmitModule = null;
        private ulong genID = 0;

        private MethodInfo LuaEnv_ThrowExceptionFromError = typeof(LuaEnv).GetMethod("ThrowExceptionFromError");
        private FieldInfo LuaBase_luaEnv = typeof(LuaBase).GetField("luaEnv", BindingFlags.NonPublic | BindingFlags.Instance);
        private MethodInfo DelegateBridgeBase_errorFuncRef_getter = typeof(LuaBase).GetProperty("_errorFuncRef", BindingFlags.NonPublic | BindingFlags.Instance).GetGetMethod(true);
        private MethodInfo LuaAPI_load_error_func = typeof(LuaAPI).GetMethod("load_error_func");
        private MethodInfo LuaBase_translator_getter  = typeof(LuaBase).GetProperty("_translator", BindingFlags.NonPublic | BindingFlags.Instance).GetGetMethod(true);
        private FieldInfo LuaBase_luaReference = typeof(LuaBase).GetField("luaReference", BindingFlags.NonPublic | BindingFlags.Instance);
        private MethodInfo LuaAPI_lua_getref = typeof(LuaAPI).GetMethod("lua_getref");
        private MethodInfo Type_GetTypeFromHandle = typeof(Type).GetMethod("GetTypeFromHandle", new Type[] { typeof(RuntimeTypeHandle) });
        private MethodInfo ObjectTranslator_PushAny = typeof(ObjectTranslator).GetMethod("PushAny");
        private MethodInfo ObjectTranslator_PushParams = typeof(ObjectTranslator).GetMethod("PushParams");
        private MethodInfo LuaBase_L_getter = typeof(LuaBase).GetProperty("_L", BindingFlags.NonPublic | BindingFlags.Instance).GetGetMethod(true);
        private MethodInfo LuaAPI_lua_pcall = typeof(LuaAPI).GetMethod("lua_pcall");
        private MethodInfo LuaAPI_lua_type = typeof(LuaAPI).GetMethod("lua_type");
        private MethodInfo ObjectTranslator_GetObject = typeof(ObjectTranslator).GetMethod("GetObject", new Type[] { typeof(RealStatePtr),
               typeof(int), typeof(Type)});
        private MethodInfo ObjectTranslator_GetParams = typeof(ObjectTranslator).GetMethod("GetParams", new Type[] { typeof(RealStatePtr), typeof(int) });
        private MethodInfo ObjectTranslator_Update = typeof(ObjectTranslator).GetMethod("Update");
        private MethodInfo LuaAPI_lua_pushvalue = typeof(LuaAPI).GetMethod("lua_pushvalue");
        private MethodInfo LuaAPI_lua_remove = typeof(LuaAPI).GetMethod("lua_remove");
        private MethodInfo LuaAPI_lua_pushstring = typeof(LuaAPI).GetMethod("lua_pushstring", new Type[] { typeof(RealStatePtr), typeof(string)});
        private MethodInfo LuaAPI_lua_gettop = typeof(LuaAPI).GetMethod("lua_gettop");
        private MethodInfo LuaAPI_xlua_pgettable = typeof(LuaAPI).GetMethod("xlua_pgettable");
        private MethodInfo LuaAPI_xlua_psettable = typeof(LuaAPI).GetMethod("xlua_psettable");
        private MethodInfo LuaAPI_lua_pop = typeof(LuaAPI).GetMethod("lua_pop");
        private MethodInfo LuaAPI_lua_settop = typeof(LuaAPI).GetMethod("lua_settop");
        private MethodInfo LuaAPI_luaL_error = typeof(LuaAPI).GetMethod("luaL_error");
        private MethodInfo LuaAPI_xlua_is_eq_str = typeof(LuaAPI).GetMethod("xlua_is_eq_str", new Type[] {
        typeof(RealStatePtr), typeof(int), typeof(string)});

        private MethodInfo LuaAPI_xlua_pushinteger = typeof(LuaAPI).GetMethod("xlua_pushinteger");
        private MethodInfo LuaAPI_lua_pushint64 = typeof(LuaAPI).GetMethod("lua_pushint64");
        private MethodInfo LuaAPI_lua_pushnumber = typeof(LuaAPI).GetMethod("lua_pushnumber");
        private MethodInfo LuaAPI_xlua_pushuint = typeof(LuaAPI).GetMethod("xlua_pushuint");
        private MethodInfo LuaAPI_lua_pushuint64 = typeof(LuaAPI).GetMethod("lua_pushuint64");
        private MethodInfo LuaAPI_lua_pushboolean = typeof(LuaAPI).GetMethod("lua_pushboolean");
        private MethodInfo LuaAPI_lua_pushbytes = typeof(LuaAPI).GetMethod("lua_pushstring", new Type[] { typeof(RealStatePtr), typeof(byte[]) });
        private MethodInfo LuaAPI_lua_pushlightuserdata = typeof(LuaAPI).GetMethod("lua_pushlightuserdata");
        private MethodInfo ObjectTranslator_PushDecimal = typeof(ObjectTranslator).GetMethod("PushDecimal");
        private MethodInfo ObjectTranslator_GetDecimal = typeof(ObjectTranslator).GetMethod("GetDecimal");

        private Dictionary<Type, MethodInfo> fixPush;

        private MethodInfo LuaAPI_xlua_tointeger = typeof(LuaAPI).GetMethod("xlua_tointeger");
        private MethodInfo LuaAPI_lua_tonumber = typeof(LuaAPI).GetMethod("lua_tonumber");
        private MethodInfo LuaAPI_lua_tostring = typeof(LuaAPI).GetMethod("lua_tostring");
        private MethodInfo LuaAPI_lua_toboolean = typeof(LuaAPI).GetMethod("lua_toboolean");
        private MethodInfo LuaAPI_lua_tobytes = typeof(LuaAPI).GetMethod("lua_tobytes");
        private MethodInfo LuaAPI_lua_touserdata = typeof(LuaAPI).GetMethod("lua_touserdata");
        private MethodInfo LuaAPI_xlua_touint = typeof(LuaAPI).GetMethod("xlua_touint");
        private MethodInfo LuaAPI_lua_touint64 = typeof(LuaAPI).GetMethod("lua_touint64");
        private MethodInfo LuaAPI_lua_toint64 = typeof(LuaAPI).GetMethod("lua_toint64");

        private Dictionary<Type, MethodInfo> typedCaster;
        private Dictionary<Type, MethodInfo> fixCaster;

        public CodeEmit()
        {
            fixPush = new Dictionary<Type, MethodInfo>()
            {
                {typeof(byte), LuaAPI_xlua_pushinteger},
                {typeof(char), LuaAPI_xlua_pushinteger},
                {typeof(short), LuaAPI_xlua_pushinteger},
                {typeof(int), LuaAPI_xlua_pushinteger},
                {typeof(long), LuaAPI_lua_pushint64},
                {typeof(sbyte), LuaAPI_xlua_pushinteger},
                {typeof(float), LuaAPI_lua_pushnumber},
                {typeof(ushort), LuaAPI_xlua_pushinteger},
                {typeof(uint), LuaAPI_xlua_pushuint},
                {typeof(ulong), LuaAPI_lua_pushuint64},
                {typeof(double), LuaAPI_lua_pushnumber},
                {typeof(string), LuaAPI_lua_pushstring},
                {typeof(byte[]), LuaAPI_lua_pushbytes},
                {typeof(bool), LuaAPI_lua_pushboolean},
                {typeof(IntPtr), LuaAPI_lua_pushlightuserdata},
            };

            fixCaster = new Dictionary<Type, MethodInfo>()
            {
                {typeof(double), LuaAPI_lua_tonumber},
                {typeof(string), LuaAPI_lua_tostring},
                {typeof(bool), LuaAPI_lua_toboolean},
                {typeof(byte[]), LuaAPI_lua_tobytes},
                {typeof(IntPtr), LuaAPI_lua_touserdata},
                {typeof(uint), LuaAPI_xlua_touint},
                {typeof(ulong), LuaAPI_lua_touint64},
                {typeof(int), LuaAPI_xlua_tointeger},
                {typeof(long), LuaAPI_lua_toint64},
            };

            typedCaster = new Dictionary<Type, MethodInfo>()
            {
                {typeof(byte), LuaAPI_xlua_tointeger},
                {typeof(char), LuaAPI_xlua_tointeger},
                {typeof(short), LuaAPI_xlua_tointeger},
                {typeof(sbyte), LuaAPI_xlua_tointeger},
                {typeof(float), LuaAPI_lua_tonumber},
                {typeof(ushort), LuaAPI_xlua_tointeger},
            };

            initBlackList();
        }

        private void emitPush(ILGenerator il, Type type, short dataPos, bool isParam, LocalBuilder L, LocalBuilder translator, bool isArg)
        {
            var paramElemType = type.IsByRef ? type.GetElementType() : type;
            var ldd = isArg ? OpCodes.Ldarg : OpCodes.Ldloc;
            MethodInfo pusher;
            if (fixPush.TryGetValue(paramElemType, out pusher))
            {
                il.Emit(OpCodes.Ldloc, L);
                il.Emit(ldd, dataPos);

                if (type.IsByRef)
                {
                    if (paramElemType.IsValueType)
                    {
                        il.Emit(OpCodes.Ldobj, paramElemType);
                    }
                    else
                    {
                        il.Emit(OpCodes.Ldind_Ref);
                    }
                }

                il.Emit(OpCodes.Call, pusher);
            }
            else if (paramElemType == typeof(decimal))
            {
                il.Emit(OpCodes.Ldloc, translator);
                il.Emit(OpCodes.Ldloc, L);
                il.Emit(ldd, dataPos);
                if (type.IsByRef)
                {
                    il.Emit(OpCodes.Ldobj, paramElemType);
                }
                il.Emit(OpCodes.Callvirt, ObjectTranslator_PushDecimal);
            }
            else
            {
                il.Emit(OpCodes.Ldloc, translator);
                il.Emit(OpCodes.Ldloc, L);
                il.Emit(ldd, dataPos);
                if (type.IsByRef)
                {
                    if (paramElemType.IsValueType)
                    {
                        il.Emit(OpCodes.Ldobj, paramElemType);
                        il.Emit(OpCodes.Box, paramElemType);
                    }
                    else
                    {
                        il.Emit(OpCodes.Ldind_Ref);
                    }
                }
                else if (type.IsValueType)
                {
                    il.Emit(OpCodes.Box, type);
                }
                if (isParam)
                {
                    il.Emit(OpCodes.Callvirt, ObjectTranslator_PushParams);
                }
                else
                {
                    il.Emit(OpCodes.Callvirt, ObjectTranslator_PushAny);
                }
            }
        }

        private ModuleBuilder CodeEmitModule
        {
            get
            {
                if (codeEmitModule == null)
                {
                    var assemblyName = new AssemblyName();
                    assemblyName.Name = "XLuaCodeEmit";
                    codeEmitModule = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run)
                        .DefineDynamicModule("XLuaCodeEmit");
                }
                return codeEmitModule;
            }
        }

        public Type EmitDelegateImpl(IEnumerable<IGrouping<MethodInfo, Type>> groups)
        {
            TypeBuilder impl_type_builder = CodeEmitModule.DefineType("XLuaGenDelegateImpl" + (genID++), TypeAttributes.Public, typeof(DelegateBridge));

            MethodBuilder get_deleate_by_type = impl_type_builder.DefineMethod("GetDelegateByType", MethodAttributes.Public
                    | MethodAttributes.HideBySig
                    | MethodAttributes.NewSlot
                    | MethodAttributes.Virtual
                    | MethodAttributes.Final,
                    typeof(System.Delegate), new Type[] { typeof(System.Type) });

            ILGenerator get_deleate_by_type_il = get_deleate_by_type.GetILGenerator();

            foreach (var group in groups)
            {
                var to_be_impl = group.Key;

                var method_builder = defineImplementMethod(impl_type_builder, to_be_impl, to_be_impl.Attributes, "Invoke" + (genID++));

                emitMethodImpl(to_be_impl, method_builder.GetILGenerator(), false);

                foreach(var dt in group)
                {
                    Label end_of_if = get_deleate_by_type_il.DefineLabel();
                    get_deleate_by_type_il.Emit(OpCodes.Ldarg_1);
                    get_deleate_by_type_il.Emit(OpCodes.Ldtoken, dt);
                    get_deleate_by_type_il.Emit(OpCodes.Call, Type_GetTypeFromHandle); // typeof(type)
                    get_deleate_by_type_il.Emit(OpCodes.Bne_Un, end_of_if);

                    get_deleate_by_type_il.Emit(OpCodes.Ldarg_0);
                    get_deleate_by_type_il.Emit(OpCodes.Ldftn, method_builder);
                    get_deleate_by_type_il.Emit(OpCodes.Newobj, dt.GetConstructor(new Type[] { typeof(object), typeof(IntPtr) }));
                    get_deleate_by_type_il.Emit(OpCodes.Ret);
                    get_deleate_by_type_il.MarkLabel(end_of_if);
                }
            }

            // Constructor
            var ctor_param_types = new Type[] { typeof(int), typeof(LuaEnv) };
            ConstructorInfo parent_ctor = typeof(DelegateBridge).GetConstructor(ctor_param_types);
            var ctor_builder = impl_type_builder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, ctor_param_types);
            var ctor_il = ctor_builder.GetILGenerator();
            ctor_il.Emit(OpCodes.Ldarg_0);
            ctor_il.Emit(OpCodes.Ldarg_1);
            ctor_il.Emit(OpCodes.Ldarg_2);
            ctor_il.Emit(OpCodes.Call, parent_ctor);
            ctor_il.Emit(OpCodes.Ret);

            // end of GetDelegateByType
            get_deleate_by_type_il.Emit(OpCodes.Ldnull);
            get_deleate_by_type_il.Emit(OpCodes.Ret);

            impl_type_builder.DefineMethodOverride(get_deleate_by_type, typeof(DelegateBridgeBase).GetMethod("GetDelegateByType"));


            return impl_type_builder.CreateType();
        }

        private void EmitGetObject(ILGenerator il, int offset, Type type, LocalBuilder L, LocalBuilder translator, LocalBuilder offsetBase, bool isParam = false)
        {
            if (!fixCaster.ContainsKey(type) && !typedCaster.ContainsKey(type))
            {
                il.Emit(OpCodes.Ldloc, translator); // translator
            }
            il.Emit(OpCodes.Ldloc, L); // L
            if (offsetBase != null)
            {
                il.Emit(OpCodes.Ldloc, offsetBase); // err_func
                il.Emit(OpCodes.Ldc_I4, offset);
                il.Emit(OpCodes.Add);
            }
            else
            {
                il.Emit(OpCodes.Ldc_I4, offset);
            }

            MethodInfo caster;
            
            if (fixCaster.TryGetValue(type, out caster))
            {
                il.Emit(OpCodes.Call, caster);
            }
            else if (typedCaster.TryGetValue(type, out caster))
            {
                il.Emit(OpCodes.Call, caster);
                if (type == typeof(byte))
                {
                    il.Emit(OpCodes.Conv_U1);
                }
                else if(type == typeof(char))
                {
                    il.Emit(OpCodes.Conv_U2);
                }
                else if (type == typeof(short))
                {
                    il.Emit(OpCodes.Conv_I2);
                }
                else if (type == typeof(sbyte))
                {
                    il.Emit(OpCodes.Conv_I1);
                }
                else if (type == typeof(ushort))
                {
                    il.Emit(OpCodes.Conv_U2);
                }
                else if (type == typeof(float))
                {
                    il.Emit(OpCodes.Conv_R4);
                }
                else
                {
                    throw new InvalidProgramException(type + " is not a type need cast");
                }
            }
            else if (type == typeof(decimal))
            {
                il.Emit(OpCodes.Callvirt, ObjectTranslator_GetDecimal);
            }
            else
            {
                if (isParam)
                {
                    il.Emit(OpCodes.Callvirt, ObjectTranslator_GetParams.MakeGenericMethod(new Type[] { type.GetElementType() }));
                }
                else
                {
                    il.Emit(OpCodes.Ldtoken, type);
                    il.Emit(OpCodes.Call, Type_GetTypeFromHandle); // typeof(type)
                    il.Emit(OpCodes.Callvirt, ObjectTranslator_GetObject);
                }
                if (type.IsValueType)
                {
                    Label not_null = il.DefineLabel();
                    Label null_done = il.DefineLabel();
                    LocalBuilder local_new = il.DeclareLocal(type);

                    il.Emit(OpCodes.Dup);
                    il.Emit(OpCodes.Brtrue_S, not_null);

                    il.Emit(OpCodes.Pop);
                    il.Emit(OpCodes.Ldloca, local_new);
                    il.Emit(OpCodes.Initobj, type);
                    il.Emit(OpCodes.Ldloc, local_new);
                    il.Emit(OpCodes.Br_S, null_done);

                    il.MarkLabel(not_null);
                    il.Emit(OpCodes.Unbox_Any, type);
                    il.MarkLabel(null_done);
                }
                else if (type != typeof(object))
                {
                    il.Emit(OpCodes.Castclass, type);
                }
            }
        }

        HashSet<Type> gen_interfaces = new HashSet<Type>();

        public void SetGenInterfaces(List<Type> gen_interfaces)
        {
            gen_interfaces.ForEach((item) =>
            {
                if (!this.gen_interfaces.Contains(item))
                {
                    this.gen_interfaces.Add(item);
                }
            });
        }

        public Type EmitInterfaceImpl(Type to_be_impl)
        {
            if (!to_be_impl.IsInterface)
            {
                throw new InvalidOperationException("interface expected, but got " + to_be_impl);
            }

            if (!gen_interfaces.Contains(to_be_impl))
            {
                throw new InvalidCastException("This type must add to CSharpCallLua: " + to_be_impl.GetFriendlyName());
            }

            TypeBuilder impl_type_builder = CodeEmitModule.DefineType("XLuaGenInterfaceImpl" + (genID++), TypeAttributes.Public | TypeAttributes.Class, typeof(LuaBase), new Type[] { to_be_impl});

            foreach(var member in (new Type[] { to_be_impl }.Concat(to_be_impl.GetInterfaces()).SelectMany(i=> i.GetMembers())))
            {
                if (member.MemberType == MemberTypes.Method)
                {
                    MethodInfo method = member as MethodInfo;
                    if (method.Name.StartsWith("get_") || method.Name.StartsWith("set_") ||
                        method.Name.StartsWith("add_") || method.Name.StartsWith("remove_"))
                    {
                        continue;
                    }

                    var method_builder = defineImplementMethod(impl_type_builder, method,
                        MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual);

                    emitMethodImpl(method, method_builder.GetILGenerator(), true);
                }
                else if (member.MemberType == MemberTypes.Property)
                {
                    PropertyInfo property = member as PropertyInfo;
                    PropertyBuilder prop_builder = impl_type_builder.DefineProperty(property.Name, property.Attributes, property.PropertyType, Type.EmptyTypes);
                    if (property.Name == "Item")
                    {
                        if (property.CanRead)
                        {
                            var getter_buildler = defineImplementMethod(impl_type_builder, property.GetGetMethod(), 
                                MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig);
                            emitMethodImpl(property.GetGetMethod(), getter_buildler.GetILGenerator(), true);
                            prop_builder.SetGetMethod(getter_buildler);
                        }
                        if (property.CanWrite)
                        {
                            var setter_buildler = defineImplementMethod(impl_type_builder, property.GetSetMethod(),
                                MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig);
                            emitMethodImpl(property.GetSetMethod(), setter_buildler.GetILGenerator(), true);
                            prop_builder.SetSetMethod(setter_buildler);
                        }
                        continue;
                    }
                    if (property.CanRead)
                    {
                        MethodBuilder getter_buildler = impl_type_builder.DefineMethod("get_" + property.Name, 
                            MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
                            property.PropertyType, Type.EmptyTypes);

                        ILGenerator il = getter_buildler.GetILGenerator();

                        LocalBuilder L = il.DeclareLocal(typeof(RealStatePtr));
                        LocalBuilder oldTop = il.DeclareLocal(typeof(int));
                        LocalBuilder translator = il.DeclareLocal(typeof(ObjectTranslator));
                        LocalBuilder ret = il.DeclareLocal(property.PropertyType);

                        // L = LuaBase.L;
                        il.Emit(OpCodes.Ldarg_0);
                        il.Emit(OpCodes.Callvirt, LuaBase_L_getter);
                        il.Emit(OpCodes.Stloc, L);

                        //oldTop = LuaAPI.lua_gettop(L);
                        il.Emit(OpCodes.Ldloc, L);
                        il.Emit(OpCodes.Call, LuaAPI_lua_gettop);
                        il.Emit(OpCodes.Stloc, oldTop);

                        //translator = LuaBase.translator;
                        il.Emit(OpCodes.Ldarg_0);
                        il.Emit(OpCodes.Callvirt, LuaBase_translator_getter);
                        il.Emit(OpCodes.Stloc, translator);

                        //LuaAPI.lua_getref(L, luaReference);
                        il.Emit(OpCodes.Ldloc, L);
                        il.Emit(OpCodes.Ldarg_0);
                        il.Emit(OpCodes.Ldfld, LuaBase_luaReference);
                        il.Emit(OpCodes.Call, LuaAPI_lua_getref);

                        //LuaAPI.lua_pushstring(L, "xxx");
                        il.Emit(OpCodes.Ldloc, L);
                        il.Emit(OpCodes.Ldstr, property.Name);
                        il.Emit(OpCodes.Call, LuaAPI_lua_pushstring);

                        //LuaAPI.xlua_pgettable(L, -2)
                        il.Emit(OpCodes.Ldloc, L);
                        il.Emit(OpCodes.Ldc_I4_S, (sbyte)-2);
                        il.Emit(OpCodes.Call, LuaAPI_xlua_pgettable);
                        Label gettable_no_exception = il.DefineLabel();
                        il.Emit(OpCodes.Brfalse, gettable_no_exception);

                        il.Emit(OpCodes.Ldarg_0);
                        il.Emit(OpCodes.Ldfld, LuaBase_luaEnv);
                        il.Emit(OpCodes.Ldloc, oldTop);
                        il.Emit(OpCodes.Callvirt, LuaEnv_ThrowExceptionFromError);
                        il.MarkLabel(gettable_no_exception);

                        EmitGetObject(il, -1, property.PropertyType, L, translator, null);
                        il.Emit(OpCodes.Stloc, ret);

                        //LuaAPI.lua_pop(L, 2);
                        il.Emit(OpCodes.Ldloc, L);
                        il.Emit(OpCodes.Ldc_I4_S, (sbyte)2);
                        il.Emit(OpCodes.Call, LuaAPI_lua_pop);

                        il.Emit(OpCodes.Ldloc, ret);
                        il.Emit(OpCodes.Ret);

                        prop_builder.SetGetMethod(getter_buildler);
                    }
                    if (property.CanWrite)
                    {
                        MethodBuilder setter_builder = impl_type_builder.DefineMethod("set_" + property.Name, 
                            MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, 
                            null, new Type[] { property.PropertyType });

                        ILGenerator il = setter_builder.GetILGenerator();

                        LocalBuilder L = il.DeclareLocal(typeof(RealStatePtr));
                        LocalBuilder oldTop = il.DeclareLocal(typeof(int));
                        LocalBuilder translator = il.DeclareLocal(typeof(ObjectTranslator));

                        // L = LuaBase.L;
                        il.Emit(OpCodes.Ldarg_0);
                        il.Emit(OpCodes.Callvirt, LuaBase_L_getter);
                        il.Emit(OpCodes.Stloc, L);

                        //oldTop = LuaAPI.lua_gettop(L);
                        il.Emit(OpCodes.Ldloc, L);
                        il.Emit(OpCodes.Call, LuaAPI_lua_gettop);
                        il.Emit(OpCodes.Stloc, oldTop);

                        //translator = LuaBase.translator;
                        il.Emit(OpCodes.Ldarg_0);
                        il.Emit(OpCodes.Callvirt, LuaBase_translator_getter);
                        il.Emit(OpCodes.Stloc, translator);

                        //LuaAPI.lua_getref(L, luaReference);
                        il.Emit(OpCodes.Ldloc, L);
                        il.Emit(OpCodes.Ldarg_0);
                        il.Emit(OpCodes.Ldfld, LuaBase_luaReference);
                        il.Emit(OpCodes.Call, LuaAPI_lua_getref);

                        //LuaAPI.lua_pushstring(L, "xxx");
                        il.Emit(OpCodes.Ldloc, L);
                        il.Emit(OpCodes.Ldstr, property.Name);
                        il.Emit(OpCodes.Call, LuaAPI_lua_pushstring);

                        //translator.Push(L, value);
                        emitPush(il, property.PropertyType, 1, false, L, translator, true);

                        //LuaAPI.xlua_psettable(L, -2)
                        il.Emit(OpCodes.Ldloc, L);
                        il.Emit(OpCodes.Ldc_I4_S, (sbyte)-3);
                        il.Emit(OpCodes.Call, LuaAPI_xlua_psettable);
                        Label settable_no_exception = il.DefineLabel();
                        il.Emit(OpCodes.Brfalse, settable_no_exception);

                        il.Emit(OpCodes.Ldarg_0);
                        il.Emit(OpCodes.Ldfld, LuaBase_luaEnv);
                        il.Emit(OpCodes.Ldloc, oldTop);
                        il.Emit(OpCodes.Callvirt, LuaEnv_ThrowExceptionFromError);
                        il.MarkLabel(settable_no_exception);

                        //LuaAPI.lua_pop(L, 1);
                        il.Emit(OpCodes.Ldloc, L);
                        il.Emit(OpCodes.Ldc_I4_S, (sbyte)1);
                        il.Emit(OpCodes.Call, LuaAPI_lua_pop);

                        il.Emit(OpCodes.Ret);

                        prop_builder.SetSetMethod(setter_builder);

                    }
                }
                else if(member.MemberType == MemberTypes.Event)
                {
                    
                    EventInfo event_info = member as EventInfo;
                    EventBuilder event_builder = impl_type_builder.DefineEvent(event_info.Name, event_info.Attributes, event_info.EventHandlerType);
                    if (event_info.GetAddMethod() != null)
                    {
                        var add_buildler = defineImplementMethod(impl_type_builder, event_info.GetAddMethod(),
                            MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig);
                        emitMethodImpl(event_info.GetAddMethod(), add_buildler.GetILGenerator(), true);
                        event_builder.SetAddOnMethod(add_buildler);
                    }
                    if (event_info.GetRemoveMethod() != null)
                    {
                        var remove_buildler = defineImplementMethod(impl_type_builder, event_info.GetRemoveMethod(),
                            MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig);
                        emitMethodImpl(event_info.GetRemoveMethod(), remove_buildler.GetILGenerator(), true);
                        event_builder.SetRemoveOnMethod(remove_buildler);
                    }
                }
            }
            

            // Constructor
            var ctor_param_types = new Type[] { typeof(int), typeof(LuaEnv) };
            ConstructorInfo parent_ctor = typeof(LuaBase).GetConstructor(ctor_param_types);
            var ctor_builder = impl_type_builder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, ctor_param_types);
            var ctor_il = ctor_builder.GetILGenerator();
            ctor_il.Emit(OpCodes.Ldarg_0);
            ctor_il.Emit(OpCodes.Ldarg_1);
            ctor_il.Emit(OpCodes.Ldarg_2);
            ctor_il.Emit(OpCodes.Call, parent_ctor);
            ctor_il.Emit(OpCodes.Ret);

            return impl_type_builder.CreateType();
        }

        private void emitEmptyMethod(ILGenerator il, Type returnType)
        {
            if(returnType != typeof(void))
            {
                if (returnType.IsValueType)
                {
                    LocalBuilder local_new = il.DeclareLocal(returnType);
                    il.Emit(OpCodes.Ldloca, local_new);
                    il.Emit(OpCodes.Initobj, returnType);
                    il.Emit(OpCodes.Ldloc, local_new);
                }
                else
                {
                    il.Emit(OpCodes.Ldnull);
                }
            }
            il.Emit(OpCodes.Ret);
        }

        private MethodBuilder defineImplementMethod(TypeBuilder type_builder, MethodInfo to_be_impl, MethodAttributes attributes, string methodName = null)
        {
            var parameters = to_be_impl.GetParameters();

            Type[] param_types = new Type[parameters.Length];
            for (int i = 0; i < parameters.Length; ++i)
            {
                param_types[i] = parameters[i].ParameterType;
            }

            var method_builder = type_builder.DefineMethod(methodName == null ? to_be_impl.Name : methodName, attributes, to_be_impl.ReturnType, param_types);
            for (int i = 0; i < parameters.Length; ++i)
            {
                method_builder.DefineParameter(i + 1, parameters[i].Attributes, parameters[i].Name);
            }
            return method_builder;
        }

        ConstructorInfo decimalConstructor = typeof(decimal).GetConstructor(new Type[] {
            typeof(int), typeof(int), typeof(int), typeof(bool), typeof(byte)
        });

        private void emitLiteralLoad(ILGenerator il, Type type, object obj, int localIndex)
        {
            if (!type.IsValueType && ReferenceEquals(obj, null))
            {
                il.Emit(OpCodes.Ldnull);
            }
            else if(type.IsPrimitive || type.IsEnum)
            {
                if (type.IsEnum)
                {
                    type = Enum.GetUnderlyingType(type);
                }
                if (typeof(bool) == type)
                {
                    if ((bool)obj == true)
                    {
                        il.Emit(OpCodes.Ldc_I4_1);
                    }
                    else
                    {
                        il.Emit(OpCodes.Ldc_I4_0);
                    }
                }
                else if (typeof(uint) == type)
                {
                    il.Emit(OpCodes.Ldc_I4, (int)Convert.ToUInt32(obj));
                }
                else if(typeof(byte) == type || typeof(sbyte) == type || typeof(short) == type ||
                    typeof(ushort) == type || typeof(int) == type || typeof(char) == type)
                {
                    il.Emit(OpCodes.Ldc_I4, Convert.ToInt32(obj));
                }
                else if (typeof(long) == type)
                {
                    il.Emit(OpCodes.Ldc_I8, Convert.ToInt64(obj));
                }
                else if (typeof(ulong) == type)
                {
                    il.Emit(OpCodes.Ldc_I8, (long)Convert.ToUInt64(obj));
                }
                else if (typeof(IntPtr) == type || typeof(IntPtr) == type)
                {
                    il.Emit(OpCodes.Ldloca, localIndex);
                    il.Emit(OpCodes.Initobj, type);
                    il.Emit(OpCodes.Ldloc, localIndex);
                }
                else if (typeof(float) == type)
                {
                    il.Emit(OpCodes.Ldc_R4, Convert.ToSingle(obj));
                }
                else if (typeof(double) == type)
                {
                    il.Emit(OpCodes.Ldc_R8, Convert.ToDouble(obj));
                }
                else
                {
                    throw new Exception(type + " is not primitive or enum!");
                }
            }
            else if (type == typeof(string))
            {
                il.Emit(OpCodes.Ldstr, obj as string);
            }
            else if (type == typeof(decimal))
            {
                var buffer = decimal.GetBits(Convert.ToDecimal(obj));
                il.Emit(OpCodes.Ldc_I4, buffer[0]);
                il.Emit(OpCodes.Ldc_I4, buffer[1]);
                il.Emit(OpCodes.Ldc_I4, buffer[2]);
                //UnityEngine.Debug.Log(string.Format("{0}.{1}.{2}.{3}--{4}", buffer[0], buffer[1], buffer[2], buffer[3], obj));
                il.Emit(OpCodes.Ldc_I4, (buffer[3] & 0x80000000) == 0 ? 0 : 1);
                il.Emit(OpCodes.Ldc_I4, (buffer[3] >> 16) & 0xFF);
                il.Emit(OpCodes.Newobj, decimalConstructor);
            }
            else if (type.IsValueType) 
            {
                il.Emit(OpCodes.Ldloca, localIndex);
                il.Emit(OpCodes.Initobj, type);
                il.Emit(OpCodes.Ldloc, localIndex);
            }
            else
            {
                il.Emit(OpCodes.Ldnull);
            }
        }

        private void emitMethodImpl(MethodInfo to_be_impl, ILGenerator il, bool isObj)
        {
            var parameters = to_be_impl.GetParameters();

            LocalBuilder L = il.DeclareLocal(typeof(RealStatePtr));//RealStatePtr L;  0
            LocalBuilder err_func = il.DeclareLocal(typeof(int));//int err_func; 1
            LocalBuilder translator = il.DeclareLocal(typeof(ObjectTranslator));//ObjectTranslator translator; 2
            LocalBuilder ret = null;
            bool has_return = to_be_impl.ReturnType != typeof(void);
            if (has_return)
            {
                ret = il.DeclareLocal(to_be_impl.ReturnType); //ReturnType ret; 3
            }

            // L = LuaBase.L;
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Callvirt, LuaBase_L_getter);
            il.Emit(OpCodes.Stloc, L);

            //err_func =LuaAPI.load_error_func(L, errorFuncRef);
            il.Emit(OpCodes.Ldloc, L);
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Callvirt, DelegateBridgeBase_errorFuncRef_getter);
            il.Emit(OpCodes.Call, LuaAPI_load_error_func);
            il.Emit(OpCodes.Stloc, err_func);

            //translator = LuaBase.translator;
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Callvirt, LuaBase_translator_getter);
            il.Emit(OpCodes.Stloc, translator);

            //LuaAPI.lua_getref(L, luaReference);
            il.Emit(OpCodes.Ldloc, L);
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldfld, LuaBase_luaReference);
            il.Emit(OpCodes.Call, LuaAPI_lua_getref);

            if (isObj)
            {
                //LuaAPI.lua_pushstring(L, "xxx");
                il.Emit(OpCodes.Ldloc, L);
                il.Emit(OpCodes.Ldstr, to_be_impl.Name);
                il.Emit(OpCodes.Call, LuaAPI_lua_pushstring);

                //LuaAPI.xlua_pgettable(L, -2)
                il.Emit(OpCodes.Ldloc, L);
                il.Emit(OpCodes.Ldc_I4_S, (sbyte)-2);
                il.Emit(OpCodes.Call, LuaAPI_xlua_pgettable);
                Label gettable_no_exception = il.DefineLabel();
                il.Emit(OpCodes.Brfalse, gettable_no_exception);

                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldfld, LuaBase_luaEnv);
                il.Emit(OpCodes.Ldloc, err_func);
                il.Emit(OpCodes.Ldc_I4_1);
                il.Emit(OpCodes.Sub);
                il.Emit(OpCodes.Callvirt, LuaEnv_ThrowExceptionFromError);
                il.MarkLabel(gettable_no_exception);

                //LuaAPI.lua_pushvalue(L, -2);
                il.Emit(OpCodes.Ldloc, L);
                il.Emit(OpCodes.Ldc_I4_S, (sbyte)-2);
                il.Emit(OpCodes.Call, LuaAPI_lua_pushvalue);

                //LuaAPI.lua_remove(L, -3);
                il.Emit(OpCodes.Ldloc, L);
                il.Emit(OpCodes.Ldc_I4_S, (sbyte)-3);
                il.Emit(OpCodes.Call, LuaAPI_lua_remove);
            }

            int in_param_count = 0;
            int out_param_count = 0;
            bool has_params = false;
            //translator.PushAny(L, param_in)
            for (int i = 0; i < parameters.Length; ++i)
            {
                var pinfo = parameters[i];
                if (!pinfo.IsOut)
                {
                    var ptype = pinfo.ParameterType;
                    bool isParam = pinfo.IsDefined(typeof(ParamArrayAttribute), false);
                    emitPush(il, ptype, (short)(i + 1), isParam, L, translator, true);
                    if (isParam)
                    {
                        has_params = true;
                    }
                    else
                    {
                        ++in_param_count;
                    }
                }

                if (pinfo.ParameterType.IsByRef)
                {
                    ++out_param_count;
                }
            }

            il.Emit(OpCodes.Ldloc, L);
            il.Emit(OpCodes.Ldc_I4, in_param_count + (isObj ? 1 : 0));
            if (has_params)
            {
                Label l1 = il.DefineLabel();

                il.Emit(OpCodes.Ldarg, (short)parameters.Length);
                il.Emit(OpCodes.Brfalse, l1);

                il.Emit(OpCodes.Ldarg, (short)parameters.Length);
                il.Emit(OpCodes.Ldlen);
                il.Emit(OpCodes.Add);
                il.MarkLabel(l1);
            }
            il.Emit(OpCodes.Ldc_I4, out_param_count + (has_return ? 1 : 0));
            il.Emit(OpCodes.Ldloc, err_func);
            il.Emit(OpCodes.Call, LuaAPI_lua_pcall);
            Label no_exception = il.DefineLabel();
            il.Emit(OpCodes.Brfalse, no_exception);

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldfld, LuaBase_luaEnv);
            il.Emit(OpCodes.Ldloc, err_func);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Sub);
            il.Emit(OpCodes.Callvirt, LuaEnv_ThrowExceptionFromError);
            il.MarkLabel(no_exception);

            int offset = 1;
            if (has_return)
            {
                EmitGetObject(il, offset++, to_be_impl.ReturnType, L, translator, err_func);
                il.Emit(OpCodes.Stloc, ret);
            }

            for (int i = 0; i < parameters.Length; ++i)
            {
                var pinfo = parameters[i];
                var ptype = pinfo.ParameterType;
                if (ptype.IsByRef)
                {
                    il.Emit(OpCodes.Ldarg, (short)(i + 1));
                    var pelemtype = ptype.GetElementType();
                    EmitGetObject(il, offset++, pelemtype, L, translator, err_func);
                    if (pelemtype.IsValueType)
                    {
                        il.Emit(OpCodes.Stobj, pelemtype);
                    }
                    else
                    {
                        il.Emit(OpCodes.Stind_Ref);
                    }

                }
            }

            if (has_return)
            {
                il.Emit(OpCodes.Ldloc, ret);
            }

            //LuaAPI.lua_settop(L, err_func - 1);
            il.Emit(OpCodes.Ldloc, L);
            il.Emit(OpCodes.Ldloc, err_func);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Sub);
            il.Emit(OpCodes.Call, LuaAPI_lua_settop);

            il.Emit(OpCodes.Ret);
        }

        private MethodInfo ObjectTranslatorPool_FindTranslator = typeof(ObjectTranslatorPool).GetMethod("FindTranslator");
        private Type[] parameterTypeOfWrap = new Type[] { typeof(RealStatePtr) };
        private MethodInfo ObjectTranslator_Assignable = typeof(ObjectTranslator).GetMethod("Assignable", new Type[] { typeof(RealStatePtr),
               typeof(int), typeof(Type)});

        private MethodInfo Utils_BeginObjectRegister = typeof(Utils).GetMethod("BeginObjectRegister");
        private MethodInfo Utils_EndObjectRegister = typeof(Utils).GetMethod("EndObjectRegister");
        private MethodInfo Utils_BeginClassRegister = typeof(Utils).GetMethod("BeginClassRegister");
        private MethodInfo Utils_EndClassRegister = typeof(Utils).GetMethod("EndClassRegister");
        private MethodInfo Utils_RegisterFunc = typeof(Utils).GetMethod("RegisterFunc");
        private MethodInfo Utils_RegisterObject = typeof(Utils).GetMethod("RegisterObject");

        private ConstructorInfo LuaCSFunction_Constructor = typeof(LuaCSFunction).GetConstructor(new Type[] { typeof(object), typeof(IntPtr) });

        private MethodInfo String_Concat = typeof(string).GetMethod("Concat", new Type[] { typeof(object), typeof(object) });

        void checkType(ILGenerator il, Type type, LocalBuilder translator, int argPos, Label endOfBlock, bool isVParam, bool isDefault)
        {
            Label endOfCheckType = il.DefineLabel();

            if (isVParam || isDefault)
            {
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldc_I4, argPos);
                il.Emit(OpCodes.Call, LuaAPI_lua_type);
                il.Emit(OpCodes.Ldc_I4_M1);
                il.Emit(OpCodes.Beq, endOfCheckType);
            }

            il.Emit(OpCodes.Ldloc, translator);
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldc_I4, argPos);
            il.Emit(OpCodes.Ldtoken, isVParam ? type.GetElementType() : type);
            il.Emit(OpCodes.Call, Type_GetTypeFromHandle); // typeof(DeclaringType)
            il.Emit(OpCodes.Callvirt, ObjectTranslator_Assignable);
            il.Emit(OpCodes.Brfalse, endOfBlock);

            il.MarkLabel(endOfCheckType);
        }

        void emitRegisterFunc(ILGenerator il, MethodBuilder method, int index, string name)
        {
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldc_I4, index);
            il.Emit(OpCodes.Ldstr, name);
            il.Emit(OpCodes.Ldnull);
            il.Emit(OpCodes.Ldftn, method);
            il.Emit(OpCodes.Newobj, LuaCSFunction_Constructor);
            il.Emit(OpCodes.Call, Utils_RegisterFunc);
        }

        void emitCatchBlock(ILGenerator il, LocalBuilder ex, LocalBuilder wrapRet, Label retPoint, Label exceptionBlock)
        {
            il.BeginCatchBlock(typeof(Exception));
            il.Emit(OpCodes.Stloc, ex);
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldstr, "c# exception:");
            il.Emit(OpCodes.Ldloc, ex);
            il.Emit(OpCodes.Call, String_Concat);
            il.Emit(OpCodes.Call, LuaAPI_luaL_error);
            il.Emit(OpCodes.Stloc, wrapRet);
            il.Emit(OpCodes.Leave, retPoint);
            il.Emit(OpCodes.Leave, exceptionBlock);

            il.EndExceptionBlock();
        }

        public MethodBuilder emitFieldWrap(TypeBuilder typeBuilder, FieldInfo field, bool genGetter)
        {
            MethodBuilder methodBuilder = typeBuilder.DefineMethod(field.Name + (genID++), MethodAttributes.Static, typeof(int), parameterTypeOfWrap);
            methodBuilder.DefineParameter(1, ParameterAttributes.None, "L");

            ILGenerator il = methodBuilder.GetILGenerator();

            LocalBuilder L = il.DeclareLocal(typeof(RealStatePtr));
            LocalBuilder translator = il.DeclareLocal(typeof(ObjectTranslator));
            LocalBuilder fieldStore = il.DeclareLocal(field.FieldType);
            LocalBuilder wrapRet = il.DeclareLocal(typeof(int));
            LocalBuilder ex = il.DeclareLocal(typeof(Exception));

            Label exceptionBlock = il.BeginExceptionBlock();
            Label retPoint = il.DefineLabel();

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Stloc, L);

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Call, ObjectTranslatorPool_FindTranslator);
            il.Emit(OpCodes.Stloc, translator);

            if (genGetter)
            {
                if (!field.IsStatic)
                {
                    EmitGetObject(il, 1, field.DeclaringType, L, translator, null);
                    il.Emit(OpCodes.Ldfld, field);
                }
                else
                {
                    il.Emit(OpCodes.Ldsfld, field);
                }
                il.Emit(OpCodes.Stloc, fieldStore);
                emitPush(il, field.FieldType, 2, false, L, translator, false);
            }
            else
            {
                if (!field.IsStatic)
                {
                    EmitGetObject(il, 1, field.DeclaringType, L, translator, null);
                    LocalBuilder self = null;
                    if (field.DeclaringType.IsValueType)
                    {
                        self = il.DeclareLocal(field.DeclaringType);
                        il.Emit(OpCodes.Stloc, self);
                        il.Emit(OpCodes.Ldloca, self);
                    }
                    EmitGetObject(il, 2, field.FieldType, L, translator, null);
                    il.Emit(OpCodes.Stfld, field);
                    if (self != null)
                    {
                        emitUpdateIfNeeded(il, L, translator, field.DeclaringType, 1, self.LocalIndex);
                    }
                }
                else
                {
                    EmitGetObject(il, 1, field.FieldType, L, translator, null);
                    il.Emit(OpCodes.Stsfld, field);
                }
            }

            il.Emit(OpCodes.Leave, exceptionBlock);

            emitCatchBlock(il, ex, wrapRet, retPoint, exceptionBlock);

            il.Emit(genGetter ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
            il.Emit(OpCodes.Ret);

            il.MarkLabel(retPoint);
            il.Emit(OpCodes.Ldloc, wrapRet);
            il.Emit(OpCodes.Ret);

            return methodBuilder;
        }

        public MethodBuilder emitPropertyWrap(TypeBuilder typeBuilder, PropertyInfo prop, MethodInfo op, bool genGetter)
        {
            MethodBuilder methodBuilder = typeBuilder.DefineMethod(prop.Name + (genID++), MethodAttributes.Static, typeof(int), parameterTypeOfWrap);
            methodBuilder.DefineParameter(1, ParameterAttributes.None, "L");

            ILGenerator il = methodBuilder.GetILGenerator();

            LocalBuilder L = il.DeclareLocal(typeof(RealStatePtr));
            LocalBuilder translator = il.DeclareLocal(typeof(ObjectTranslator));
            LocalBuilder propStore = il.DeclareLocal(prop.PropertyType);
            LocalBuilder wrapRet = il.DeclareLocal(typeof(int));
            LocalBuilder ex = il.DeclareLocal(typeof(Exception));

            Label exceptionBlock = il.BeginExceptionBlock();
            Label retPoint = il.DefineLabel();

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Stloc, L);

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Call, ObjectTranslatorPool_FindTranslator);
            il.Emit(OpCodes.Stloc, translator);

            if (genGetter)
            {
                if (!op.IsStatic)
                {
                    EmitGetObject(il, 1, prop.DeclaringType, L, translator, null);
                    if (prop.DeclaringType.IsValueType)
                    {
                        var self = il.DeclareLocal(prop.DeclaringType);
                        il.Emit(OpCodes.Stloc, self);
                        il.Emit(OpCodes.Ldloca, self);
                        il.Emit(OpCodes.Call, op);
                        emitUpdateIfNeeded(il, L, translator, prop.DeclaringType, 1, self.LocalIndex);
                    }
                    else
                    {
                        il.Emit(OpCodes.Callvirt, op);
                    }
                }
                else
                {
                    il.Emit(OpCodes.Call, op);
                }
                il.Emit(OpCodes.Stloc, propStore);
                emitPush(il, prop.PropertyType, (short)propStore.LocalIndex, false, L, translator, false);
            }
            else
            {
                if (!op.IsStatic)
                {
                    EmitGetObject(il, 1, prop.DeclaringType, L, translator, null);
                    LocalBuilder self = null;
                    if (prop.DeclaringType.IsValueType)
                    {
                        self = il.DeclareLocal(prop.DeclaringType);
                        il.Emit(OpCodes.Stloc, self);
                        il.Emit(OpCodes.Ldloca, self);
                    }
                    EmitGetObject(il, 2, prop.PropertyType, L, translator, null);
                    il.Emit(prop.DeclaringType.IsValueType ? OpCodes.Call : OpCodes.Callvirt, op);
                    if (self != null)
                    {
                        emitUpdateIfNeeded(il, L, translator, prop.DeclaringType, 1, self.LocalIndex);
                    }
                }
                else
                {
                    EmitGetObject(il, 1, prop.PropertyType, L, translator, null);
                    il.Emit(OpCodes.Call, op);
                }
            }

            il.Emit(OpCodes.Leave, exceptionBlock);

            emitCatchBlock(il, ex, wrapRet, retPoint, exceptionBlock);

            il.Emit(genGetter ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
            il.Emit(OpCodes.Ret);

            il.MarkLabel(retPoint);
            il.Emit(OpCodes.Ldloc, wrapRet);
            il.Emit(OpCodes.Ret);

            return methodBuilder;
        }

        static HashSet<MemberInfo> BlackList = new HashSet<MemberInfo>();

        static void addToBlackList(List<string> info)
        {
            try
            {
                var type = Type.GetType(info[0], true);
                var members = type.GetMember(info[1], BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly);
                foreach(var member in members)
                {
                    if (member.MemberType == MemberTypes.Method)
                    {
                        var mb = member as MethodBase;
                        var parameters = mb.GetParameters();
                        if (parameters.Length != info.Count - 2)
                        {
                            continue;
                        }

                        bool paramsMatch = true;

                        for (int i = 0; i < parameters.Length; i++)
                        {
                            if (parameters[i].ParameterType.FullName != info[i + 2])
                            {
                                paramsMatch = false;
                                break;
                            }
                        }
                        if (paramsMatch)
                        {
                            BlackList.Add(member);
                        }
                    }
                    else if (info.Count == 2)
                    {
                        BlackList.Add(member);
                    }
                }
            } catch { }
        }

        static void initBlackList()
        {
            foreach (var t in Utils.GetAllTypes(true))
            {
                if (!t.IsAbstract || !t.IsSealed) continue;

                var fields = t.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
                for (int i = 0; i < fields.Length; i++)
                {
                    var field = fields[i];
                    if (field.IsDefined(typeof(BlackListAttribute), false)
                        && (typeof(List<List<string>>)).IsAssignableFrom(field.FieldType))
                    {
                        foreach (var info in (field.GetValue(null) as List<List<string>>))
                        {
                            addToBlackList(info);
                        }
                    }
                }

                var props = t.GetProperties(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
                for (int i = 0; i < props.Length; i++)
                {
                    var prop = props[i];
                    if (prop.IsDefined(typeof(BlackListAttribute), false)
                        && (typeof(List<List<string>>)).IsAssignableFrom(prop.PropertyType))
                    {
                        foreach (var info in (prop.GetValue(null, null) as List<List<string>>))
                        {
                            addToBlackList(info);
                        }
                    }
                }
            }
        }

        static bool isMemberInBlackList(MemberInfo mb)
        {
            if (mb is FieldInfo && (mb as FieldInfo).FieldType.IsPointer) return true;
            if (mb is PropertyInfo && (mb as PropertyInfo).PropertyType.IsPointer) return true;

            if (mb.IsDefined(typeof(BlackListAttribute), false)) return true;

            return BlackList.Contains(mb);
        }

        static bool isMethodInBlackList(MethodBase mb)
        {
            if (mb.GetParameters().Any(pInfo => pInfo.ParameterType.IsPointer)) return true;
            if (mb is MethodInfo && (mb as MethodInfo).ReturnType.IsPointer) return false;

            if (mb.IsDefined(typeof(BlackListAttribute), false)) return true;

            return BlackList.Contains(mb);
        }

        public Type EmitTypeWrap(Type toBeWrap)
        {
            TypeBuilder wrapTypeBuilder = CodeEmitModule.DefineType(toBeWrap.Name + "Wrap" + (genID++), TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Abstract | TypeAttributes.Sealed);

            var methodBuilder = wrapTypeBuilder.DefineMethod("__Register", MethodAttributes.Static | MethodAttributes.Public, null, parameterTypeOfWrap);
            methodBuilder.DefineParameter(1, ParameterAttributes.None, "L");

            ILGenerator il = methodBuilder.GetILGenerator();

            LocalBuilder translator = il.DeclareLocal(typeof(ObjectTranslator));

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Call, ObjectTranslatorPool_FindTranslator);
            il.Emit(OpCodes.Stloc, translator);

            var instanceFlag = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly;
            var staticFlag = BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly;

            var instanceFields = toBeWrap.GetFields(instanceFlag).Where(m => !isMemberInBlackList(m));
            var instanceProperties = toBeWrap.GetProperties(instanceFlag).Where(m => !isMemberInBlackList(m));
            var extensionMethods = Utils.GetExtensionMethodsOf(toBeWrap);
            extensionMethods = (extensionMethods == null) ? Enumerable.Empty<MethodInfo>() : extensionMethods.Where(m => !isMemberInBlackList(m));
            var instanceMethods = toBeWrap.GetMethods(instanceFlag)
                .Where(m => !isMethodInBlackList(m))
                .Concat(extensionMethods)
                .Where(m => Utils.IsSupportedMethod(m))
                .Where(m => !m.IsSpecialName
                    || (
                         ((m.Name == "get_Item" && m.GetParameters().Length == 1) || (m.Name == "set_Item" && m.GetParameters().Length == 2))
                         && m.GetParameters()[0].ParameterType.IsAssignableFrom(typeof(string))
                       )
                ).GroupBy(m => m.Name).ToList();
            var supportOperators = toBeWrap.GetMethods(staticFlag)
                .Where(m => !isMethodInBlackList(m))
                .Where(m => m.IsSpecialName && InternalGlobals.supportOp.ContainsKey(m.Name))
                .GroupBy(m => m.Name);

            //begin obj
            il.Emit(OpCodes.Ldtoken, toBeWrap);
            il.Emit(OpCodes.Call, Type_GetTypeFromHandle); // typeof(type)
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldloc, translator);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Ldc_I4_M1);
            il.Emit(OpCodes.Call, Utils_BeginObjectRegister);

            foreach(var field in instanceFields)
            {
                emitRegisterFunc(il, emitFieldWrap(wrapTypeBuilder, field, true), Utils.GETTER_IDX, field.Name);
                emitRegisterFunc(il, emitFieldWrap(wrapTypeBuilder, field, false), Utils.SETTER_IDX, field.Name);
            }

            List<MethodBase> itemGetter = new List<MethodBase>();
            List<MethodBase> itemSetter = new List<MethodBase>();

            foreach(var prop in instanceProperties)
            {
                var getter = prop.GetGetMethod();
                if (getter != null && getter.IsPublic)
                {
                    if (prop.GetIndexParameters().Length > 0)
                    {
                        if (!prop.GetIndexParameters()[0].ParameterType.IsAssignableFrom(typeof(string)))
                        {
                            itemGetter.Add(getter);
                        }
                    }
                    else
                    {
                        emitRegisterFunc(il, emitPropertyWrap(wrapTypeBuilder, prop, getter, true), Utils.GETTER_IDX, prop.Name);
                    }
                }

                var setter = prop.GetSetMethod();
                if (setter != null && setter.IsPublic)
                {
                    if (prop.GetIndexParameters().Length > 0)
                    {
                        if (!prop.GetIndexParameters()[0].ParameterType.IsAssignableFrom(typeof(string)))
                        {
                            itemSetter.Add(setter);
                        }
                    }
                    else
                    {
                        emitRegisterFunc(il, emitPropertyWrap(wrapTypeBuilder, prop, setter, false), Utils.SETTER_IDX, prop.Name);
                    }
                }
            }

            foreach (var group in instanceMethods)
            {
                emitRegisterFunc(il, emitMethodWrap(wrapTypeBuilder, group.Cast<MethodBase>().ToList(), false, toBeWrap), Utils.METHOD_IDX, group.Key);
            }

            foreach (var group in supportOperators)
            {
                emitRegisterFunc(il, emitMethodWrap(wrapTypeBuilder, group.Cast<MethodBase>().ToList(), false, toBeWrap), Utils.OBJ_META_IDX, InternalGlobals.supportOp[group.Key]);
            }

            foreach (var ev in toBeWrap.GetEvents(instanceFlag).Where(m => !isMemberInBlackList(m)))
            {
                emitRegisterFunc(il, emitEventWrap(wrapTypeBuilder, ev), Utils.METHOD_IDX, ev.Name);
            }

            //end obj
            il.Emit(OpCodes.Ldtoken, toBeWrap);
            il.Emit(OpCodes.Call, Type_GetTypeFromHandle); // typeof(type)
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldloc, translator);
            il.Emit(OpCodes.Ldnull);
            if (itemGetter.Count > 0)
            {
                il.Emit(OpCodes.Ldftn, emitMethodWrap(wrapTypeBuilder, itemGetter, true, toBeWrap));
                il.Emit(OpCodes.Newobj, LuaCSFunction_Constructor);
            }
            il.Emit(OpCodes.Ldnull);
            if (itemSetter.Count > 0)
            {
                il.Emit(OpCodes.Ldftn, emitMethodWrap(wrapTypeBuilder, itemSetter, true, toBeWrap));
                il.Emit(OpCodes.Newobj, LuaCSFunction_Constructor);
            }
            il.Emit(OpCodes.Ldnull);
            il.Emit(OpCodes.Ldnull);
            il.Emit(OpCodes.Ldnull);
            il.Emit(OpCodes.Call, Utils_EndObjectRegister);

            // begin class
            il.Emit(OpCodes.Ldtoken, toBeWrap);
            il.Emit(OpCodes.Call, Type_GetTypeFromHandle); // typeof(type)
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldnull);
            il.Emit(OpCodes.Ldftn, emitMethodWrap(wrapTypeBuilder,
                toBeWrap.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase)
                .Where(m => !isMethodInBlackList(m))
                .Cast<MethodBase>().ToList(), false, toBeWrap, toBeWrap.ToString() + " constructor"));
            il.Emit(OpCodes.Newobj, LuaCSFunction_Constructor);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Call, Utils_BeginClassRegister);

            var staticMethods = toBeWrap.GetMethods(staticFlag)
                .Where(m => !isMethodInBlackList(m))
                .Where(m => Utils.IsSupportedMethod(m))
                .Where(m => !m.IsSpecialName).GroupBy(m => m.Name);

            var staticFields = toBeWrap.GetFields(staticFlag).Where(m => !isMemberInBlackList(m));

            var staticProperties = toBeWrap.GetProperties(staticFlag).Where(m => !isMemberInBlackList(m));

            foreach (var group in staticMethods)
            {
                emitRegisterFunc(il, emitMethodWrap(wrapTypeBuilder, group.Cast<MethodBase>().ToList(), false, toBeWrap), Utils.CLS_IDX, group.Key);
            }

            foreach (var ev in toBeWrap.GetEvents(staticFlag).Where(m => !isMemberInBlackList(m)))
            {
                emitRegisterFunc(il, emitEventWrap(wrapTypeBuilder, ev), Utils.CLS_IDX, ev.Name);
            }

            foreach (var prop in staticProperties)
            {
                var getter = prop.GetGetMethod();
                if (getter != null && getter.IsPublic)
                {
                    emitRegisterFunc(il, emitPropertyWrap(wrapTypeBuilder, prop, getter, true), Utils.GETTER_IDX, prop.Name);
                }

                var setter = prop.GetSetMethod();
                if (setter != null && setter.IsPublic)
                {
                    emitRegisterFunc(il, emitPropertyWrap(wrapTypeBuilder, prop, setter, false), Utils.SETTER_IDX, prop.Name);
                }
            }

            foreach (var field in staticFields)
            {
                if (field.IsInitOnly || field.IsLiteral)
                {
                    il.Emit(OpCodes.Ldarg_0);
                    il.Emit(OpCodes.Ldloc, translator);
                    il.Emit(OpCodes.Ldc_I4, Utils.CLS_IDX);
                    il.Emit(OpCodes.Ldstr, field.Name);
                    if (field.IsLiteral)
                    {
                        LocalBuilder literalStore = il.DeclareLocal(field.FieldType);
                        emitLiteralLoad(il, field.FieldType, field.GetValue(null), literalStore.LocalIndex);
                        il.Emit(OpCodes.Stloc, literalStore);
                        il.Emit(OpCodes.Ldloc, literalStore);
                    }
                    else
                    {
                        il.Emit(OpCodes.Ldsfld, field);
                    }
                    if (field.FieldType.IsValueType)
                    {
                        il.Emit(OpCodes.Box, field.FieldType);
                    }
                    il.Emit(OpCodes.Call, Utils_RegisterObject);
                }
                else
                {
                    emitRegisterFunc(il, emitFieldWrap(wrapTypeBuilder, field, true), Utils.CLS_GETTER_IDX, field.Name);
                    emitRegisterFunc(il, emitFieldWrap(wrapTypeBuilder, field, false), Utils.CLS_SETTER_IDX, field.Name);
                }
            }

            //end class
            il.Emit(OpCodes.Ldtoken, toBeWrap);
            il.Emit(OpCodes.Call, Type_GetTypeFromHandle); // typeof(type)
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldloc, translator);
            il.Emit(OpCodes.Call, Utils_EndClassRegister);

            il.Emit(OpCodes.Ret);

            return wrapTypeBuilder.CreateType();
        }

        MethodBuilder emitEventWrap(TypeBuilder typeBuilder, EventInfo ev)
        {
            var addEvent = ev.GetAddMethod();
            var removeEvent = ev.GetRemoveMethod();

            if (addEvent == null && removeEvent == null)
            {
                return null;
            }

            bool isStatic = addEvent != null ? addEvent.IsStatic : removeEvent.IsStatic;

            var methodBuilder = typeBuilder.DefineMethod(ev.Name + (genID++), MethodAttributes.Static, typeof(int), parameterTypeOfWrap);
            methodBuilder.DefineParameter(1, ParameterAttributes.None, "L");

            ILGenerator il = methodBuilder.GetILGenerator();

            LocalBuilder wrapRet = il.DeclareLocal(typeof(int));
            LocalBuilder ex = il.DeclareLocal(typeof(Exception));
            LocalBuilder L = il.DeclareLocal(typeof(RealStatePtr));
            LocalBuilder translator = il.DeclareLocal(typeof(ObjectTranslator));
            LocalBuilder callback = il.DeclareLocal(ev.EventHandlerType);

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Stloc, L);

            Label exceptionBlock = il.BeginExceptionBlock();
            Label retPoint = il.DefineLabel();

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Call, ObjectTranslatorPool_FindTranslator);
            il.Emit(OpCodes.Stloc, translator);

            EmitGetObject(il, isStatic ? 2 : 3, ev.EventHandlerType, L, translator, null);
            il.Emit(OpCodes.Stloc, callback);
            il.Emit(OpCodes.Ldloc, callback);
            Label ifBlock = il.DefineLabel();
            il.Emit(OpCodes.Brtrue, ifBlock);

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldstr, string.Format("#{0}, need {1}", isStatic ? 2 : 3, ev.EventHandlerType));
            il.Emit(OpCodes.Call, LuaAPI_luaL_error);
            il.Emit(OpCodes.Stloc, wrapRet);
            il.Emit(OpCodes.Leave, retPoint);
            il.MarkLabel(ifBlock);

            if (addEvent != null)
            {
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(isStatic ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_2);
                il.Emit(OpCodes.Ldstr, "+");
                il.Emit(OpCodes.Call, LuaAPI_xlua_is_eq_str);
                ifBlock = il.DefineLabel();
                il.Emit(OpCodes.Brfalse, ifBlock);

                if (!isStatic)
                {
                    EmitGetObject(il, 1, ev.DeclaringType, L, translator, null);
                    if (ev.DeclaringType.IsValueType)
                    {
                        var self = il.DeclareLocal(ev.DeclaringType);
                        il.Emit(OpCodes.Stloc, self);
                        il.Emit(OpCodes.Ldloca, self);
                    }
                }
                il.Emit(OpCodes.Ldloc, callback);
                il.Emit(OpCodes.Call, addEvent);
                il.Emit(OpCodes.Ldc_I4_0);
                il.Emit(OpCodes.Leave, retPoint);
                il.MarkLabel(ifBlock);
            }

            if (removeEvent != null)
            {
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(isStatic ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_2);
                il.Emit(OpCodes.Ldstr, "-");
                il.Emit(OpCodes.Call, LuaAPI_xlua_is_eq_str);
                ifBlock = il.DefineLabel();
                il.Emit(OpCodes.Brfalse, ifBlock);

                if (!isStatic)
                {
                    EmitGetObject(il, 1, ev.DeclaringType, L, translator, null);
                    if (ev.DeclaringType.IsValueType)
                    {
                        var self = il.DeclareLocal(ev.DeclaringType);
                        il.Emit(OpCodes.Stloc, self);
                        il.Emit(OpCodes.Ldloca, self);
                    }
                }
                il.Emit(OpCodes.Ldloc, callback);
                il.Emit(OpCodes.Call, removeEvent);
                il.Emit(OpCodes.Ldc_I4_0);
                il.Emit(OpCodes.Leave, retPoint);
                il.MarkLabel(ifBlock);
            }

            il.Emit(OpCodes.Leave, exceptionBlock);

            emitCatchBlock(il, ex, wrapRet, retPoint, exceptionBlock);

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldstr, "invalid arguments to " + ev.DeclaringType + "." + ev.Name + "!");
            il.Emit(OpCodes.Call, LuaAPI_luaL_error);
            il.Emit(OpCodes.Ret);

            il.MarkLabel(retPoint);
            il.Emit(OpCodes.Ldloc, wrapRet);
            il.Emit(OpCodes.Ret);

            return methodBuilder;
        }

        void emitUpdateIfNeeded(ILGenerator il, LocalBuilder L, LocalBuilder translator, Type type, int luaIndex, int localIndex)
        {
            if (type.IsValueType && !type.IsPrimitive && !type.IsEnum && type != typeof(decimal))
            {
                //UnityEngine.Debug.LogWarning("-----------------emit update:" + type);
                il.Emit(OpCodes.Ldloc, translator);
                il.Emit(OpCodes.Ldloc, L);
                il.Emit(OpCodes.Ldc_I4, luaIndex);
                il.Emit(OpCodes.Ldloc, localIndex);
                il.Emit(OpCodes.Box, type);
                il.Emit(OpCodes.Callvirt, ObjectTranslator_Update);
            }
        }

        //private MethodInfo UnityEngine_Debug_Log = typeof(UnityEngine.Debug).GetMethod("Log", new Type[] { typeof(object)});
        int firstDefaultValue(MethodBase method)
        {
            var parameters = method.GetParameters();
            for(int i = 0; i < parameters.Length; i++)
            {
                if (parameters[i].IsOptional) return i;
            }
            return -1;
        }

        MethodBuilder emitMethodWrap(TypeBuilder typeBuilder, List<MethodBase> methodsToCall, bool isIndexer, Type declaringType, string methodDesciption = null)
        {
            string wrapName = (methodsToCall.Count > 0 ? methodsToCall[0].Name : "Constructor");
            var methodBuilder = typeBuilder.DefineMethod(wrapName + (genID++), MethodAttributes.Static, typeof(int), parameterTypeOfWrap);
            methodBuilder.DefineParameter(1,  ParameterAttributes.None, "L");

            bool needCheckParameterType = (methodsToCall.Count > 1)  || isIndexer;

            if (methodsToCall.Count == 0 || methodsToCall[0].IsConstructor)
            {
                needCheckParameterType = true;
            }

            if (methodsToCall.Count == 1 && firstDefaultValue(methodsToCall[0]) != -1)
            {
                needCheckParameterType = true;
            }

            ILGenerator il = methodBuilder.GetILGenerator();

            LocalBuilder wrapRet = il.DeclareLocal(typeof(int));
            LocalBuilder ex = il.DeclareLocal(typeof(Exception));
            LocalBuilder L = il.DeclareLocal(typeof(RealStatePtr));
            LocalBuilder translator = il.DeclareLocal(typeof(ObjectTranslator));
            LocalBuilder top = il.DeclareLocal(typeof(int));

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Stloc, L);

            Label exceptionBlock = il.BeginExceptionBlock();
            Label retPoint = il.DefineLabel();
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Call, ObjectTranslatorPool_FindTranslator);
            il.Emit(OpCodes.Stloc, translator);

            if (needCheckParameterType)
            {
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Call, LuaAPI_lua_gettop);
                il.Emit(OpCodes.Stloc, top);
            }

            for (int i = 0; i < methodsToCall.Count; i++)
            {
                var method = methodsToCall[i];
                if ((method is MethodInfo) && method.ContainsGenericParameters)
                {
                    method = Utils.MakeGenericMethodWithConstraints(method as MethodInfo);
                }
                bool isStatic = method.IsStatic;
                var paramInfos = method.GetParameters();
                int minInParamCount = 0;
                int maxInParamCount = 0;
                int outParamCount = 0;
                bool hasParams = paramInfos.Length > 0 && paramInfos[paramInfos.Length - 1].IsDefined(typeof(ParamArrayAttribute), false);
                bool hasOptional = false;

                LocalBuilder methodReturn = null;

                for (int j = 0; j < paramInfos.Length; j++)
                {
                    if (!paramInfos[j].IsOut)
                    {
                        if (!paramInfos[j].IsOptional && (!hasParams || j != paramInfos.Length - 1))
                        {
                            minInParamCount++;
                        }
                        maxInParamCount++;
                    }
                    if (paramInfos[j].IsOptional)
                    {
                        hasOptional = true;
                    }
                    if (paramInfos[j].ParameterType.IsByRef)
                    {
                        outParamCount++;
                    }
                }

                Label endOfBlock = il.DefineLabel();

                if (needCheckParameterType)
                {
                    il.Emit(OpCodes.Ldloc, top);
                    il.Emit(OpCodes.Ldc_I4, minInParamCount + (isStatic ? 0 : 1));
                    il.Emit((hasParams || hasOptional) ? OpCodes.Blt : OpCodes.Bne_Un, endOfBlock);

                    if (hasOptional && !hasParams)
                    {
                        il.Emit(OpCodes.Ldloc, top);
                        il.Emit(OpCodes.Ldc_I4, maxInParamCount + (isStatic ? 0 : 1));
                        il.Emit(OpCodes.Bgt, endOfBlock);
                    }
                    
                    if (!isStatic && !method.IsConstructor)
                    {
                        checkType(il, method.DeclaringType, translator, 1, endOfBlock, false, false);
                    }

                    int argPos = isStatic ? 1 : 2;

                    for (int j = 0; j < paramInfos.Length; j++)
                    {
                        var paramInfo = paramInfos[j];
                        if (!paramInfo.IsOut)
                        {
                            var rawParamType = paramInfo.ParameterType;
                            if (rawParamType.IsByRef)
                            {
                                rawParamType = rawParamType.GetElementType();
                            }
                            checkType(il, rawParamType, translator, argPos++, endOfBlock, 
                                hasParams && (j == paramInfos.Length - 1), paramInfo.IsOptional);
                        }
                    }
                }

                int luaPos = isStatic ? 1 : 2;

                int argStoreStart = -1;

                for (int j = 0; j < paramInfos.Length; j++)
                {
                    var paramInfo = paramInfos[j];
                    var paramRawType = paramInfo.ParameterType.IsByRef ? paramInfo.ParameterType.GetElementType() :
                        paramInfo.ParameterType;
                    var argStore = il.DeclareLocal(paramRawType);
                    if (paramInfo.IsOptional)
                    {
                        //UnityEngine.Debug.Log(paramInfo.Name + "," + paramRawType + "," + paramInfo.DefaultValue);
                        emitLiteralLoad(il, paramRawType, paramInfo.DefaultValue, argStore.LocalIndex);
                        il.Emit(OpCodes.Stloc, argStore);
                    }
                    //UnityEngine.Debug.LogWarning(declaringType.Name + "." + method.Name + "." + paramInfos[j].Name + " pos(d):" + argStore.LocalIndex + ", pt:" + paramRawType + ", j:" + j);
                    if (argStoreStart == -1)
                    {
                        argStoreStart = argStore.LocalIndex;
                    }
                    
                }
                for (int j = 0; j < paramInfos.Length; j++)
                {
                    var paramInfo = paramInfos[j];
                    var paramRawType = paramInfo.ParameterType.IsByRef ? paramInfo.ParameterType.GetElementType() :
                        paramInfo.ParameterType;
                    if (!paramInfo.IsOut)
                    {
                        Label endOfGetValue = il.DefineLabel();
                        if (paramInfo.IsOptional)
                        {
                            il.Emit(OpCodes.Ldarg_0);
                            il.Emit(OpCodes.Ldc_I4, luaPos);
                            il.Emit(OpCodes.Call, LuaAPI_lua_type);
                            il.Emit(OpCodes.Ldc_I4_M1);
                            il.Emit(OpCodes.Beq, endOfGetValue);
                        }
                        EmitGetObject(il, luaPos++, paramRawType, L, translator, null, hasParams && (j == paramInfos.Length - 1));
                        il.Emit(OpCodes.Stloc, argStoreStart + j);
                        il.MarkLabel(endOfGetValue);
                    }
                }

                LocalBuilder valueTypeTmp = null;

                if (!isStatic && (!method.IsConstructor || method.DeclaringType.IsValueType))
                {
                    if (!method.IsConstructor)
                    {
                        EmitGetObject(il, 1, method.DeclaringType, L, translator, null);
                    }
                    if (method.DeclaringType.IsValueType)
                    {
                        if (method.IsConstructor)
                        {
                            methodReturn = il.DeclareLocal(method.DeclaringType);
                            il.Emit(OpCodes.Ldloca, methodReturn);
                        }
                        else
                        {
                            valueTypeTmp = il.DeclareLocal(method.DeclaringType);
                            il.Emit(OpCodes.Stloc, valueTypeTmp);
                            il.Emit(OpCodes.Ldloca, valueTypeTmp);
                        }
                    }
                }

                for (int j = 0; j < paramInfos.Length; j++)
                {
                    //UnityEngine.Debug.LogWarning(declaringType.Name + "." + method.Name + "." + paramInfos[j].Name +" pos:" + (argStoreStart + j) + ", op:" + (paramInfos[j].ParameterType.IsByRef ? OpCodes.Ldloca : OpCodes.Ldloc) + ", j:" + j );
                    il.Emit(paramInfos[j].ParameterType.IsByRef ? OpCodes.Ldloca : OpCodes.Ldloc, argStoreStart + j);
                }

                if (method.IsConstructor)
                {
                    if (method.DeclaringType.IsValueType)
                    {
                        il.Emit(OpCodes.Call, method as ConstructorInfo);
                    }
                    else
                    {
                        il.Emit(OpCodes.Newobj, method as ConstructorInfo);
                    }
                }
                else
                {
                    il.Emit(isStatic ? OpCodes.Call : OpCodes.Callvirt, method as MethodInfo);
                }

                if (valueTypeTmp != null)
                {
                    emitUpdateIfNeeded(il, L, translator, method.DeclaringType, 1, valueTypeTmp.LocalIndex);
                }

                if (isIndexer)
                {
                    il.Emit(OpCodes.Ldarg_0);
                    il.Emit(OpCodes.Ldc_I4_1);
                    il.Emit(OpCodes.Call, LuaAPI_lua_pushboolean);
                }

                bool hasReturn = false;

                MethodInfo methodInfo = method as MethodInfo;
                if (methodInfo == null || methodInfo.ReturnType != typeof(void))
                {
                    hasReturn = true;
                    Type returnType = methodInfo == null ? method.DeclaringType : methodInfo.ReturnType;
                    if (methodReturn == null)
                    {
                        methodReturn = il.DeclareLocal(returnType);
                        il.Emit(OpCodes.Stloc, methodReturn);
                    }
                    emitPush(il, returnType, (short)methodReturn.LocalIndex, false, L, translator, false);
                }

                int luaIndex = isStatic ? 1 : 2;
                for (int j = 0; j < paramInfos.Length; j++)
                {
                    if (paramInfos[j].ParameterType.IsByRef)
                    {
                        var rawParamType = paramInfos[j].ParameterType.GetElementType();
                        emitPush(il, rawParamType,
                            (short)(argStoreStart + j), false, L, translator, false);
                        if (!paramInfos[j].IsOut)
                        {
                            emitUpdateIfNeeded(il, L, translator, rawParamType, luaIndex, argStoreStart + j);
                        }
                    }
                    if (!paramInfos[j].IsOut)
                    {
                        luaIndex++;
                    }
                }

                il.Emit(OpCodes.Ldc_I4, outParamCount + (hasReturn ? 1 : 0) + (isIndexer ? 1 : 0));
                il.Emit(OpCodes.Stloc, wrapRet);
                il.Emit(OpCodes.Leave, retPoint);
                //il.Emit(OpCodes.Ret);

                if (needCheckParameterType)
                {
                    il.MarkLabel(endOfBlock);
                }
            }

            if (declaringType.IsValueType && (methodsToCall.Count == 0 || methodsToCall[0].IsConstructor))
            {
                Label endOfBlock = il.DefineLabel();
                il.Emit(OpCodes.Ldloc, top);
                il.Emit(OpCodes.Ldc_I4_1);
                il.Emit(OpCodes.Bne_Un, endOfBlock);

                var methodReturn = il.DeclareLocal(declaringType);

                il.Emit(OpCodes.Ldloca, methodReturn);
                il.Emit(OpCodes.Initobj, declaringType);
                emitPush(il, declaringType, (short)methodReturn.LocalIndex, false, L, translator, false);
                il.Emit(OpCodes.Ldc_I4_1);
                il.Emit(OpCodes.Stloc, wrapRet);
                il.Emit(OpCodes.Leave_S, retPoint);
                il.MarkLabel(endOfBlock);
            }

            il.Emit(OpCodes.Leave, exceptionBlock);
            emitCatchBlock(il, ex, wrapRet, retPoint, exceptionBlock);

            if (needCheckParameterType)
            {
                if (isIndexer)
                {
                    il.Emit(OpCodes.Ldarg_0);
                    il.Emit(OpCodes.Ldc_I4_0);
                    il.Emit(OpCodes.Call, LuaAPI_lua_pushboolean);
                    il.Emit(OpCodes.Ldc_I4_1);
                    il.Emit(OpCodes.Ret);
                }
                else
                {
                    il.Emit(OpCodes.Ldarg_0);
                    if (methodDesciption == null)
                    {
                        if (methodsToCall.Count > 0)
                        {
                            methodDesciption = declaringType + "." + methodsToCall[0].Name;
                        }
                        else
                        {
                            methodDesciption = "unknow method in " + declaringType;
                        }
                    }
                    il.Emit(OpCodes.Ldstr, "invalid arguments to " + methodDesciption + "!");
                    il.Emit(OpCodes.Call, LuaAPI_luaL_error);
                    il.Emit(OpCodes.Ret);
                }
            }

            il.MarkLabel(retPoint);
            il.Emit(OpCodes.Ldloc, wrapRet);
            il.Emit(OpCodes.Ret);

            return methodBuilder;
        }
    }
}

#endif

        #region No parameters
        /// <summary>
        ///   <para>Prints <see cref="OpCodes.Add"/>:</para>
        ///   <para>"Add two values, returning a new value."</para>
        /// </summary>
        public static void Add() => Emit((ILOpCode)OpCodes.Add.Value);
        
        /// <summary>
        ///   <para>Prints <see cref="OpCodes.Add_Ovf"/>:</para>
        ///   <para>"Add signed integer values with overflow check."</para>
        /// </summary>
        public static void Add_Ovf() => Emit((ILOpCode)OpCodes.Add_Ovf.Value);
        
        /// <summary>
        ///   <para>Prints <see cref="OpCodes.Add_Ovf_Un"/>:</para>
        ///   <para>"Add unsigned integer values with overflow check."</para>
        /// </summary>
        public static void Add_Ovf_Un() => Emit((ILOpCode)OpCodes.Add_Ovf_Un.Value);
        
        /// <summary>
        ///   <para>Prints <see cref="OpCodes.And"/>:</para>
        ///   <para>"Bitwise AND of two integral values, returns an integral value."</para>
        /// </summary>
        public static void And() => Emit((ILOpCode)OpCodes.And.Value);
        
        /// <summary>
        ///   <para>Prints <see cref="OpCodes.Arglist"/>:</para>
        ///   <para>"Return argument list handle for the current method."</para>
        /// </summary>
        public static void Arglist() => Emit((ILOpCode)OpCodes.Arglist.Value);
        
        /// <summary>
        ///   <para>Prints <see cref="OpCodes.Break"/>:</para>
        ///   <para>"Inform a debugger that a breakpoint has been reached."</para>
        /// </summary>
        public static void Break() => Emit((ILOpCode)OpCodes.Break.Value);


        private static void MethodBodSetp1(GeneratorContext context, ILGenerator generator)
        {
            if (context.Parameters.Length == 0)
                return;

            generator.Emit(OpCodes.Newobj, context.DisplayConstructor);
            generator.Emit(OpCodes.Stloc_0);
            generator.Emit(OpCodes.Ldloc_0);
            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Stfld, context.DisplayFields[0]);
        }


        /// <summary>
        /// Is this instruction a local load-by-value instruction.
        /// </summary>
        public static bool IsLocalLoad(this OpCode opcode)
        {
            return opcode == OpCodes.Ldloc || opcode == OpCodes.Ldloc_S || opcode == OpCodes.Ldloc_0 ||
                   opcode == OpCodes.Ldloc_1 || opcode == OpCodes.Ldloc_2 || opcode == OpCodes.Ldloc_3;
        }

        /// <summary>
        /// Is this instruction a local load-by-reference instruction.
        /// </summary>
        public static bool IsLocalLoadByRef(this OpCode opcode)
        {
            return opcode == OpCodes.Ldloca || opcode == OpCodes.Ldloca_S;
        }

        /// <summary>
        /// Is this instruction a local store instruction.
        /// </summary>
        public static bool IsLocalStore(this OpCode opcode)
        {
            return opcode == OpCodes.Stloc || opcode == OpCodes.Stloc_S || opcode == OpCodes.Stloc_0 ||
                   opcode == OpCodes.Stloc_1 || opcode == OpCodes.Stloc_2 || opcode == OpCodes.Stloc_3;
        }

        /// <summary>
        /// Gets an instruction representing a load-by-reference from the given local.
        /// </summary>
        /// <param name="local">Local to load</param>
        /// <returns>Loading instruction</returns>
        public static MsilInstruction AsReferenceLoad(this MsilLocal local)
        {
            return new MsilInstruction(local.Index < 0xFF ? OpCodes.Ldloca_S : OpCodes.Ldloca).InlineValue(local);
        }
        #endregion

        #region Argument Utils
        /// <summary>
        /// Is this instruction an argument load-by-value instruction.
        /// </summary>
        public static bool IsArgumentLoad(this MsilInstruction me)
        {
            return me.OpCode == OpCodes.Ldarg || me.OpCode == OpCodes.Ldarg_S || me.OpCode == OpCodes.Ldarg_0 ||
                   me.OpCode == OpCodes.Ldarg_1 || me.OpCode == OpCodes.Ldarg_2 || me.OpCode == OpCodes.Ldarg_3;
        }

        /// <summary>
        /// Is this instruction an argument load-by-reference instruction.
        /// </summary>
        public static bool IsArgumentLoadByRef(this MsilInstruction me)
        {
            return me.OpCode == OpCodes.Ldarga || me.OpCode == OpCodes.Ldarga_S;
        }


		public static void EmitLoadCopConditionBit( GenerationContext context, int cop )
		{
			Debug.Assert( cop == 1 );
			context.ILGen.Emit( OpCodes.Ldarg_0 );
			context.ILGen.Emit( OpCodes.Ldfld, context.Core0Cp1 );
			context.ILGen.Emit( OpCodes.Call, context.Cp1ConditionBitGet );
		}

		public static void EmitStoreCopConditionBit( GenerationContext context, int cop )
		{
			Debug.Assert( cop == 1 );
			context.ILGen.Emit( OpCodes.Stloc_0 );
			context.ILGen.Emit( OpCodes.Ldarg_0 );
			context.ILGen.Emit( OpCodes.Ldfld, context.Core0Cp1 );
			context.ILGen.Emit( OpCodes.Ldloc_0 );
			context.ILGen.Emit( OpCodes.Conv_U1 );
			context.ILGen.Emit( OpCodes.Call, context.Cp1ConditionBitSet );
		}

			public static GenerationResult LUI( GenerationContext context, int pass, int address, uint code, byte opcode, byte rs, byte rt, ushort imm )
			{
				if( pass == 0 )
				{
					context.WriteRegisters[ rt ] = true;
				}
				else if( pass == 1 )
				{
					context.ILGen.Emit( OpCodes.Ldc_I4, ( int )( ( uint )imm << 16 ) );
					EmitStoreRegister( context, rt );
					//rt.Value = imm << 16;
				}
				return GenerationResult.Success;
			}

			public static GenerationResult BREAK( GenerationContext context, int pass, int address, uint code, byte opcode, byte rs, byte rt, byte rd, byte shamt, byte function )
			{
				if( pass == 0 )
				{
				}
				else if( pass == 1 )
				{
					context.ILGen.Emit( OpCodes.Call, typeof( Debugger ).GetMethod( "Break" ) );
				}
				return GenerationResult.Success;
			}


        internal static void EmitLoadArgAddress(this ILGenerator il, int index) {
            Debug.Assert(index >= 0);

            if (index <= Byte.MaxValue) {
                il.Emit(OpCodes.Ldarga_S, (byte)index);
            } else {
                il.Emit(OpCodes.Ldarga, index);
            }
        }

        internal static void EmitStoreArg(this ILGenerator il, int index) {
            Debug.Assert(index >= 0);

            if (index <= Byte.MaxValue) {
                il.Emit(OpCodes.Starg_S, (byte)index);
            } else {
                il.Emit(OpCodes.Starg, index);
            }
        }

        internal static void EmitType(this ILGenerator il, Type type) {
            ContractUtils.RequiresNotNull(type, "type");

            il.Emit(OpCodes.Ldtoken, type);
            il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"));
        }

        #endregion

        #region Fields, properties and methods

        internal static void EmitFieldAddress(this ILGenerator il, FieldInfo fi) {
            ContractUtils.RequiresNotNull(fi, "fi");

            if (fi.IsStatic) {
                il.Emit(OpCodes.Ldsflda, fi);
            } else {
                il.Emit(OpCodes.Ldflda, fi);
            }
        }

        internal static void EmitFieldGet(this ILGenerator il, FieldInfo fi) {
            ContractUtils.RequiresNotNull(fi, "fi");

            if (fi.IsStatic) {
                il.Emit(OpCodes.Ldsfld, fi);
            } else {
                il.Emit(OpCodes.Ldfld, fi);
            }
        }

        internal static void EmitFieldSet(this ILGenerator il, FieldInfo fi) {
            ContractUtils.RequiresNotNull(fi, "fi");

            if (fi.IsStatic) {
                il.Emit(OpCodes.Stsfld, fi);
            } else {
                il.Emit(OpCodes.Stfld, fi);
            }
        }


        #endregion

        #region Addtional Methods

        public EmitHelper ldelem(Type type)
        {
            _ilGenerator.Emit(OpCodes.Ldelem, type);
            return this;
        }

        public EmitHelper stelem(Type type)
        {
            _ilGenerator.Emit(OpCodes.Stelem, type);
            return this;
        }

        public EmitHelper call(bool isStatic, MethodInfo methodInfo)
        {
            _ilGenerator.Emit(isStatic ? OpCodes.Call : OpCodes.Callvirt, methodInfo);
            return this;
        }

        public EmitHelper ldfld(bool isStatic, FieldInfo fieldInfo)
        {
            _ilGenerator.Emit(isStatic ? OpCodes.Ldsfld : OpCodes.Ldfld, fieldInfo);
            return this;
        }

        public EmitHelper stfld(bool isStatic, FieldInfo fieldInfo)
        {
            _ilGenerator.Emit(isStatic ? OpCodes.Stsfld : OpCodes.Stfld, fieldInfo);
            return this;
        }

        public EmitHelper unbox(Type type)
        {
            _ilGenerator.Emit(OpCodes.Unbox, type);
            return this;
        }

using System;
using System.Collections;
using System.Globalization;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;

#if NET_2_0
using System.Collections.Generic;
#endif

namespace System.Text.RegularExpressions {

	//
	// Compiler which generates IL bytecode to perform the matching instead of
	// interpreting a program.
	// For simplicity, we inherit from RxCompiler, and generate the IL code based
	// on the program generated by it. This also allows us to fallback to interpretation
	// if we can't handle something.
	// This is net 2.0, since 1.0 doesn't support DynamicMethods
	// FIXME: Add support for 1.0, and CompileToAssembly
	// FIXME: Overwrite RxCompiler methods so we don't have to decode char
	// matching opcodes
	//

#if NET_2_0
	class CILCompiler : RxCompiler, ICompiler {
		DynamicMethod[] eval_methods;
		bool[] eval_methods_defined;

		/*
		 * To avoid the overhead of decoding the countless opcode variants created
		 * by RxCompiler, we save the original, 'generic' version and its flags
		 * in these two tables.
		 */
		private Dictionary<int, int> generic_ops;
		private Dictionary<int, int> op_flags;
		private Dictionary<int, Label> labels;

		static FieldInfo fi_str = typeof (RxInterpreter).GetField ("str", BindingFlags.Instance|BindingFlags.NonPublic);
		static FieldInfo fi_string_start = typeof (RxInterpreter).GetField ("string_start", BindingFlags.Instance|BindingFlags.NonPublic);
		static FieldInfo fi_string_end = typeof (RxInterpreter).GetField ("string_end", BindingFlags.Instance|BindingFlags.NonPublic);
		static FieldInfo fi_program = typeof (RxInterpreter).GetField ("program", BindingFlags.Instance|BindingFlags.NonPublic);
		static FieldInfo fi_marks = typeof (RxInterpreter).GetField ("marks", BindingFlags.Instance|BindingFlags.NonPublic);
		static FieldInfo fi_groups = typeof (RxInterpreter).GetField ("groups", BindingFlags.Instance|BindingFlags.NonPublic);
		static FieldInfo fi_deep = typeof (RxInterpreter).GetField ("deep", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
		static FieldInfo fi_stack = typeof (RxInterpreter).GetField ("stack", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
		static FieldInfo fi_mark_start = typeof (Mark).GetField ("Start", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
		static FieldInfo fi_mark_end = typeof (Mark).GetField ("End", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
		//static FieldInfo fi_mark_index = typeof (Mark).GetField ("Index", BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);

		static MethodInfo mi_stack_get_count, mi_stack_set_count, mi_stack_push, mi_stack_pop;
		static MethodInfo mi_set_start_of_match, mi_is_word_char, mi_reset_groups;
		static MethodInfo mi_checkpoint, mi_backtrack, mi_open, mi_close;
		static MethodInfo mi_get_last_defined, mi_mark_get_index, mi_mark_get_length;

		public static readonly bool trace_compile = Environment.GetEnvironmentVariable ("MONO_TRACE_RX_COMPILE") != null;

		public CILCompiler () {
			generic_ops = new Dictionary <int, int> ();
			op_flags = new Dictionary <int, int> ();
		}

		IMachineFactory ICompiler.GetMachineFactory () {
			byte[] code = new byte [curpos];
			Buffer.BlockCopy (program, 0, code, 0, curpos);

			eval_methods = new DynamicMethod [code.Length];
			eval_methods_defined = new bool [code.Length];

			// The main eval method
		    DynamicMethod main = GetEvalMethod (code, 11);

			if (main != null)
				return new RxInterpreterFactory (code, (EvalDelegate)main.CreateDelegate (typeof (EvalDelegate)));
			else
				return new RxInterpreterFactory (code, null);
		}

		DynamicMethod GetEvalMethod (byte[] program, int pc) {
			if (eval_methods_defined [pc])
				return eval_methods [pc];

			// FIXME: Recursion ?
			eval_methods_defined [pc] = true;

			eval_methods [pc] = CreateEvalMethod (program, pc);
			return eval_methods [pc];
		}

		private MethodInfo GetMethod (Type t, string name, ref MethodInfo cached) {
			if (cached == null) {
				cached = t.GetMethod (name, BindingFlags.Static|BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
				if (cached == null)
					throw new Exception ("Method not found: " + name);
			}
			return cached;
		}

		private MethodInfo GetMethod (string name, ref MethodInfo cached) {
			return GetMethod (typeof (RxInterpreter), name, ref cached);
	    }

		private int ReadInt (byte[] code, int pc) {
			int val = code [pc];
			val |= code [pc + 1] << 8;
			val |= code [pc + 2] << 16;
			val |= code [pc + 3] << 24;
			return val;
		}

		static OpFlags MakeFlags (bool negate, bool ignore, bool reverse, bool lazy) {
			OpFlags flags = 0;
			if (negate) flags |= OpFlags.Negate;
			if (ignore) flags |= OpFlags.IgnoreCase;
			if (reverse) flags |= OpFlags.RightToLeft;
			if (lazy) flags |= OpFlags.Lazy;

			return flags;
		}

		void EmitGenericOp (RxOp op, bool negate, bool ignore, bool reverse, bool lazy) {
			generic_ops [curpos] = (int)op;
			op_flags [curpos] = (int)MakeFlags (negate, ignore, reverse, false);
	    }

		public override void EmitOp (RxOp op, bool negate, bool ignore, bool reverse) {
			EmitGenericOp (op, negate, ignore, reverse, false);
			base.EmitOp (op, negate, ignore, reverse);
		}

		public override void EmitOpIgnoreReverse (RxOp op, bool ignore, bool reverse) {
			EmitGenericOp (op, false, ignore, reverse, false);
			base.EmitOpIgnoreReverse (op, ignore, reverse);
		}

		public override void EmitOpNegateReverse (RxOp op, bool negate, bool reverse) {
			EmitGenericOp (op, negate, false, reverse, false);
			base.EmitOpNegateReverse (op, negate, reverse);
		}

		class Frame {
			public Label label_pass, label_fail;

			public Frame (ILGenerator ilgen) {
				label_fail = ilgen.DefineLabel ();
				label_pass = ilgen.DefineLabel ();
			}				
		}

		LocalBuilder local_textinfo;

		/*
		 * Create a dynamic method which is equivalent to the RxInterpreter.EvalByteCode 
		 * method specialized to the given program and a given pc. Return the newly
		 * created method or null if a not-supported opcode was encountered.
		 */
		DynamicMethod CreateEvalMethod (byte[] program, int pc) {
			DynamicMethod m = new DynamicMethod ("Eval_" + pc, typeof (bool), new Type [] { typeof (RxInterpreter), typeof (int), typeof (int).MakeByRefType () }, typeof (RxInterpreter), true);
			ILGenerator ilgen = m.GetILGenerator ();

			/* 
			   Args:
			   interp - 0
			   strpos - 1
			   strpos_result - 2
			*/

			/*
			 * Recursive calls to EvalByteCode are inlined manually by calling 
			 * EmitEvalMethodBody with the pc of the recursive call. Frame objects hold
			 * the information required to link together the code generated by the recursive
			 * call with the rest of the code.
			 */
			Frame frame = new Frame (ilgen);

			/* Cache the textinfo used by Char.ToLower () */
			local_textinfo = ilgen.DeclareLocal (typeof (TextInfo));
			ilgen.Emit (OpCodes.Call, typeof (Thread).GetMethod ("get_CurrentThread"));
			ilgen.Emit (OpCodes.Call, typeof (Thread).GetMethod ("get_CurrentCulture"));
			ilgen.Emit (OpCodes.Call, typeof (CultureInfo).GetMethod ("get_TextInfo"));
			ilgen.Emit (OpCodes.Stloc, local_textinfo);

			m = EmitEvalMethodBody (m, ilgen, frame, program, pc, program.Length, false, false, out pc);
			if (m == null)
				return null;
				
			ilgen.MarkLabel (frame.label_pass);
			ilgen.Emit (OpCodes.Ldarg_2);
			ilgen.Emit (OpCodes.Ldarg_1);
			ilgen.Emit (OpCodes.Stind_I4);
			ilgen.Emit (OpCodes.Ldc_I4_1);
			ilgen.Emit (OpCodes.Ret);

			ilgen.MarkLabel (frame.label_fail);
			ilgen.Emit (OpCodes.Ldc_I4_0);
			ilgen.Emit (OpCodes.Ret);

			return m;
		}

		private int ReadShort (byte[] program, int pc) {
			return (int)program [pc] | ((int)program [pc + 1] << 8);
		}

		private Label CreateLabelForPC (ILGenerator ilgen, int pc) {
			if (labels == null)
				labels = new Dictionary <int, Label> ();
			Label l;
			if (!labels.TryGetValue (pc, out l)) {
				l = ilgen.DefineLabel ();
				labels [pc] = l;
			}

			return l;
		}

		private int GetILOffset (ILGenerator ilgen) {
			return (int)typeof (ILGenerator).GetField ("code_len", BindingFlags.Instance|BindingFlags.NonPublic).GetValue (ilgen);
		}

		/*
		 * Emit IL code for a sequence of opcodes between pc and end_pc. If there is a
		 * match, set strpos (Arg 1) to the position after the match, then 
		 * branch to frame.label_pass. Otherwise branch to frame.label_fail, 
		 * and leave strpos at an undefined position. The caller should 
		 * generate code to save the original value of strpos if it needs it.
		 * If one_op is true, only generate code for one opcode and set out_pc 
		 * to the next pc after the opcode.
		 * If no_bump is true, don't bump strpos in char matching opcodes.
		 * Keep this in synch with RxInterpreter.EvalByteCode (). It it is sync with
		 * the version in r111969.
		 * FIXME: Modify the regex tests so they are run with RegexOptions.Compiled as
		 * well.
		 */
		private DynamicMethod EmitEvalMethodBody (DynamicMethod m, ILGenerator ilgen,
												  Frame frame, byte[] program,
												  int pc, int end_pc,
 												  bool one_op, bool no_bump,
												  out int out_pc)
		{
			int start, length, end;

			out_pc = 0;

			int group_count = 1 + ReadShort (program, 1);

			while (pc < end_pc) {
				RxOp op = (RxOp)program [pc];

				// FIXME: Optimize this
				if (generic_ops.ContainsKey (pc))
					op = (RxOp)generic_ops [pc];

				if (trace_compile) {
					Console.WriteLine ("compiling {0} pc={1} end_pc={2}, il_offset=0x{3:x}", op, pc, end_pc, GetILOffset (ilgen));
				}

				if (labels != null) {
					Label l;
					if (labels.TryGetValue (pc, out l)) {
						ilgen.MarkLabel (l);
						labels.Remove (pc);
					}
				}

				if (RxInterpreter.trace_rx) {
					//Console.WriteLine ("evaluating: {0} at pc: {1}, strpos: {2}", op, pc, strpos);
					ilgen.Emit (OpCodes.Ldstr, "evaluating: {0} at pc: {1}, strpos: {2}");
					ilgen.Emit (OpCodes.Ldc_I4, (int)op);
					ilgen.Emit (OpCodes.Box, typeof (RxOp));
					ilgen.Emit (OpCodes.Ldc_I4, pc);
					ilgen.Emit (OpCodes.Box, typeof (int));
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Box, typeof (int));
					ilgen.Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type [] { typeof (string), typeof (object), typeof (object), typeof (object) }));
				}

				switch (op) {
				case RxOp.Anchor:
				case RxOp.AnchorReverse: {
					bool reverse = (RxOp)program [pc] == RxOp.AnchorReverse;
					length = ReadShort (program, pc + 3);
					pc += ReadShort (program, pc + 1);

					// Optimize some common cases by inlining the code generated for the
					// anchor body 
					RxOp anch_op = (RxOp)program [pc];

					// FIXME: Do this even if the archor op is not the last in the regex
					if (!reverse && group_count == 1 && anch_op == RxOp.Char && (RxOp)program [pc + 2] == RxOp.True) {

						/*
						 * while (strpos < string_end) {
						 *   if (str [strpos] == program [pc + 1]) {
						 *     match_start = strpos;
						 *     strpos_result = strpos + 1;
						 *     marks [groups [0]].Start = strpos;
						 *     if (groups.Length > 1)
						 *		marks [groups [0]].End = res;
						 *     return true;
						 *   }
						 *   strpos ++;
						 * }
						 * return false;
						 */
						// Add some locals to avoid an indirection
						LocalBuilder local_string_end = ilgen.DeclareLocal (typeof (int));
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldfld, fi_string_end);
						ilgen.Emit (OpCodes.Stloc, local_string_end);
						LocalBuilder local_str = ilgen.DeclareLocal (typeof (string));
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldfld, fi_str);
						ilgen.Emit (OpCodes.Stloc, local_str);

						//while (strpos < string_end) {
						// -> Done at the end of the loop like mcs does
						Label l1 = ilgen.DefineLabel ();
						Label l2 = ilgen.DefineLabel ();
						ilgen.Emit (OpCodes.Br, l2);
						ilgen.MarkLabel (l1);

						//  if (str [strpos] == program [pc + 1]) {
						Label l3 = ilgen.DefineLabel ();
						ilgen.Emit (OpCodes.Ldloc, local_str);
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
						ilgen.Emit (OpCodes.Conv_I4);
						ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 1]);
						ilgen.Emit (OpCodes.Beq, l3);

						// The true case is done after the loop

						//  }
						//  strpos++;
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldc_I4_1);
						ilgen.Emit (OpCodes.Add);
						ilgen.Emit (OpCodes.Starg, 1);
						//}
						ilgen.MarkLabel (l2);
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldloc, local_string_end);
						ilgen.Emit (OpCodes.Blt, l1);

						//return false;
						ilgen.Emit (OpCodes.Br, frame.label_fail);

						// True case
						ilgen.MarkLabel (l3);
						// call SetStartOfMatch (strpos)
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter), "SetStartOfMatch", ref mi_set_start_of_match));
						//  strpos++;
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldc_I4_1);
						ilgen.Emit (OpCodes.Add);
						ilgen.Emit (OpCodes.Starg, 1);
						//    return true;
						ilgen.Emit (OpCodes.Br, frame.label_pass);

					} else {
						// General case

						//Console.WriteLine ("Anchor op " + anch_op);

						// Add some locals to avoid an indirection
						LocalBuilder local_string_end = ilgen.DeclareLocal (typeof (int));
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldfld, fi_string_end);
						ilgen.Emit (OpCodes.Ldc_I4_1);
						ilgen.Emit (OpCodes.Add);
						ilgen.Emit (OpCodes.Stloc, local_string_end);

						//while (strpos < string_end + 1) {
						// -> Done at the end of the loop like mcs does
						Label l1 = ilgen.DefineLabel ();
						Label l2 = ilgen.DefineLabel ();
						ilgen.Emit (OpCodes.Br, l2);
						ilgen.MarkLabel (l1);

						//if (groups.Length > 1) {
						//	ResetGroups ();
						//	marks [groups [0]].Start = strpos;
						//}
						if (group_count > 1) {
							ilgen.Emit (OpCodes.Ldarg_0);
							ilgen.Emit (OpCodes.Call, GetMethod ("ResetGroups", ref mi_reset_groups));

							ilgen.Emit (OpCodes.Ldarg_0);
							ilgen.Emit (OpCodes.Ldfld, fi_marks);
							ilgen.Emit (OpCodes.Ldarg_0);
							ilgen.Emit (OpCodes.Ldfld, fi_groups);
							ilgen.Emit (OpCodes.Ldc_I4_0);
							ilgen.Emit (OpCodes.Ldelem_I4);
							ilgen.Emit (OpCodes.Ldelema, typeof (Mark));
							ilgen.Emit (OpCodes.Ldarg_1);
							ilgen.Emit (OpCodes.Stfld, fi_mark_start);
						}

						//  if (EvalByteCode (pc, strpos, ref res)) {

						Frame new_frame = new Frame (ilgen);

						//  old_stros = strpos;
						LocalBuilder local_old_strpos = ilgen.DeclareLocal (typeof (int));
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Stloc, local_old_strpos);

						m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc, end_pc, false, false, out out_pc);
						if (m == null)
							return null;

						// Pass
						ilgen.MarkLabel (new_frame.label_pass);
						//    marks [groups [0]].Start = old_strpos;
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldfld, fi_marks);
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldfld, fi_groups);
						ilgen.Emit (OpCodes.Ldc_I4_0);
						ilgen.Emit (OpCodes.Ldelem_I4);
						ilgen.Emit (OpCodes.Ldelema, typeof (Mark));
						ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
						ilgen.Emit (OpCodes.Stfld, fi_mark_start);
						//    if (groups.Length > 1)
						//		marks [groups [0]].End = res;
						if (group_count > 1) {
							ilgen.Emit (OpCodes.Ldarg_0);
							ilgen.Emit (OpCodes.Ldfld, fi_marks);
							ilgen.Emit (OpCodes.Ldarg_0);
							ilgen.Emit (OpCodes.Ldfld, fi_groups);
							ilgen.Emit (OpCodes.Ldc_I4_0);
							ilgen.Emit (OpCodes.Ldelem_I4);
							ilgen.Emit (OpCodes.Ldelema, typeof (Mark));
							ilgen.Emit (OpCodes.Ldarg_1);
							ilgen.Emit (OpCodes.Stfld, fi_mark_end);
						}

						//    return true;
						ilgen.Emit (OpCodes.Br, frame.label_pass);

						// Fail
						ilgen.MarkLabel (new_frame.label_fail);
						//  strpos = old_strpos +/- 1;
						ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
						ilgen.Emit (OpCodes.Ldc_I4_1);
						if (reverse)
							ilgen.Emit (OpCodes.Sub);
						else
							ilgen.Emit (OpCodes.Add);
						ilgen.Emit (OpCodes.Starg, 1);
						//}
						ilgen.MarkLabel (l2);
						if (reverse) {
							ilgen.Emit (OpCodes.Ldarg_1);
							ilgen.Emit (OpCodes.Ldc_I4_0);
							ilgen.Emit (OpCodes.Bge, l1);
						} else {
							ilgen.Emit (OpCodes.Ldarg_1);
							ilgen.Emit (OpCodes.Ldloc, local_string_end);
							ilgen.Emit (OpCodes.Blt, l1);
						}
						//return false;
						ilgen.Emit (OpCodes.Br, frame.label_fail);
					}

					goto End;
				}
				case RxOp.Branch: {
					//if (EvalByteCode (pc + 3, strpos, ref res)) {

					int target_pc = pc + ReadShort (program, pc + 1);

					// Emit the rest of the code inline instead of making a recursive call
					Frame new_frame = new Frame (ilgen);

					//  old_strpos = strpos;
					LocalBuilder local_old_strpos = ilgen.DeclareLocal (typeof (int));
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Stloc, local_old_strpos);

					m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc + 3, target_pc, false, false, out out_pc);
					if (m == null)
						return null;

					// Pass
					ilgen.MarkLabel (new_frame.label_pass);
					//  return true;
					ilgen.Emit (OpCodes.Br, frame.label_pass);

					// Fail
					ilgen.MarkLabel (new_frame.label_fail);
					//  strpos = old_strpos;
					ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
					ilgen.Emit (OpCodes.Starg, 1);

					pc = target_pc;
					break;
				}
				case RxOp.Char:
				case RxOp.UnicodeChar:
				case RxOp.Range:
				case RxOp.UnicodeRange: {
					OpFlags flags = (OpFlags)op_flags [pc];
					bool negate = (flags & OpFlags.Negate) > 0;
					bool ignore = (flags & OpFlags.IgnoreCase) > 0;
					bool reverse = (flags & OpFlags.RightToLeft) > 0;

					//if (strpos < string_end) {
					Label l1 = ilgen.DefineLabel ();
					if (reverse) {
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldc_I4_0);
						ilgen.Emit (OpCodes.Ble, l1);
					} else {
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldfld, fi_string_end);
						ilgen.Emit (OpCodes.Bge, l1);
					}

					if (ignore)
						ilgen.Emit (OpCodes.Ldloc, local_textinfo);

					//  int c = str [strpos];
					LocalBuilder local_c = ilgen.DeclareLocal (typeof (char));
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_str);
					ilgen.Emit (OpCodes.Ldarg_1);
					if (reverse) {
						ilgen.Emit (OpCodes.Ldc_I4_1);
						ilgen.Emit (OpCodes.Sub);
					}
					ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
					if (ignore)
						ilgen.Emit (OpCodes.Callvirt, typeof (TextInfo).GetMethod ("ToLower", new Type [] { typeof (char) }));

					if (op == RxOp.Char) {
						ilgen.Emit (OpCodes.Conv_I4);
						ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 1]);
						ilgen.Emit (negate ? OpCodes.Beq : OpCodes.Bne_Un, l1);

						pc += 2;
					} else if (op == RxOp.UnicodeChar) {
						ilgen.Emit (OpCodes.Conv_I4);
						ilgen.Emit (OpCodes.Ldc_I4, ReadShort (program, pc + 1));
						ilgen.Emit (negate ? OpCodes.Beq : OpCodes.Bne_Un, l1);

						pc += 3;
					} else if (op == RxOp.Range) {
						ilgen.Emit (OpCodes.Stloc, local_c);

						//  if (c >= program [pc + 1] && c <= program [pc + 2]) {
						if (negate) {
							Label l3 = ilgen.DefineLabel ();

							ilgen.Emit (OpCodes.Ldloc, local_c);
							ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 1]);
							ilgen.Emit (OpCodes.Blt, l3);
							ilgen.Emit (OpCodes.Ldloc, local_c);
							ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 2]);
							ilgen.Emit (OpCodes.Bgt, l3);
							ilgen.Emit (OpCodes.Br, l1);
							ilgen.MarkLabel (l3);
						} else {
							ilgen.Emit (OpCodes.Ldloc, local_c);
							ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 1]);
							ilgen.Emit (OpCodes.Blt, l1);
							ilgen.Emit (OpCodes.Ldloc, local_c);
							ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 2]);
							ilgen.Emit (OpCodes.Bgt, l1);
						}

						pc += 3;
					} else if (op == RxOp.UnicodeRange) {
						ilgen.Emit (OpCodes.Stloc, local_c);

						//  if (c >= program [pc + 1] && c <= program [pc + 2]) {
						if (negate) {
							Label l3 = ilgen.DefineLabel ();

							ilgen.Emit (OpCodes.Ldloc, local_c);
							ilgen.Emit (OpCodes.Ldc_I4, ReadShort (program, pc + 1));
							ilgen.Emit (OpCodes.Blt, l3);
							ilgen.Emit (OpCodes.Ldloc, local_c);
							ilgen.Emit (OpCodes.Ldc_I4, ReadShort (program, pc + 3));
							ilgen.Emit (OpCodes.Bgt, l3);
							ilgen.Emit (OpCodes.Br, l1);
							ilgen.MarkLabel (l3);
						} else {
							ilgen.Emit (OpCodes.Ldloc, local_c);
							ilgen.Emit (OpCodes.Ldc_I4, ReadShort (program, pc + 1));
							ilgen.Emit (OpCodes.Blt, l1);
							ilgen.Emit (OpCodes.Ldloc, local_c);
							ilgen.Emit (OpCodes.Ldc_I4, ReadShort (program, pc + 3));
							ilgen.Emit (OpCodes.Bgt, l1);
						}

						pc += 5;
					} else {
						throw new NotSupportedException ();
					}

					//ilgen.EmitWriteLine ("HIT:" + (char)program [pc + 1]);
					if (!no_bump) {
						//  strpos++ / strpos--;
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldc_I4_1);
						if (reverse)
							ilgen.Emit (OpCodes.Sub);
						else
							ilgen.Emit (OpCodes.Add);
						ilgen.Emit (OpCodes.Starg, 1);
					}
					Label l2 = ilgen.DefineLabel ();
					ilgen.Emit (OpCodes.Br, l2);
					//}
					ilgen.MarkLabel (l1);
					//return false;
					ilgen.Emit (OpCodes.Br, frame.label_fail);
					ilgen.MarkLabel (l2);

					break;
				}
				case RxOp.True: {
					//  return true;
					ilgen.Emit (OpCodes.Br, frame.label_pass);
					pc++;
					break;
				}
				case RxOp.False: {
					//  return false;
					ilgen.Emit (OpCodes.Br, frame.label_fail);
					pc++;
					break;
				}
				case RxOp.AnyPosition: {
					pc++;
					break;
				}
				case RxOp.StartOfString: {
					//if (strpos != 0)
					//	return false;
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Ldc_I4_0);
					ilgen.Emit (OpCodes.Bgt, frame.label_fail);
					pc++;
					break;
				}
				case RxOp.StartOfLine: {
					// FIXME: windows line endings
					//if (!(strpos == 0 || str [strpos - 1] == '\n'))
					//	return false;
					Label l = ilgen.DefineLabel ();
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Ldc_I4_0);
					ilgen.Emit (OpCodes.Beq, l);
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_str);
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Ldc_I4_1);
					ilgen.Emit (OpCodes.Sub);
					ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
					ilgen.Emit (OpCodes.Ldc_I4, (int)'\n');
					ilgen.Emit (OpCodes.Beq, l);
					ilgen.Emit (OpCodes.Br, frame.label_fail);
					ilgen.MarkLabel (l);

					pc++;
					break;
				}
				case RxOp.StartOfScan: {
					//if (strpos != string_start)
					//	return false;
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_string_start);
					ilgen.Emit (OpCodes.Bne_Un, frame.label_fail);
					pc++;
					break;
				}
				case RxOp.End: {
					//if (!(strpos == string_end || (strpos == string_end - 1 && str [strpos] == '\n')))
					//	return false;
					Label l = ilgen.DefineLabel ();

					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_string_end);
					ilgen.Emit (OpCodes.Beq, l);

					Label l2 = ilgen.DefineLabel ();
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_string_end);
					ilgen.Emit (OpCodes.Ldc_I4_1);
					ilgen.Emit (OpCodes.Sub);
					ilgen.Emit (OpCodes.Bne_Un, l2);
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_str);
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
					ilgen.Emit (OpCodes.Ldc_I4, (int)'\n');
					ilgen.Emit (OpCodes.Bne_Un, l2);
					ilgen.Emit (OpCodes.Br, l);
					ilgen.MarkLabel (l2);

					ilgen.Emit (OpCodes.Br, frame.label_fail);
					ilgen.MarkLabel (l);

					pc++;
					break;
				}
				case RxOp.EndOfString: {
					//if (strpos != string_end)
					//	return false;
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_string_end);
					ilgen.Emit (OpCodes.Bne_Un, frame.label_fail);
					pc++;
					break;
				}
				case RxOp.EndOfLine: {
					//if (!(strpos == string_end || str [strpos] == '\n'))
					//	return false;
					Label l_match = ilgen.DefineLabel ();
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_string_end);
					ilgen.Emit (OpCodes.Beq, l_match);
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_str);
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
					ilgen.Emit (OpCodes.Ldc_I4, (int)'\n');
					ilgen.Emit (OpCodes.Beq, l_match);
					ilgen.Emit (OpCodes.Br, frame.label_fail);
					ilgen.MarkLabel (l_match);
					
					pc++;
					break;
				}
				case RxOp.WordBoundary:
				case RxOp.NoWordBoundary: {
					bool negate = op == RxOp.NoWordBoundary;

					//if (string_end == 0)
					//	return false;
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_string_end);
					ilgen.Emit (OpCodes.Ldc_I4_0);
					ilgen.Emit (OpCodes.Beq, frame.label_fail);

					Label l_match = ilgen.DefineLabel ();

					//if (strpos == 0) {
					Label l1 = ilgen.DefineLabel ();
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Ldc_I4_0);
					ilgen.Emit (OpCodes.Bne_Un, l1);
					//if (!IsWordChar (str [strpos])) {
					//  return false;
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_str);
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
					ilgen.Emit (OpCodes.Call, GetMethod ("IsWordChar", ref mi_is_word_char));
					ilgen.Emit (negate ? OpCodes.Brtrue : OpCodes.Brfalse, frame.label_fail);
					ilgen.Emit (OpCodes.Br, l_match);

					//} else if (strpos == string_end) {
					ilgen.MarkLabel (l1);
					Label l2 = ilgen.DefineLabel ();
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_string_end);
					ilgen.Emit (OpCodes.Bne_Un, l2);
					//if (!IsWordChar (str [strpos - 1])) {
					//  return false;
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_str);
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Ldc_I4_1);
					ilgen.Emit (OpCodes.Sub);
					ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
					ilgen.Emit (OpCodes.Call, GetMethod ("IsWordChar", ref mi_is_word_char));
					ilgen.Emit (negate ? OpCodes.Brtrue : OpCodes.Brfalse, frame.label_fail);
					ilgen.Emit (OpCodes.Br, l_match);

					//} else {
					ilgen.MarkLabel (l2);
					//if (IsWordChar (str [strpos]) == IsWordChar (str [strpos - 1])) {
					//  return false;
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_str);
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
					ilgen.Emit (OpCodes.Call, GetMethod ("IsWordChar", ref mi_is_word_char));
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_str);
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Ldc_I4_1);
					ilgen.Emit (OpCodes.Sub);
					ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
					ilgen.Emit (OpCodes.Call, GetMethod ("IsWordChar", ref mi_is_word_char));
					ilgen.Emit (negate ? OpCodes.Bne_Un : OpCodes.Beq, frame.label_fail);
					ilgen.Emit (OpCodes.Br, l_match);

					ilgen.MarkLabel (l_match);

					pc++;
					break;
				}
				case RxOp.Bitmap:
				case RxOp.UnicodeBitmap: {
					OpFlags flags = (OpFlags)op_flags [pc];
					bool negate = (flags & OpFlags.Negate) > 0;
					bool ignore = (flags & OpFlags.IgnoreCase) > 0;
					bool reverse = (flags & OpFlags.RightToLeft) > 0;
					bool unicode = (op == RxOp.UnicodeBitmap);

					//if (strpos < string_end) {
					Label l1 = ilgen.DefineLabel ();
					Label l2 = ilgen.DefineLabel ();
					Label l_match = ilgen.DefineLabel ();
					if (reverse) {
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldc_I4_0);
						ilgen.Emit (OpCodes.Ble, l1);
					} else {
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldfld, fi_string_end);
						ilgen.Emit (OpCodes.Bge, l1);
					}
					//  int c = str [strpos];
					LocalBuilder local_c = ilgen.DeclareLocal (typeof (int));
					if (ignore)
						ilgen.Emit (OpCodes.Ldloc, local_textinfo);
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_str);
					ilgen.Emit (OpCodes.Ldarg_1);
					if (reverse) {
						ilgen.Emit (OpCodes.Ldc_I4_1);
						ilgen.Emit (OpCodes.Sub);
					}
					ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
					ilgen.Emit (OpCodes.Conv_I4);
					if (ignore)
						ilgen.Emit (OpCodes.Callvirt, typeof (TextInfo).GetMethod ("ToLower", new Type [] { typeof (char) }));
					//  c -= program [pc + 1];
					if (unicode) {
						ilgen.Emit (OpCodes.Ldc_I4, ReadShort (program, pc + 1));
						ilgen.Emit (OpCodes.Sub);
						ilgen.Emit (OpCodes.Stloc, local_c);
						length = ReadShort (program, pc + 3);
						pc += 5;
					} else {
						ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 1]);
						ilgen.Emit (OpCodes.Sub);
						ilgen.Emit (OpCodes.Stloc, local_c);
						length =  program [pc + 2];
						pc += 3;
					}
					//  if (c < 0 || c >= (length << 3))
					//    return false;
					ilgen.Emit (OpCodes.Ldloc, local_c);
					ilgen.Emit (OpCodes.Ldc_I4_0);
					ilgen.Emit (OpCodes.Blt, negate ? l_match : frame.label_fail);
					ilgen.Emit (OpCodes.Ldloc, local_c);
					ilgen.Emit (OpCodes.Ldc_I4, length << 3);
					ilgen.Emit (OpCodes.Bge, negate ? l_match : frame.label_fail);

					// Optimized version for small bitmaps
					if (length <= 4) {
						uint bitmap = program [pc];
						
						if (length > 1)
							bitmap |= ((uint)program [pc + 1] << 8);
						if (length > 2)
							bitmap |= ((uint)program [pc + 2] << 16);
						if (length > 3)
							bitmap |= ((uint)program [pc + 3] << 24);

						//if ((bitmap >> c) & 1)
						ilgen.Emit (OpCodes.Ldc_I4, bitmap);
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Shr_Un);
						ilgen.Emit (OpCodes.Ldc_I4_1);
						ilgen.Emit (OpCodes.And);
						ilgen.Emit (negate ? OpCodes.Brtrue : OpCodes.Brfalse, l1);
					} else {
						//  if ((program [pc + (c >> 3)] & (1 << (c & 0x7))) != 0) {
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldfld, fi_program);
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4_3);
						ilgen.Emit (OpCodes.Shr);
						ilgen.Emit (OpCodes.Ldc_I4, pc);
						ilgen.Emit (OpCodes.Add);
						ilgen.Emit (OpCodes.Ldelem_I1);
						ilgen.Emit (OpCodes.Ldc_I4_1);
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, 7);
						ilgen.Emit (OpCodes.And);
						ilgen.Emit (OpCodes.Shl);
						ilgen.Emit (OpCodes.And);
						ilgen.Emit (OpCodes.Ldc_I4_0);
						ilgen.Emit (negate ? OpCodes.Bne_Un : OpCodes.Beq, l1);
					}
					ilgen.MarkLabel (l_match);
					if (!no_bump) {
						//  strpos++ / strpos--;
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldc_I4_1);
						if (reverse)
							ilgen.Emit (OpCodes.Sub);
						else
							ilgen.Emit (OpCodes.Add);
						ilgen.Emit (OpCodes.Starg, 1);
					}
					//    continue;
					ilgen.Emit (OpCodes.Br, l2);
					//  }
					//}
					//return false;
					ilgen.MarkLabel (l1);
					ilgen.Emit (OpCodes.Br, frame.label_fail);

					ilgen.MarkLabel (l2);

					pc += length;
					break;
				}
				case RxOp.String:
				case RxOp.UnicodeString: {
					OpFlags flags = (OpFlags)op_flags [pc];
					bool ignore = (flags & OpFlags.IgnoreCase) > 0;
					bool reverse = (flags & OpFlags.RightToLeft) > 0;
					bool unicode = (op == RxOp.UnicodeString);

					if (unicode) {
						start = pc + 3;
						length = ReadShort (program, pc + 1);
					} else {
						start = pc + 2;
						length = program [pc + 1];
					}
					//if (strpos + length > string_end)
					//	return false;
					if (reverse) {
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldc_I4, length);
						ilgen.Emit (OpCodes.Blt, frame.label_fail);
					} else {
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldc_I4, length);
						ilgen.Emit (OpCodes.Add);
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldfld, fi_string_end);
						ilgen.Emit (OpCodes.Bgt, frame.label_fail);
					}

					/* Avoid unsafe code in Moonlight build */
#if false && !NET_2_1
					// FIXME:
					if (reverse || unicode)
						throw new NotImplementedException ();
					int i;
					LocalBuilder local_strptr = ilgen.DeclareLocal (typeof (char).MakePointerType ());
					// char *strptr = &str.start_char + strpos
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_str);
					ilgen.Emit (OpCodes.Ldflda, typeof (String).GetField ("start_char", BindingFlags.Instance|BindingFlags.NonPublic));
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Ldc_I4_1);
					ilgen.Emit (OpCodes.Shl);
					ilgen.Emit (OpCodes.Add);
					ilgen.Emit (OpCodes.Stloc, local_strptr);

					end = start + length;
					for (i = 0; i < length; ++i) {
						// if (*(strptr + i) != program [start + i])
						//   return false;
						if (ignore)
							ilgen.Emit (OpCodes.Ldloc, local_textinfo);
						ilgen.Emit (OpCodes.Ldloc, local_strptr);
						ilgen.Emit (OpCodes.Ldc_I4, i * 2);
						ilgen.Emit (OpCodes.Add);
						ilgen.Emit (OpCodes.Ldind_I2);
						if (ignore)
							ilgen.Emit (OpCodes.Callvirt, typeof (TextInfo).GetMethod ("ToLower", new Type [] { typeof (char) }));
						ilgen.Emit (OpCodes.Ldc_I4, (int)program [start + i]);
						ilgen.Emit (OpCodes.Bne_Un, frame.label_fail);
					}

					// strpos += length
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Ldc_I4, length);
					ilgen.Emit (OpCodes.Add);
					ilgen.Emit (OpCodes.Starg, 1);

#else
					// Allocate a local for 'str' to save an indirection
					LocalBuilder local_str = ilgen.DeclareLocal (typeof (string));
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_str);
					ilgen.Emit (OpCodes.Stloc, local_str);

					if (reverse) {
						// strpos -= length;
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldc_I4, length);
						ilgen.Emit (OpCodes.Sub);
						ilgen.Emit (OpCodes.Starg, 1);
					}

					// FIXME: Emit a loop for long strings
					end = start + (unicode ? length * 2 : length);
					while (start < end) {
						//if (str [strpos] != program [start])
						//	return false;
						if (ignore)
							ilgen.Emit (OpCodes.Ldloc, local_textinfo);
						ilgen.Emit (OpCodes.Ldloc, local_str);
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
						if (ignore)
							ilgen.Emit (OpCodes.Callvirt, typeof (TextInfo).GetMethod ("ToLower", new Type [] { typeof (char) }));
						ilgen.Emit (OpCodes.Ldc_I4, unicode ? ReadShort (program, start) : (int)program [start]);
						ilgen.Emit (OpCodes.Bne_Un, frame.label_fail);
						//strpos++;
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldc_I4_1);
						ilgen.Emit (OpCodes.Add);
						ilgen.Emit (OpCodes.Starg, 1);

						if (unicode)
							start += 2;
						else
							start ++;
					}

					if (reverse) {
						// strpos -= length;
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldc_I4, length);
						ilgen.Emit (OpCodes.Sub);
						ilgen.Emit (OpCodes.Starg, 1);
					}
#endif

					pc = end;
					break;
				}
				case RxOp.OpenGroup: {
					//Open (program [pc + 1] | (program [pc + 2] << 8), strpos);
					int group_id = ReadShort (program, pc + 1);
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldc_I4, group_id);
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Call, GetMethod ("Open", ref mi_open));

					pc += 3;
					break;
				}
				case RxOp.CloseGroup: {
					//Close (program [pc + 1] | (program [pc + 2] << 8), strpos);
					int group_id = ReadShort (program, pc + 1);
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldc_I4, group_id);
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Call, GetMethod ("Close", ref mi_close));

					pc += 3;
					break;
				}
				case RxOp.Jump: {
					int target_pc = pc + ReadShort (program, pc + 1);
					if (target_pc > end_pc)
						/* 
						 * This breaks the our code generation logic, see
						 * https://bugzilla.novell.com/show_bug.cgi?id=466151
						 * for an example.
						 */
						return null;
					if (trace_compile)
						Console.WriteLine ("\tjump target: {0}", target_pc);
					if (labels == null)
						labels = new Dictionary <int, Label> ();
					Label l = CreateLabelForPC (ilgen, target_pc);
					ilgen.Emit (OpCodes.Br, l);
					pc += 3;
 					break;
				}
				case RxOp.Test: {
					int target1 = pc + ReadShort (program, pc + 1);
					int target2 = pc + ReadShort (program, pc + 3);

					if (trace_compile)
						Console.WriteLine ("\temitting <test_expr>");

					//  old_stros = strpos;
					LocalBuilder local_old_strpos = ilgen.DeclareLocal (typeof (int));
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Stloc, local_old_strpos);

					Frame new_frame = new Frame (ilgen);
					m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc + 5, target1 < target2 ? target1 : target2, false, false, out pc);
					if (m == null)
						return null;						

					if (trace_compile) {
						Console.WriteLine ("\temitted <test_expr>");
						Console.WriteLine ("\ttarget1 = {0}", target1);
						Console.WriteLine ("\ttarget2 = {0}", target2);
					}

					Label l1 = CreateLabelForPC (ilgen, target1);
					Label l2 = CreateLabelForPC (ilgen, target2);

					// Pass
					ilgen.MarkLabel (new_frame.label_pass);
					//  strpos = old_strpos;
					ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
					ilgen.Emit (OpCodes.Starg, 1);
					ilgen.Emit (OpCodes.Br, l1);
						
					// Fail
					ilgen.MarkLabel (new_frame.label_fail);
					//  strpos = old_strpos;
					ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
					ilgen.Emit (OpCodes.Starg, 1);
					ilgen.Emit (OpCodes.Br, l2);

					// Continue at pc, which should equal to target1
					break;
				}
				case RxOp.SubExpression: {
					int target = pc + ReadShort (program, pc + 1);

					if (trace_compile)
						Console.WriteLine ("\temitting <sub_expr>");

					//  old_stros = strpos;
					LocalBuilder local_old_strpos = ilgen.DeclareLocal (typeof (int));
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Stloc, local_old_strpos);

					Frame new_frame = new Frame (ilgen);
					m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc + 3, target, false, false, out pc);
					if (m == null)
						return null;						

					if (trace_compile) {
						Console.WriteLine ("\temitted <sub_expr>");
						Console.WriteLine ("\ttarget = {0}", target);
					}

					Label l1 = CreateLabelForPC (ilgen, target);

					// Pass
					ilgen.MarkLabel (new_frame.label_pass);
					ilgen.Emit (OpCodes.Br, l1);
						
					// Fail
					ilgen.MarkLabel (new_frame.label_fail);
					//  strpos = old_strpos;
					ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
					ilgen.Emit (OpCodes.Starg, 1);
					ilgen.Emit (OpCodes.Br, frame.label_fail);

					// Continue at pc, which should equal to target
					break;
				}
				case RxOp.TestCharGroup: {
					int char_group_end = pc + ReadShort (program, pc + 1);
					pc += 3;

					Label label_match = ilgen.DefineLabel ();

					/* Determine the negate/reverse flags by examining the first op */
					OpFlags flags = (OpFlags)op_flags [pc];

					/* Determine whenever this is a negated character class */
					/* If it is, then the conditions are ANDed together, not ORed */
					bool revert = (flags & OpFlags.Negate) > 0;
					bool reverse = (flags & OpFlags.RightToLeft) > 0;

					/*
					 * Generate code for all the matching ops in the group
					 */
					while (pc < char_group_end) {
						Frame new_frame = new Frame (ilgen);
						m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc, Int32.MaxValue, true, true, out pc);
						if (m == null)
							return null;						

						if (!revert) {
							// Pass
							ilgen.MarkLabel (new_frame.label_pass);
							ilgen.Emit (OpCodes.Br, label_match);
						
							// Fail
							// Just fall through to the next test
							ilgen.MarkLabel (new_frame.label_fail);
						} else {
							// Pass
							// Just fall through to the next test
							ilgen.MarkLabel (new_frame.label_pass);
							Label l2 = ilgen.DefineLabel ();
							ilgen.Emit (OpCodes.Br, l2);

							// Fail
							// Fail completely
							ilgen.MarkLabel (new_frame.label_fail);
							ilgen.Emit (OpCodes.Br, frame.label_fail);

							ilgen.MarkLabel (l2);
						}
					}

					if (revert) {
						/* Success */
						ilgen.Emit (OpCodes.Br, label_match);
					} else {
						// If we reached here, all the matching ops have failed
						ilgen.Emit (OpCodes.Br, frame.label_fail);
					}

					ilgen.MarkLabel (label_match);

					//  strpos++ / strpos--;
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Ldc_I4_1);
					if (reverse)
						ilgen.Emit (OpCodes.Sub);
					else
						ilgen.Emit (OpCodes.Add);
					ilgen.Emit (OpCodes.Starg, 1);

					break;
				}
				case RxOp.FastRepeat:
				case RxOp.FastRepeatLazy: {
					/*
					 * A FastRepeat is a simplified version of Repeat which does
					 * not contain another repeat inside, so backtracking is 
					 * easier.
					 * FIXME: Implement faster backtracking versions for
					 * simple inner exceptions like chars/strings.
					 */
					bool lazy = program [pc] == (byte)RxOp.FastRepeatLazy;
					int tail = pc + ReadShort (program, pc + 1);
 					start = ReadInt (program, pc + 3);
 					end = ReadInt (program, pc + 7);
					//Console.WriteLine ("min: {0}, max: {1} tail: {2}", start, end, tail);

					//  deep = null;
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldnull);
					ilgen.Emit (OpCodes.Stfld, fi_deep);

					LocalBuilder local_length = ilgen.DeclareLocal (typeof (int));

					ilgen.Emit (OpCodes.Ldc_I4_0);
					ilgen.Emit (OpCodes.Stloc, local_length);

					LocalBuilder local_old_strpos = ilgen.DeclareLocal (typeof (int));
					
					// First match at least 'start' items
					if (start > 0) {
						//for (length = 0; length < start; ++length) {
						Label l_loop_footer = ilgen.DefineLabel ();
						ilgen.Emit (OpCodes.Br, l_loop_footer);
						Label l_loop_body = ilgen.DefineLabel ();
						ilgen.MarkLabel (l_loop_body);

						// int old_strpos = strpos;
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Stloc, local_old_strpos);
						
						// if (!EvalByteCode (pc + 11, strpos, ref res))
						Frame new_frame = new Frame (ilgen);
						m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc + 11, tail, false, false, out out_pc);
						if (m == null)
							return null;

						// Fail
						// return false;
						ilgen.MarkLabel (new_frame.label_fail);
						ilgen.Emit (OpCodes.Br, frame.label_fail);

						// Pass
						ilgen.MarkLabel (new_frame.label_pass);
						// length++
						ilgen.Emit (OpCodes.Ldloc, local_length);
						ilgen.Emit (OpCodes.Ldc_I4_1);
						ilgen.Emit (OpCodes.Add);
						ilgen.Emit (OpCodes.Stloc, local_length);
						// Loop footer
						ilgen.MarkLabel (l_loop_footer);
						ilgen.Emit (OpCodes.Ldloc, local_length);
						ilgen.Emit (OpCodes.Ldc_I4, start);
						ilgen.Emit (OpCodes.Blt, l_loop_body);
					}

					if (lazy) {
						Label l_loop_footer = ilgen.DefineLabel ();
						//while (true) {
						ilgen.Emit (OpCodes.Br, l_loop_footer);
						Label l_loop_body = ilgen.DefineLabel ();
						ilgen.MarkLabel (l_loop_body);
						// Match the tail
						//  int cp = Checkpoint ();
						LocalBuilder local_cp = ilgen.DeclareLocal (typeof (int));
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Call, GetMethod ("Checkpoint", ref mi_checkpoint));
						ilgen.Emit (OpCodes.Stloc, local_cp);

						// int old_strpos = strpos;
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Stloc, local_old_strpos);

						//  if (EvalByteCode (tail, strpos, ref res)) {
						Frame new_frame = new Frame (ilgen);
						m = EmitEvalMethodBody (m, ilgen, new_frame, program, tail, end_pc, false, false, out out_pc);
						if (m == null)
							return null;

						// Success:
						ilgen.MarkLabel (new_frame.label_pass);
						//    return true;
						ilgen.Emit (OpCodes.Br, frame.label_pass);

						// Fail:
						ilgen.MarkLabel (new_frame.label_fail);
						//  Backtrack (cp);
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldloc, local_cp);
						ilgen.Emit (OpCodes.Call, GetMethod ("Backtrack", ref mi_backtrack));
						// strpos = old_strpos;
						ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
						ilgen.Emit (OpCodes.Starg, 1);

						//if (length >= end)
						//  return false;
						ilgen.Emit (OpCodes.Ldloc, local_length);
						ilgen.Emit (OpCodes.Ldc_I4, end);
						ilgen.Emit (OpCodes.Bge, frame.label_fail);

						// Match an item
						//if (!EvalByteCode (pc + 11, strpos, ref res))
						new_frame = new Frame (ilgen);
						m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc + 11, tail, false, false, out out_pc);
						if (m == null)
							return null;

						// Success:
						ilgen.MarkLabel (new_frame.label_pass);
						// length ++;
						ilgen.Emit (OpCodes.Ldloc, local_length);
						ilgen.Emit (OpCodes.Ldc_I4_1);
						ilgen.Emit (OpCodes.Add);
						ilgen.Emit (OpCodes.Stloc, local_length);
						ilgen.Emit (OpCodes.Br, l_loop_body);
						
						// Fail:
						ilgen.MarkLabel (new_frame.label_fail);
						// return false;
						ilgen.Emit (OpCodes.Br, frame.label_fail);

						// Loop footer
						ilgen.MarkLabel (l_loop_footer);
						ilgen.Emit (OpCodes.Br, l_loop_body);
					} else {
						// Then match as many items as possible, recording
						// backtracking information
						
						//int old_stack_size = stack.Count;
						LocalBuilder local_old_stack_size = ilgen.DeclareLocal (typeof (int));
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldflda, fi_stack);
						ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter.IntStack), "get_Count", ref mi_stack_get_count));
						ilgen.Emit (OpCodes.Stloc, local_old_stack_size);
						//while (length < end) {
						Label l_loop_footer = ilgen.DefineLabel ();
						ilgen.Emit (OpCodes.Br, l_loop_footer);
						Label l_loop_body = ilgen.DefineLabel ();
						ilgen.MarkLabel (l_loop_body);
						//  int cp = Checkpoint ();
						LocalBuilder local_cp = ilgen.DeclareLocal (typeof (int));
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Call, GetMethod ("Checkpoint", ref mi_checkpoint));
						ilgen.Emit (OpCodes.Stloc, local_cp);

						// int old_strpos = strpos;
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Stloc, local_old_strpos);

						//  if (!EvalByteCode (pc + 11, strpos, ref res)) {
						Frame new_frame = new Frame (ilgen);
						m = EmitEvalMethodBody (m, ilgen, new_frame, program, pc + 11, tail, false, false, out out_pc);
						if (m == null)
							return null;

						// Fail:
						ilgen.MarkLabel (new_frame.label_fail);
						// strpos = old_strpos
						ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
						ilgen.Emit (OpCodes.Starg, 1);
						//    Backtrack (cp);
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldloc, local_cp);
						ilgen.Emit (OpCodes.Call, GetMethod ("Backtrack", ref mi_backtrack));

						//    break;
						Label l_after_loop = ilgen.DefineLabel ();
						ilgen.Emit (OpCodes.Br, l_after_loop);

						// Success:
						ilgen.MarkLabel (new_frame.label_pass);

						//stack.Push (cp);
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldflda, fi_stack);
						ilgen.Emit (OpCodes.Ldloc, local_cp);
						ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter.IntStack), "Push", ref mi_stack_push));
						//stack.Push (strpos);
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldflda, fi_stack);
						ilgen.Emit (OpCodes.Ldloc, local_old_strpos);
						ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter.IntStack), "Push", ref mi_stack_push));
						// length++
						ilgen.Emit (OpCodes.Ldloc, local_length);
						ilgen.Emit (OpCodes.Ldc_I4_1);
						ilgen.Emit (OpCodes.Add);
						ilgen.Emit (OpCodes.Stloc, local_length);
						// Loop footer
						ilgen.MarkLabel (l_loop_footer);
						ilgen.Emit (OpCodes.Ldloc, local_length);
						ilgen.Emit (OpCodes.Ldc_I4, end);
						ilgen.Emit (OpCodes.Blt, l_loop_body);

						ilgen.MarkLabel (l_after_loop);

						// Then, match the tail, backtracking as necessary.

						//while (true) {
						l_loop_footer = ilgen.DefineLabel ();
						ilgen.Emit (OpCodes.Br, l_loop_footer);
						l_loop_body = ilgen.DefineLabel ();
						ilgen.MarkLabel (l_loop_body);

						if (RxInterpreter.trace_rx) {
							ilgen.Emit (OpCodes.Ldstr, "matching tail at: {0}");
							ilgen.Emit (OpCodes.Ldarg_1);
							ilgen.Emit (OpCodes.Box, typeof (int));
							ilgen.Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type [] { typeof (string), typeof (object) }));
						}

						//  if (EvalByteCode (tail, strpos, ref res)) {
						new_frame = new Frame (ilgen);
						m = EmitEvalMethodBody (m, ilgen, new_frame, program, tail, end_pc, false, false, out out_pc);
						if (m == null)
							return null;

						// Success:
						ilgen.MarkLabel (new_frame.label_pass);

						if (RxInterpreter.trace_rx) {
							ilgen.Emit (OpCodes.Ldstr, "tail matched at: {0}");
							ilgen.Emit (OpCodes.Ldarg_1);
							ilgen.Emit (OpCodes.Box, typeof (int));
							ilgen.Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type [] { typeof (string), typeof (object) }));
						}

						//	stack.Count = old_stack_size;
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldflda, fi_stack);
						ilgen.Emit (OpCodes.Ldloc, local_old_stack_size);
						ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter.IntStack), "set_Count", ref mi_stack_set_count));
						//  return true;
						ilgen.Emit (OpCodes.Br, frame.label_pass);

						// Fail:
						ilgen.MarkLabel (new_frame.label_fail);

						if (RxInterpreter.trace_rx) {
							ilgen.Emit (OpCodes.Ldstr, "tail failed to match at: {0}");
							ilgen.Emit (OpCodes.Ldarg_1);
							ilgen.Emit (OpCodes.Box, typeof (int));
							ilgen.Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type [] { typeof (string), typeof (object) }));
						}

						//  if (stack.Count == old_stack_size)
						//		return false;
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldflda, fi_stack);
						ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter.IntStack), "get_Count", ref mi_stack_get_count));
						ilgen.Emit (OpCodes.Ldloc, local_old_stack_size);
						ilgen.Emit (OpCodes.Beq, frame.label_fail);
						
						// Backtrack
						//strpos = stack.Pop ();
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldflda, fi_stack);
						ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter.IntStack), "Pop", ref mi_stack_pop));
						ilgen.Emit (OpCodes.Starg, 1);
						//Backtrack (stack.Pop ());
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldflda, fi_stack);
						ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter.IntStack), "Pop", ref mi_stack_pop));
						ilgen.Emit (OpCodes.Call, GetMethod ("Backtrack", ref mi_backtrack));

						if (RxInterpreter.trace_rx) {
							//Console.WriteLine ("backtracking to: {0}", strpos);
							ilgen.Emit (OpCodes.Ldstr, "backtracking to: {0}");
							ilgen.Emit (OpCodes.Ldarg_1);
							ilgen.Emit (OpCodes.Box, typeof (int));
							ilgen.Emit (OpCodes.Call, typeof (Console).GetMethod ("WriteLine", new Type [] { typeof (string), typeof (object) }));
						}

						// Loop footer
						ilgen.MarkLabel (l_loop_footer);
						ilgen.Emit (OpCodes.Br, l_loop_body);
					}

					// We already processed the tail
					pc = out_pc;
					goto End;
				}

				case RxOp.CategoryAny:
				case RxOp.CategoryAnySingleline:
				case RxOp.CategoryWord:
				case RxOp.CategoryDigit:
				case RxOp.CategoryWhiteSpace:
				case RxOp.CategoryEcmaWord:
				case RxOp.CategoryEcmaWhiteSpace:
				case RxOp.CategoryUnicodeSpecials:
				case RxOp.CategoryUnicode: {
					OpFlags flags = (OpFlags)op_flags [pc];
					bool negate = (flags & OpFlags.Negate) > 0;
					bool reverse = (flags & OpFlags.RightToLeft) > 0;

					//if (strpos < string_end) {
					Label l_nomatch = ilgen.DefineLabel ();
					if (reverse) {
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldc_I4_0);
						ilgen.Emit (OpCodes.Ble, l_nomatch);
					} else {
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldfld, fi_string_end);
						ilgen.Emit (OpCodes.Bge, l_nomatch);
					}

					//  int c = str [strpos];
					LocalBuilder local_c = ilgen.DeclareLocal (typeof (char));
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_str);
					ilgen.Emit (OpCodes.Ldarg_1);
					if (reverse) {
						ilgen.Emit (OpCodes.Ldc_I4_1);
						ilgen.Emit (OpCodes.Sub);
					}
					ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
					ilgen.Emit (OpCodes.Stloc, local_c);

					Label l_match = ilgen.DefineLabel ();

					Label l_true, l_false;

					l_true = negate ? l_nomatch : l_match;
					l_false = negate ? l_match : l_nomatch;

					switch (op) {
					case RxOp.CategoryAny:
						// if (str [strpos] != '\n') {
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, (int)'\n');
						ilgen.Emit (OpCodes.Bne_Un, l_true);
						break;
					case RxOp.CategoryAnySingleline:
						ilgen.Emit (OpCodes.Br, l_true);
						break;
					case RxOp.CategoryWord:
						//  if (Char.IsLetterOrDigit (c) || Char.GetUnicodeCategory (c) == UnicodeCategory.ConnectorPunctuation) {
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Call, typeof (Char).GetMethod ("IsLetterOrDigit", new Type [] { typeof (char) }));
						ilgen.Emit (OpCodes.Brtrue, l_true);
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Call, typeof (Char).GetMethod ("GetUnicodeCategory", new Type [] { typeof (char) }));
						ilgen.Emit (OpCodes.Ldc_I4, (int)UnicodeCategory.ConnectorPunctuation);
						ilgen.Emit (OpCodes.Beq, l_true);
						break;
					case RxOp.CategoryDigit:
						// if (Char.IsDigit (c)) {
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Call, typeof (Char).GetMethod ("IsDigit", new Type [] { typeof (char) }));
						ilgen.Emit (OpCodes.Brtrue, l_true);
						break;
					case RxOp.CategoryWhiteSpace:
						// if (Char.IsWhiteSpace (c)) {
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Call, typeof (Char).GetMethod ("IsWhiteSpace", new Type [] { typeof (char) }));
						ilgen.Emit (OpCodes.Brtrue, l_true);
						break;
					case RxOp.CategoryEcmaWord:
						// if ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' || c == '_') {
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, (int)'a' - 1);
						ilgen.Emit (OpCodes.Cgt);
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, (int)'z' + 1);
						ilgen.Emit (OpCodes.Clt);
						ilgen.Emit (OpCodes.And);
						ilgen.Emit (OpCodes.Brtrue, l_true);

						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, (int)'A' - 1);
						ilgen.Emit (OpCodes.Cgt);
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, (int)'Z' + 1);
						ilgen.Emit (OpCodes.Clt);
						ilgen.Emit (OpCodes.And);
						ilgen.Emit (OpCodes.Brtrue, l_true);

						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, (int)'0' - 1);
						ilgen.Emit (OpCodes.Cgt);
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, (int)'9' + 1);
						ilgen.Emit (OpCodes.Clt);
						ilgen.Emit (OpCodes.And);
						ilgen.Emit (OpCodes.Brtrue, l_true);

						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, (int)'_');
						ilgen.Emit (OpCodes.Beq, l_true);
						break;
					case RxOp.CategoryEcmaWhiteSpace:
						// if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v') {
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, (int)' ');
						ilgen.Emit (OpCodes.Beq, l_true);
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, (int)'\t');
						ilgen.Emit (OpCodes.Beq, l_true);
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, (int)'\n');
						ilgen.Emit (OpCodes.Beq, l_true);
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, (int)'\r');
						ilgen.Emit (OpCodes.Beq, l_true);
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, (int)'\f');
						ilgen.Emit (OpCodes.Beq, l_true);
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, (int)'\v');
						ilgen.Emit (OpCodes.Beq, l_true);
						break;
					case RxOp.CategoryUnicodeSpecials:
						// if ('\uFEFF' <= c && c <= '\uFEFF' || '\uFFF0' <= c && c <= '\uFFFD') {
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, (int)'\uFEFF' - 1);
						ilgen.Emit (OpCodes.Cgt);
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, (int)'\uFEFF' + 1);
						ilgen.Emit (OpCodes.Clt);
						ilgen.Emit (OpCodes.And);
						ilgen.Emit (OpCodes.Brtrue, l_true);

						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, (int)'\uFFF0' - 1);
						ilgen.Emit (OpCodes.Cgt);
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Ldc_I4, (int)'\uFFFD' + 1);
						ilgen.Emit (OpCodes.Clt);
						ilgen.Emit (OpCodes.And);
						ilgen.Emit (OpCodes.Brtrue, l_true);
						break;
					case RxOp.CategoryUnicode:
						// if (Char.GetUnicodeCategory (c) == (UnicodeCategory)program [pc + 1]) {						
						ilgen.Emit (OpCodes.Ldloc, local_c);
						ilgen.Emit (OpCodes.Call, typeof (Char).GetMethod ("GetUnicodeCategory", new Type [] { typeof (char) }));
						ilgen.Emit (OpCodes.Ldc_I4, (int)program [pc + 1]);
						ilgen.Emit (OpCodes.Beq, l_true);
						break;
					}

					ilgen.Emit (OpCodes.Br, l_false);

					ilgen.MarkLabel (l_match);

					//    strpos++;
					if (!no_bump) {
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldc_I4_1);
						if (reverse)
							ilgen.Emit (OpCodes.Sub);
						else
							ilgen.Emit (OpCodes.Add);
						ilgen.Emit (OpCodes.Starg, 1);
					}
					//  }
					Label l2 = ilgen.DefineLabel ();
					ilgen.Emit (OpCodes.Br, l2);
					//}
					ilgen.MarkLabel (l_nomatch);
					//return false;
					ilgen.Emit (OpCodes.Br, frame.label_fail);

					ilgen.MarkLabel (l2);

					if (op == RxOp.CategoryUnicode)
						pc += 2;
					else
						pc++;
					break;
				}
				case RxOp.Reference: {
					OpFlags flags = (OpFlags)op_flags [pc];
					bool ignore = (flags & OpFlags.IgnoreCase) > 0;
					bool reverse = (flags & OpFlags.RightToLeft) > 0;

					//length = GetLastDefined (program [pc + 1] | ((int)program [pc + 2] << 8));
					LocalBuilder loc_length = ilgen.DeclareLocal (typeof (int));
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldc_I4, ReadShort (program, pc + 1)); 
					ilgen.Emit (OpCodes.Call, GetMethod (typeof (RxInterpreter), "GetLastDefined", ref mi_get_last_defined));					
					ilgen.Emit (OpCodes.Stloc, loc_length);
					//if (length < 0)
					//  return false;
					ilgen.Emit (OpCodes.Ldloc, loc_length);
					ilgen.Emit (OpCodes.Ldc_I4_0);
					ilgen.Emit (OpCodes.Blt, frame.label_fail);
					//start = marks [length].Index;
					LocalBuilder loc_start = ilgen.DeclareLocal (typeof (int));
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_marks);
					ilgen.Emit (OpCodes.Ldloc, loc_length);
					ilgen.Emit (OpCodes.Ldelema, typeof (Mark));
					ilgen.Emit (OpCodes.Call, GetMethod (typeof (Mark), "get_Index", ref mi_mark_get_index));
					ilgen.Emit (OpCodes.Stloc, loc_start);
					// length = marks [length].Length;
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_marks);
					ilgen.Emit (OpCodes.Ldloc, loc_length);
					ilgen.Emit (OpCodes.Ldelema, typeof (Mark));
					ilgen.Emit (OpCodes.Call, GetMethod (typeof (Mark), "get_Length", ref mi_mark_get_length));
					ilgen.Emit (OpCodes.Stloc, loc_length);
					if (reverse) {
						//ptr -= length;
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldloc, loc_length);
						ilgen.Emit (OpCodes.Sub);
						ilgen.Emit (OpCodes.Starg, 1);
						//if (ptr < 0)
						//goto Fail;
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldc_I4_0);
						ilgen.Emit (OpCodes.Blt, frame.label_fail);
					} else {
						//if (strpos + length > string_end)
						//  return false;
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldloc, loc_length);
						ilgen.Emit (OpCodes.Add);
						ilgen.Emit (OpCodes.Ldarg_0);
						ilgen.Emit (OpCodes.Ldfld, fi_string_end);
						ilgen.Emit (OpCodes.Bgt, frame.label_fail);
					}

					LocalBuilder local_str = ilgen.DeclareLocal (typeof (string));
					ilgen.Emit (OpCodes.Ldarg_0);
					ilgen.Emit (OpCodes.Ldfld, fi_str);
					ilgen.Emit (OpCodes.Stloc, local_str);

					// end = start + length;
					LocalBuilder loc_end = ilgen.DeclareLocal (typeof (int));
					ilgen.Emit (OpCodes.Ldloc, loc_start);
					ilgen.Emit (OpCodes.Ldloc, loc_length);
					ilgen.Emit (OpCodes.Add);
					ilgen.Emit (OpCodes.Stloc, loc_end);
					//for (; start < end; ++start) {
					Label l_loop_footer = ilgen.DefineLabel ();
					ilgen.Emit (OpCodes.Br, l_loop_footer);
					Label l_loop_body = ilgen.DefineLabel ();
					ilgen.MarkLabel (l_loop_body);
					//if (str [strpos] != str [start])
					//return false;
					if (ignore)
						ilgen.Emit (OpCodes.Ldloc, local_textinfo);
					ilgen.Emit (OpCodes.Ldloc, local_str);
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
					if (ignore)
						ilgen.Emit (OpCodes.Callvirt, typeof (TextInfo).GetMethod ("ToLower", new Type [] { typeof (char) }));
					if (ignore)
						ilgen.Emit (OpCodes.Ldloc, local_textinfo);
					ilgen.Emit (OpCodes.Ldloc, local_str);
					ilgen.Emit (OpCodes.Ldloc, loc_start);
					ilgen.Emit (OpCodes.Callvirt, typeof (string).GetMethod ("get_Chars"));
					if (ignore)
						ilgen.Emit (OpCodes.Callvirt, typeof (TextInfo).GetMethod ("ToLower", new Type [] { typeof (char) }));
					ilgen.Emit (OpCodes.Bne_Un, frame.label_fail);
					// strpos++;
					ilgen.Emit (OpCodes.Ldarg_1);
					ilgen.Emit (OpCodes.Ldc_I4_1);
					ilgen.Emit (OpCodes.Add);
					ilgen.Emit (OpCodes.Starg, 1);
					// start++
					ilgen.Emit (OpCodes.Ldloc, loc_start);
					ilgen.Emit (OpCodes.Ldc_I4_1);
					ilgen.Emit (OpCodes.Add);
					ilgen.Emit (OpCodes.Stloc, loc_start);
					// Loop footer
					ilgen.MarkLabel (l_loop_footer);
					ilgen.Emit (OpCodes.Ldloc, loc_start);
					ilgen.Emit (OpCodes.Ldloc, loc_end);
					ilgen.Emit (OpCodes.Blt, l_loop_body);

					if (reverse) {
						//ptr -= length;
						ilgen.Emit (OpCodes.Ldarg_1);
						ilgen.Emit (OpCodes.Ldloc, loc_length);
						ilgen.Emit (OpCodes.Sub);
						ilgen.Emit (OpCodes.Starg, 1);
					}

					pc += 3;
					break;
				}
				case RxOp.Repeat:
				case RxOp.RepeatLazy:
				case RxOp.IfDefined:
					// FIXME:
					if (RxInterpreter.trace_rx || trace_compile)
						Console.WriteLine ("Opcode " + op + " not supported.");
					return null;
				default:
					throw new NotImplementedException ("Opcode '" + op + "' not supported by the regex->IL compiler.");
			    }

				if (one_op)
					break;
			}

			End:

			out_pc = pc;

			return m;
		}
	}
#else
	class CILCompiler : RxCompiler {
	}
#endif

}


/*
 * Tencent is pleased to support the open source community by making xLua available.
 * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
 * Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
 * http://opensource.org/licenses/MIT
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
*/

#if (UNITY_EDITOR || XLUA_GENERAL) && !NET_STANDARD_2_0
using System.Collections.Generic;
using System.Reflection.Emit;
using System.Reflection;
using System;
using System.Linq;

#if USE_UNI_LUA
using LuaAPI = UniLua.Lua;
using RealStatePtr = UniLua.ILuaState;
using LuaCSFunction = UniLua.CSharpFunctionDelegate;
#else
using LuaAPI = XLua.LuaDLL.Lua;
using RealStatePtr = System.IntPtr;
using LuaCSFunction = XLua.LuaDLL.lua_CSFunction;
#endif

namespace XLua
{
    public class CodeEmit
    {
        private ModuleBuilder codeEmitModule = null;
        private ulong genID = 0;

        private MethodInfo LuaEnv_ThrowExceptionFromError = typeof(LuaEnv).GetMethod("ThrowExceptionFromError");
        private FieldInfo LuaBase_luaEnv = typeof(LuaBase).GetField("luaEnv", BindingFlags.NonPublic | BindingFlags.Instance);
        private MethodInfo DelegateBridgeBase_errorFuncRef_getter = typeof(LuaBase).GetProperty("_errorFuncRef", BindingFlags.NonPublic | BindingFlags.Instance).GetGetMethod(true);
        private MethodInfo LuaAPI_load_error_func = typeof(LuaAPI).GetMethod("load_error_func");
        private MethodInfo LuaBase_translator_getter  = typeof(LuaBase).GetProperty("_translator", BindingFlags.NonPublic | BindingFlags.Instance).GetGetMethod(true);
        private FieldInfo LuaBase_luaReference = typeof(LuaBase).GetField("luaReference", BindingFlags.NonPublic | BindingFlags.Instance);
        private MethodInfo LuaAPI_lua_getref = typeof(LuaAPI).GetMethod("lua_getref");
        private MethodInfo Type_GetTypeFromHandle = typeof(Type).GetMethod("GetTypeFromHandle", new Type[] { typeof(RuntimeTypeHandle) });
        private MethodInfo ObjectTranslator_PushAny = typeof(ObjectTranslator).GetMethod("PushAny");
        private MethodInfo ObjectTranslator_PushParams = typeof(ObjectTranslator).GetMethod("PushParams");
        private MethodInfo LuaBase_L_getter = typeof(LuaBase).GetProperty("_L", BindingFlags.NonPublic | BindingFlags.Instance).GetGetMethod(true);
        private MethodInfo LuaAPI_lua_pcall = typeof(LuaAPI).GetMethod("lua_pcall");
        private MethodInfo LuaAPI_lua_type = typeof(LuaAPI).GetMethod("lua_type");
        private MethodInfo ObjectTranslator_GetObject = typeof(ObjectTranslator).GetMethod("GetObject", new Type[] { typeof(RealStatePtr),
               typeof(int), typeof(Type)});
        private MethodInfo ObjectTranslator_GetParams = typeof(ObjectTranslator).GetMethod("GetParams", new Type[] { typeof(RealStatePtr), typeof(int) });
        private MethodInfo ObjectTranslator_Update = typeof(ObjectTranslator).GetMethod("Update");
        private MethodInfo LuaAPI_lua_pushvalue = typeof(LuaAPI).GetMethod("lua_pushvalue");
        private MethodInfo LuaAPI_lua_remove = typeof(LuaAPI).GetMethod("lua_remove");
        private MethodInfo LuaAPI_lua_pushstring = typeof(LuaAPI).GetMethod("lua_pushstring", new Type[] { typeof(RealStatePtr), typeof(string)});
        private MethodInfo LuaAPI_lua_gettop = typeof(LuaAPI).GetMethod("lua_gettop");
        private MethodInfo LuaAPI_xlua_pgettable = typeof(LuaAPI).GetMethod("xlua_pgettable");
        private MethodInfo LuaAPI_xlua_psettable = typeof(LuaAPI).GetMethod("xlua_psettable");
        private MethodInfo LuaAPI_lua_pop = typeof(LuaAPI).GetMethod("lua_pop");
        private MethodInfo LuaAPI_lua_settop = typeof(LuaAPI).GetMethod("lua_settop");
        private MethodInfo LuaAPI_luaL_error = typeof(LuaAPI).GetMethod("luaL_error");
        private MethodInfo LuaAPI_xlua_is_eq_str = typeof(LuaAPI).GetMethod("xlua_is_eq_str", new Type[] {
        typeof(RealStatePtr), typeof(int), typeof(string)});

        private MethodInfo LuaAPI_xlua_pushinteger = typeof(LuaAPI).GetMethod("xlua_pushinteger");
        private MethodInfo LuaAPI_lua_pushint64 = typeof(LuaAPI).GetMethod("lua_pushint64");
        private MethodInfo LuaAPI_lua_pushnumber = typeof(LuaAPI).GetMethod("lua_pushnumber");
        private MethodInfo LuaAPI_xlua_pushuint = typeof(LuaAPI).GetMethod("xlua_pushuint");
        private MethodInfo LuaAPI_lua_pushuint64 = typeof(LuaAPI).GetMethod("lua_pushuint64");
        private MethodInfo LuaAPI_lua_pushboolean = typeof(LuaAPI).GetMethod("lua_pushboolean");
        private MethodInfo LuaAPI_lua_pushbytes = typeof(LuaAPI).GetMethod("lua_pushstring", new Type[] { typeof(RealStatePtr), typeof(byte[]) });
        private MethodInfo LuaAPI_lua_pushlightuserdata = typeof(LuaAPI).GetMethod("lua_pushlightuserdata");
        private MethodInfo ObjectTranslator_PushDecimal = typeof(ObjectTranslator).GetMethod("PushDecimal");
        private MethodInfo ObjectTranslator_GetDecimal = typeof(ObjectTranslator).GetMethod("GetDecimal");

        private Dictionary<Type, MethodInfo> fixPush;

        private MethodInfo LuaAPI_xlua_tointeger = typeof(LuaAPI).GetMethod("xlua_tointeger");
        private MethodInfo LuaAPI_lua_tonumber = typeof(LuaAPI).GetMethod("lua_tonumber");
        private MethodInfo LuaAPI_lua_tostring = typeof(LuaAPI).GetMethod("lua_tostring");
        private MethodInfo LuaAPI_lua_toboolean = typeof(LuaAPI).GetMethod("lua_toboolean");
        private MethodInfo LuaAPI_lua_tobytes = typeof(LuaAPI).GetMethod("lua_tobytes");
        private MethodInfo LuaAPI_lua_touserdata = typeof(LuaAPI).GetMethod("lua_touserdata");
        private MethodInfo LuaAPI_xlua_touint = typeof(LuaAPI).GetMethod("xlua_touint");
        private MethodInfo LuaAPI_lua_touint64 = typeof(LuaAPI).GetMethod("lua_touint64");
        private MethodInfo LuaAPI_lua_toint64 = typeof(LuaAPI).GetMethod("lua_toint64");

        private Dictionary<Type, MethodInfo> typedCaster;
        private Dictionary<Type, MethodInfo> fixCaster;

        public CodeEmit()
        {
            fixPush = new Dictionary<Type, MethodInfo>()
            {
                {typeof(byte), LuaAPI_xlua_pushinteger},
                {typeof(char), LuaAPI_xlua_pushinteger},
                {typeof(short), LuaAPI_xlua_pushinteger},
                {typeof(int), LuaAPI_xlua_pushinteger},
                {typeof(long), LuaAPI_lua_pushint64},
                {typeof(sbyte), LuaAPI_xlua_pushinteger},
                {typeof(float), LuaAPI_lua_pushnumber},
                {typeof(ushort), LuaAPI_xlua_pushinteger},
                {typeof(uint), LuaAPI_xlua_pushuint},
                {typeof(ulong), LuaAPI_lua_pushuint64},
                {typeof(double), LuaAPI_lua_pushnumber},
                {typeof(string), LuaAPI_lua_pushstring},
                {typeof(byte[]), LuaAPI_lua_pushbytes},
                {typeof(bool), LuaAPI_lua_pushboolean},
                {typeof(IntPtr), LuaAPI_lua_pushlightuserdata},
            };

            fixCaster = new Dictionary<Type, MethodInfo>()
            {
                {typeof(double), LuaAPI_lua_tonumber},
                {typeof(string), LuaAPI_lua_tostring},
                {typeof(bool), LuaAPI_lua_toboolean},
                {typeof(byte[]), LuaAPI_lua_tobytes},
                {typeof(IntPtr), LuaAPI_lua_touserdata},
                {typeof(uint), LuaAPI_xlua_touint},
                {typeof(ulong), LuaAPI_lua_touint64},
                {typeof(int), LuaAPI_xlua_tointeger},
                {typeof(long), LuaAPI_lua_toint64},
            };

            typedCaster = new Dictionary<Type, MethodInfo>()
            {
                {typeof(byte), LuaAPI_xlua_tointeger},
                {typeof(char), LuaAPI_xlua_tointeger},
                {typeof(short), LuaAPI_xlua_tointeger},
                {typeof(sbyte), LuaAPI_xlua_tointeger},
                {typeof(float), LuaAPI_lua_tonumber},
                {typeof(ushort), LuaAPI_xlua_tointeger},
            };

            initBlackList();
        }

        private void emitPush(ILGenerator il, Type type, short dataPos, bool isParam, LocalBuilder L, LocalBuilder translator, bool isArg)
        {
            var paramElemType = type.IsByRef ? type.GetElementType() : type;
            var ldd = isArg ? OpCodes.Ldarg : OpCodes.Ldloc;
            MethodInfo pusher;
            if (fixPush.TryGetValue(paramElemType, out pusher))
            {
                il.Emit(OpCodes.Ldloc, L);
                il.Emit(ldd, dataPos);

                if (type.IsByRef)
                {
                    if (paramElemType.IsValueType)
                    {
                        il.Emit(OpCodes.Ldobj, paramElemType);
                    }
                    else
                    {
                        il.Emit(OpCodes.Ldind_Ref);
                    }
                }

                il.Emit(OpCodes.Call, pusher);
            }
            else if (paramElemType == typeof(decimal))
            {
                il.Emit(OpCodes.Ldloc, translator);
                il.Emit(OpCodes.Ldloc, L);
                il.Emit(ldd, dataPos);
                if (type.IsByRef)
                {
                    il.Emit(OpCodes.Ldobj, paramElemType);
                }
                il.Emit(OpCodes.Callvirt, ObjectTranslator_PushDecimal);
            }
            else
            {
                il.Emit(OpCodes.Ldloc, translator);
                il.Emit(OpCodes.Ldloc, L);
                il.Emit(ldd, dataPos);
                if (type.IsByRef)
                {
                    if (paramElemType.IsValueType)
                    {
                        il.Emit(OpCodes.Ldobj, paramElemType);
                        il.Emit(OpCodes.Box, paramElemType);
                    }
                    else
                    {
                        il.Emit(OpCodes.Ldind_Ref);
                    }
                }
                else if (type.IsValueType)
                {
                    il.Emit(OpCodes.Box, type);
                }
                if (isParam)
                {
                    il.Emit(OpCodes.Callvirt, ObjectTranslator_PushParams);
                }
                else
                {
                    il.Emit(OpCodes.Callvirt, ObjectTranslator_PushAny);
                }
            }
        }

        private ModuleBuilder CodeEmitModule
        {
            get
            {
                if (codeEmitModule == null)
                {
                    var assemblyName = new AssemblyName();
                    assemblyName.Name = "XLuaCodeEmit";
                    codeEmitModule = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run)
                        .DefineDynamicModule("XLuaCodeEmit");
                }
                return codeEmitModule;
            }
        }

        public Type EmitDelegateImpl(IEnumerable<IGrouping<MethodInfo, Type>> groups)
        {
            TypeBuilder impl_type_builder = CodeEmitModule.DefineType("XLuaGenDelegateImpl" + (genID++), TypeAttributes.Public, typeof(DelegateBridge));

            MethodBuilder get_deleate_by_type = impl_type_builder.DefineMethod("GetDelegateByType", MethodAttributes.Public
                    | MethodAttributes.HideBySig
                    | MethodAttributes.NewSlot
                    | MethodAttributes.Virtual
                    | MethodAttributes.Final,
                    typeof(System.Delegate), new Type[] { typeof(System.Type) });

            ILGenerator get_deleate_by_type_il = get_deleate_by_type.GetILGenerator();

            foreach (var group in groups)
            {
                var to_be_impl = group.Key;

                var method_builder = defineImplementMethod(impl_type_builder, to_be_impl, to_be_impl.Attributes, "__Gen_Delegate_Imp" + (genID++));

                emitMethodImpl(to_be_impl, method_builder.GetILGenerator(), false);

                foreach(var dt in group)
                {
                    Label end_of_if = get_deleate_by_type_il.DefineLabel();
                    get_deleate_by_type_il.Emit(OpCodes.Ldarg_1);
                    get_deleate_by_type_il.Emit(OpCodes.Ldtoken, dt);
                    get_deleate_by_type_il.Emit(OpCodes.Call, Type_GetTypeFromHandle); // typeof(type)
                    get_deleate_by_type_il.Emit(OpCodes.Bne_Un, end_of_if);

                    get_deleate_by_type_il.Emit(OpCodes.Ldarg_0);
                    get_deleate_by_type_il.Emit(OpCodes.Ldftn, method_builder);
                    get_deleate_by_type_il.Emit(OpCodes.Newobj, dt.GetConstructor(new Type[] { typeof(object), typeof(IntPtr) }));
                    get_deleate_by_type_il.Emit(OpCodes.Ret);
                    get_deleate_by_type_il.MarkLabel(end_of_if);
                }
            }

            // Constructor
            var ctor_param_types = new Type[] { typeof(int), typeof(LuaEnv) };
            ConstructorInfo parent_ctor = typeof(DelegateBridge).GetConstructor(ctor_param_types);
            var ctor_builder = impl_type_builder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, ctor_param_types);
            var ctor_il = ctor_builder.GetILGenerator();
            ctor_il.Emit(OpCodes.Ldarg_0);
            ctor_il.Emit(OpCodes.Ldarg_1);
            ctor_il.Emit(OpCodes.Ldarg_2);
            ctor_il.Emit(OpCodes.Call, parent_ctor);
            ctor_il.Emit(OpCodes.Ret);

            // end of GetDelegateByType
            get_deleate_by_type_il.Emit(OpCodes.Ldnull);
            get_deleate_by_type_il.Emit(OpCodes.Ret);

            impl_type_builder.DefineMethodOverride(get_deleate_by_type, typeof(DelegateBridgeBase).GetMethod("GetDelegateByType"));


            return impl_type_builder.CreateType();
        }

        private void EmitGetObject(ILGenerator il, int offset, Type type, LocalBuilder L, LocalBuilder translator, LocalBuilder offsetBase, bool isParam = false)
        {
            if (!fixCaster.ContainsKey(type) && !typedCaster.ContainsKey(type))
            {
                il.Emit(OpCodes.Ldloc, translator); // translator
            }
            il.Emit(OpCodes.Ldloc, L); // L
            if (offsetBase != null)
            {
                il.Emit(OpCodes.Ldloc, offsetBase); // err_func
                il.Emit(OpCodes.Ldc_I4, offset);
                il.Emit(OpCodes.Add);
            }
            else
            {
                il.Emit(OpCodes.Ldc_I4, offset);
            }

            MethodInfo caster;
            
            if (fixCaster.TryGetValue(type, out caster))
            {
                il.Emit(OpCodes.Call, caster);
            }
            else if (typedCaster.TryGetValue(type, out caster))
            {
                il.Emit(OpCodes.Call, caster);
                if (type == typeof(byte))
                {
                    il.Emit(OpCodes.Conv_U1);
                }
                else if(type == typeof(char))
                {
                    il.Emit(OpCodes.Conv_U2);
                }
                else if (type == typeof(short))
                {
                    il.Emit(OpCodes.Conv_I2);
                }
                else if (type == typeof(sbyte))
                {
                    il.Emit(OpCodes.Conv_I1);
                }
                else if (type == typeof(ushort))
                {
                    il.Emit(OpCodes.Conv_U2);
                }
                else if (type == typeof(float))
                {
                    il.Emit(OpCodes.Conv_R4);
                }
                else
                {
                    throw new InvalidProgramException(type + " is not a type need cast");
                }
            }
            else if (type == typeof(decimal))
            {
                il.Emit(OpCodes.Callvirt, ObjectTranslator_GetDecimal);
            }
            else
            {
                if (isParam)
                {
                    il.Emit(OpCodes.Callvirt, ObjectTranslator_GetParams.MakeGenericMethod(new Type[] { type.GetElementType() }));
                }
                else
                {
                    il.Emit(OpCodes.Ldtoken, type);
                    il.Emit(OpCodes.Call, Type_GetTypeFromHandle); // typeof(type)
                    il.Emit(OpCodes.Callvirt, ObjectTranslator_GetObject);
                }
                if (type.IsValueType)
                {
                    Label not_null = il.DefineLabel();
                    Label null_done = il.DefineLabel();
                    LocalBuilder local_new = il.DeclareLocal(type);

                    il.Emit(OpCodes.Dup);
                    il.Emit(OpCodes.Brtrue_S, not_null);

                    il.Emit(OpCodes.Pop);
                    il.Emit(OpCodes.Ldloca, local_new);
                    il.Emit(OpCodes.Initobj, type);
                    il.Emit(OpCodes.Ldloc, local_new);
                    il.Emit(OpCodes.Br_S, null_done);

                    il.MarkLabel(not_null);
                    il.Emit(OpCodes.Unbox_Any, type);
                    il.MarkLabel(null_done);
                }
                else if (type != typeof(object))
                {
                    il.Emit(OpCodes.Castclass, type);
                }
            }
        }

        HashSet<Type> gen_interfaces = new HashSet<Type>();

        public void SetGenInterfaces(List<Type> gen_interfaces)
        {
            gen_interfaces.ForEach((item) =>
            {
                if (!this.gen_interfaces.Contains(item))
                {
                    this.gen_interfaces.Add(item);
                }
            });
        }

        public Type EmitInterfaceImpl(Type to_be_impl)
        {
            if (!to_be_impl.IsInterface)
            {
                throw new InvalidOperationException("interface expected, but got " + to_be_impl);
            }

            if (!gen_interfaces.Contains(to_be_impl))
            {
                throw new InvalidCastException("This type must add to CSharpCallLua: " + to_be_impl.GetFriendlyName());
            }

            TypeBuilder impl_type_builder = CodeEmitModule.DefineType("XLuaGenInterfaceImpl" + (genID++), TypeAttributes.Public | TypeAttributes.Class, typeof(LuaBase), new Type[] { to_be_impl});

            foreach(var member in (new Type[] { to_be_impl }.Concat(to_be_impl.GetInterfaces()).SelectMany(i=> i.GetMembers())))
            {
                if (member.MemberType == MemberTypes.Method)
                {
                    MethodInfo method = member as MethodInfo;
                    if (method.Name.StartsWith("get_") || method.Name.StartsWith("set_") ||
                        method.Name.StartsWith("add_") || method.Name.StartsWith("remove_"))
                    {
                        continue;
                    }

                    var method_builder = defineImplementMethod(impl_type_builder, method,
                        MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual);

                    emitMethodImpl(method, method_builder.GetILGenerator(), true);
                }
                else if (member.MemberType == MemberTypes.Property)
                {
                    PropertyInfo property = member as PropertyInfo;
                    PropertyBuilder prop_builder = impl_type_builder.DefineProperty(property.Name, property.Attributes, property.PropertyType, Type.EmptyTypes);
                    if (property.Name == "Item")
                    {
                        if (property.CanRead)
                        {
                            var getter_buildler = defineImplementMethod(impl_type_builder, property.GetGetMethod(), 
                                MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig);
                            emitMethodImpl(property.GetGetMethod(), getter_buildler.GetILGenerator(), true);
                            prop_builder.SetGetMethod(getter_buildler);
                        }
                        if (property.CanWrite)
                        {
                            var setter_buildler = defineImplementMethod(impl_type_builder, property.GetSetMethod(),
                                MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig);
                            emitMethodImpl(property.GetSetMethod(), setter_buildler.GetILGenerator(), true);
                            prop_builder.SetSetMethod(setter_buildler);
                        }
                        continue;
                    }
                    if (property.CanRead)
                    {
                        MethodBuilder getter_buildler = impl_type_builder.DefineMethod("get_" + property.Name, 
                            MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
                            property.PropertyType, Type.EmptyTypes);

                        ILGenerator il = getter_buildler.GetILGenerator();

                        LocalBuilder L = il.DeclareLocal(typeof(RealStatePtr));
                        LocalBuilder oldTop = il.DeclareLocal(typeof(int));
                        LocalBuilder translator = il.DeclareLocal(typeof(ObjectTranslator));
                        LocalBuilder ret = il.DeclareLocal(property.PropertyType);

                        // L = LuaBase.L;
                        il.Emit(OpCodes.Ldarg_0);
                        il.Emit(OpCodes.Callvirt, LuaBase_L_getter);
                        il.Emit(OpCodes.Stloc, L);

                        //oldTop = LuaAPI.lua_gettop(L);
                        il.Emit(OpCodes.Ldloc, L);
                        il.Emit(OpCodes.Call, LuaAPI_lua_gettop);
                        il.Emit(OpCodes.Stloc, oldTop);

                        //translator = LuaBase.translator;
                        il.Emit(OpCodes.Ldarg_0);
                        il.Emit(OpCodes.Callvirt, LuaBase_translator_getter);
                        il.Emit(OpCodes.Stloc, translator);

                        //LuaAPI.lua_getref(L, luaReference);
                        il.Emit(OpCodes.Ldloc, L);
                        il.Emit(OpCodes.Ldarg_0);
                        il.Emit(OpCodes.Ldfld, LuaBase_luaReference);
                        il.Emit(OpCodes.Call, LuaAPI_lua_getref);

                        //LuaAPI.lua_pushstring(L, "xxx");
                        il.Emit(OpCodes.Ldloc, L);
                        il.Emit(OpCodes.Ldstr, property.Name);
                        il.Emit(OpCodes.Call, LuaAPI_lua_pushstring);

                        //LuaAPI.xlua_pgettable(L, -2)
                        il.Emit(OpCodes.Ldloc, L);
                        il.Emit(OpCodes.Ldc_I4_S, (sbyte)-2);
                        il.Emit(OpCodes.Call, LuaAPI_xlua_pgettable);
                        Label gettable_no_exception = il.DefineLabel();
                        il.Emit(OpCodes.Brfalse, gettable_no_exception);

                        il.Emit(OpCodes.Ldarg_0);
                        il.Emit(OpCodes.Ldfld, LuaBase_luaEnv);
                        il.Emit(OpCodes.Ldloc, oldTop);
                        il.Emit(OpCodes.Callvirt, LuaEnv_ThrowExceptionFromError);
                        il.MarkLabel(gettable_no_exception);

                        EmitGetObject(il, -1, property.PropertyType, L, translator, null);
                        il.Emit(OpCodes.Stloc, ret);

                        //LuaAPI.lua_pop(L, 2);
                        il.Emit(OpCodes.Ldloc, L);
                        il.Emit(OpCodes.Ldc_I4_S, (sbyte)2);
                        il.Emit(OpCodes.Call, LuaAPI_lua_pop);

                        il.Emit(OpCodes.Ldloc, ret);
                        il.Emit(OpCodes.Ret);

                        prop_builder.SetGetMethod(getter_buildler);
                    }
                    if (property.CanWrite)
                    {
                        MethodBuilder setter_builder = impl_type_builder.DefineMethod("set_" + property.Name, 
                            MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, 
                            null, new Type[] { property.PropertyType });

                        ILGenerator il = setter_builder.GetILGenerator();

                        LocalBuilder L = il.DeclareLocal(typeof(RealStatePtr));
                        LocalBuilder oldTop = il.DeclareLocal(typeof(int));
                        LocalBuilder translator = il.DeclareLocal(typeof(ObjectTranslator));

                        // L = LuaBase.L;
                        il.Emit(OpCodes.Ldarg_0);
                        il.Emit(OpCodes.Callvirt, LuaBase_L_getter);
                        il.Emit(OpCodes.Stloc, L);

                        //oldTop = LuaAPI.lua_gettop(L);
                        il.Emit(OpCodes.Ldloc, L);
                        il.Emit(OpCodes.Call, LuaAPI_lua_gettop);
                        il.Emit(OpCodes.Stloc, oldTop);

                        //translator = LuaBase.translator;
                        il.Emit(OpCodes.Ldarg_0);
                        il.Emit(OpCodes.Callvirt, LuaBase_translator_getter);
                        il.Emit(OpCodes.Stloc, translator);

                        //LuaAPI.lua_getref(L, luaReference);
                        il.Emit(OpCodes.Ldloc, L);
                        il.Emit(OpCodes.Ldarg_0);
                        il.Emit(OpCodes.Ldfld, LuaBase_luaReference);
                        il.Emit(OpCodes.Call, LuaAPI_lua_getref);

                        //LuaAPI.lua_pushstring(L, "xxx");
                        il.Emit(OpCodes.Ldloc, L);
                        il.Emit(OpCodes.Ldstr, property.Name);
                        il.Emit(OpCodes.Call, LuaAPI_lua_pushstring);

                        //translator.Push(L, value);
                        emitPush(il, property.PropertyType, 1, false, L, translator, true);

                        //LuaAPI.xlua_psettable(L, -2)
                        il.Emit(OpCodes.Ldloc, L);
                        il.Emit(OpCodes.Ldc_I4_S, (sbyte)-3);
                        il.Emit(OpCodes.Call, LuaAPI_xlua_psettable);
                        Label settable_no_exception = il.DefineLabel();
                        il.Emit(OpCodes.Brfalse, settable_no_exception);

                        il.Emit(OpCodes.Ldarg_0);
                        il.Emit(OpCodes.Ldfld, LuaBase_luaEnv);
                        il.Emit(OpCodes.Ldloc, oldTop);
                        il.Emit(OpCodes.Callvirt, LuaEnv_ThrowExceptionFromError);
                        il.MarkLabel(settable_no_exception);

                        //LuaAPI.lua_pop(L, 1);
                        il.Emit(OpCodes.Ldloc, L);
                        il.Emit(OpCodes.Ldc_I4_S, (sbyte)1);
                        il.Emit(OpCodes.Call, LuaAPI_lua_pop);

                        il.Emit(OpCodes.Ret);

                        prop_builder.SetSetMethod(setter_builder);

                    }
                }
                else if(member.MemberType == MemberTypes.Event)
                {
                    
                    EventInfo event_info = member as EventInfo;
                    EventBuilder event_builder = impl_type_builder.DefineEvent(event_info.Name, event_info.Attributes, event_info.EventHandlerType);
                    if (event_info.GetAddMethod() != null)
                    {
                        var add_buildler = defineImplementMethod(impl_type_builder, event_info.GetAddMethod(),
                            MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig);
                        emitMethodImpl(event_info.GetAddMethod(), add_buildler.GetILGenerator(), true);
                        event_builder.SetAddOnMethod(add_buildler);
                    }
                    if (event_info.GetRemoveMethod() != null)
                    {
                        var remove_buildler = defineImplementMethod(impl_type_builder, event_info.GetRemoveMethod(),
                            MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig);
                        emitMethodImpl(event_info.GetRemoveMethod(), remove_buildler.GetILGenerator(), true);
                        event_builder.SetRemoveOnMethod(remove_buildler);
                    }
                }
            }
            

            // Constructor
            var ctor_param_types = new Type[] { typeof(int), typeof(LuaEnv) };
            ConstructorInfo parent_ctor = typeof(LuaBase).GetConstructor(ctor_param_types);
            var ctor_builder = impl_type_builder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, ctor_param_types);
            var ctor_il = ctor_builder.GetILGenerator();
            ctor_il.Emit(OpCodes.Ldarg_0);
            ctor_il.Emit(OpCodes.Ldarg_1);
            ctor_il.Emit(OpCodes.Ldarg_2);
            ctor_il.Emit(OpCodes.Call, parent_ctor);
            ctor_il.Emit(OpCodes.Ret);

            return impl_type_builder.CreateType();
        }

        private void emitEmptyMethod(ILGenerator il, Type returnType)
        {
            if(returnType != typeof(void))
            {
                if (returnType.IsValueType)
                {
                    LocalBuilder local_new = il.DeclareLocal(returnType);
                    il.Emit(OpCodes.Ldloca, local_new);
                    il.Emit(OpCodes.Initobj, returnType);
                    il.Emit(OpCodes.Ldloc, local_new);
                }
                else
                {
                    il.Emit(OpCodes.Ldnull);
                }
            }
            il.Emit(OpCodes.Ret);
        }

        private MethodBuilder defineImplementMethod(TypeBuilder type_builder, MethodInfo to_be_impl, MethodAttributes attributes, string methodName = null)
        {
            var parameters = to_be_impl.GetParameters();

            Type[] param_types = new Type[parameters.Length];
            for (int i = 0; i < parameters.Length; ++i)
            {
                param_types[i] = parameters[i].ParameterType;
            }

            var method_builder = type_builder.DefineMethod(methodName == null ? to_be_impl.Name : methodName, attributes, to_be_impl.ReturnType, param_types);
            for (int i = 0; i < parameters.Length; ++i)
            {
                method_builder.DefineParameter(i + 1, parameters[i].Attributes, parameters[i].Name);
            }
            return method_builder;
        }

        ConstructorInfo decimalConstructor = typeof(decimal).GetConstructor(new Type[] {
            typeof(int), typeof(int), typeof(int), typeof(bool), typeof(byte)
        });

        private void emitLiteralLoad(ILGenerator il, Type type, object obj, int localIndex)
        {
            if (!type.IsValueType && ReferenceEquals(obj, null))
            {
                il.Emit(OpCodes.Ldnull);
            }
            else if(type.IsPrimitive || type.IsEnum())
            {
                if (type.IsEnum())
                {
                    type = Enum.GetUnderlyingType(type);
                }
                if (typeof(bool) == type)
                {
                    if ((bool)obj == true)
                    {
                        il.Emit(OpCodes.Ldc_I4_1);
                    }
                    else
                    {
                        il.Emit(OpCodes.Ldc_I4_0);
                    }
                }
                else if (typeof(uint) == type)
                {
                    il.Emit(OpCodes.Ldc_I4, (int)Convert.ToUInt32(obj));
                }
                else if(typeof(byte) == type || typeof(sbyte) == type || typeof(short) == type ||
                    typeof(ushort) == type || typeof(int) == type || typeof(char) == type)
                {
                    il.Emit(OpCodes.Ldc_I4, Convert.ToInt32(obj));
                }
                else if (typeof(long) == type)
                {
                    il.Emit(OpCodes.Ldc_I8, Convert.ToInt64(obj));
                }
                else if (typeof(ulong) == type)
                {
                    il.Emit(OpCodes.Ldc_I8, (long)Convert.ToUInt64(obj));
                }
                else if (typeof(IntPtr) == type || typeof(UIntPtr) == type)
                {
                    il.Emit(OpCodes.Ldloca, localIndex);
                    il.Emit(OpCodes.Initobj, type);
                    il.Emit(OpCodes.Ldloc, localIndex);
                }
                else if (typeof(float) == type)
                {
                    il.Emit(OpCodes.Ldc_R4, Convert.ToSingle(obj));
                }
                else if (typeof(double) == type)
                {
                    il.Emit(OpCodes.Ldc_R8, Convert.ToDouble(obj));
                }
                else
                {
                    throw new Exception(type + " is not primitive or enum!");
                }
            }
            else if (type == typeof(string))
            {
                il.Emit(OpCodes.Ldstr, obj as string);
            }
            else if (type == typeof(decimal))
            {
                var buffer = decimal.GetBits(Convert.ToDecimal(obj));
                il.Emit(OpCodes.Ldc_I4, buffer[0]);
                il.Emit(OpCodes.Ldc_I4, buffer[1]);
                il.Emit(OpCodes.Ldc_I4, buffer[2]);
                //UnityEngine.Debug.Log(string.Format("{0}.{1}.{2}.{3}--{4}", buffer[0], buffer[1], buffer[2], buffer[3], obj));
                il.Emit(OpCodes.Ldc_I4, (buffer[3] & 0x80000000) == 0 ? 0 : 1);
                il.Emit(OpCodes.Ldc_I4, (buffer[3] >> 16) & 0xFF);
                il.Emit(OpCodes.Newobj, decimalConstructor);
            }
            else if (type.IsValueType) 
            {
                il.Emit(OpCodes.Ldloca, localIndex);
                il.Emit(OpCodes.Initobj, type);
                il.Emit(OpCodes.Ldloc, localIndex);
            }
            else
            {
                il.Emit(OpCodes.Ldnull);
            }
        }

        private void emitMethodImpl(MethodInfo to_be_impl, ILGenerator il, bool isObj)
        {
            var parameters = to_be_impl.GetParameters();

            LocalBuilder L = il.DeclareLocal(typeof(RealStatePtr));//RealStatePtr L;  0
            LocalBuilder err_func = il.DeclareLocal(typeof(int));//int err_func; 1
            LocalBuilder translator = il.DeclareLocal(typeof(ObjectTranslator));//ObjectTranslator translator; 2
            LocalBuilder ret = null;
            bool has_return = to_be_impl.ReturnType != typeof(void);
            if (has_return)
            {
                ret = il.DeclareLocal(to_be_impl.ReturnType); //ReturnType ret; 3
            }

            // L = LuaBase.L;
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Callvirt, LuaBase_L_getter);
            il.Emit(OpCodes.Stloc, L);

            //err_func =LuaAPI.load_error_func(L, errorFuncRef);
            il.Emit(OpCodes.Ldloc, L);
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Callvirt, DelegateBridgeBase_errorFuncRef_getter);
            il.Emit(OpCodes.Call, LuaAPI_load_error_func);
            il.Emit(OpCodes.Stloc, err_func);

            //translator = LuaBase.translator;
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Callvirt, LuaBase_translator_getter);
            il.Emit(OpCodes.Stloc, translator);

            //LuaAPI.lua_getref(L, luaReference);
            il.Emit(OpCodes.Ldloc, L);
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldfld, LuaBase_luaReference);
            il.Emit(OpCodes.Call, LuaAPI_lua_getref);

            if (isObj)
            {
                //LuaAPI.lua_pushstring(L, "xxx");
                il.Emit(OpCodes.Ldloc, L);
                il.Emit(OpCodes.Ldstr, to_be_impl.Name);
                il.Emit(OpCodes.Call, LuaAPI_lua_pushstring);

                //LuaAPI.xlua_pgettable(L, -2)
                il.Emit(OpCodes.Ldloc, L);
                il.Emit(OpCodes.Ldc_I4_S, (sbyte)-2);
                il.Emit(OpCodes.Call, LuaAPI_xlua_pgettable);
                Label gettable_no_exception = il.DefineLabel();
                il.Emit(OpCodes.Brfalse, gettable_no_exception);

                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldfld, LuaBase_luaEnv);
                il.Emit(OpCodes.Ldloc, err_func);
                il.Emit(OpCodes.Ldc_I4_1);
                il.Emit(OpCodes.Sub);
                il.Emit(OpCodes.Callvirt, LuaEnv_ThrowExceptionFromError);
                il.MarkLabel(gettable_no_exception);

                //LuaAPI.lua_pushvalue(L, -2);
                il.Emit(OpCodes.Ldloc, L);
                il.Emit(OpCodes.Ldc_I4_S, (sbyte)-2);
                il.Emit(OpCodes.Call, LuaAPI_lua_pushvalue);

                //LuaAPI.lua_remove(L, -3);
                il.Emit(OpCodes.Ldloc, L);
                il.Emit(OpCodes.Ldc_I4_S, (sbyte)-3);
                il.Emit(OpCodes.Call, LuaAPI_lua_remove);
            }

            int in_param_count = 0;
            int out_param_count = 0;
            bool has_params = false;
            //translator.PushAny(L, param_in)
            for (int i = 0; i < parameters.Length; ++i)
            {
                var pinfo = parameters[i];
                if (!pinfo.IsOut)
                {
                    var ptype = pinfo.ParameterType;
                    bool isParam = pinfo.IsDefined(typeof(ParamArrayAttribute), false);
                    emitPush(il, ptype, (short)(i + 1), isParam, L, translator, true);
                    if (isParam)
                    {
                        has_params = true;
                    }
                    else
                    {
                        ++in_param_count;
                    }
                }

                if (pinfo.ParameterType.IsByRef)
                {
                    ++out_param_count;
                }
            }

            il.Emit(OpCodes.Ldloc, L);
            il.Emit(OpCodes.Ldc_I4, in_param_count + (isObj ? 1 : 0));
            if (has_params)
            {
                Label l1 = il.DefineLabel();

                il.Emit(OpCodes.Ldarg, (short)parameters.Length);
                il.Emit(OpCodes.Brfalse, l1);

                il.Emit(OpCodes.Ldarg, (short)parameters.Length);
                il.Emit(OpCodes.Ldlen);
                il.Emit(OpCodes.Add);
                il.MarkLabel(l1);
            }
            il.Emit(OpCodes.Ldc_I4, out_param_count + (has_return ? 1 : 0));
            il.Emit(OpCodes.Ldloc, err_func);
            il.Emit(OpCodes.Call, LuaAPI_lua_pcall);
            Label no_exception = il.DefineLabel();
            il.Emit(OpCodes.Brfalse, no_exception);

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldfld, LuaBase_luaEnv);
            il.Emit(OpCodes.Ldloc, err_func);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Sub);
            il.Emit(OpCodes.Callvirt, LuaEnv_ThrowExceptionFromError);
            il.MarkLabel(no_exception);

            int offset = 1;
            if (has_return)
            {
                EmitGetObject(il, offset++, to_be_impl.ReturnType, L, translator, err_func);
                il.Emit(OpCodes.Stloc, ret);
            }

            for (int i = 0; i < parameters.Length; ++i)
            {
                var pinfo = parameters[i];
                var ptype = pinfo.ParameterType;
                if (ptype.IsByRef)
                {
                    il.Emit(OpCodes.Ldarg, (short)(i + 1));
                    var pelemtype = ptype.GetElementType();
                    EmitGetObject(il, offset++, pelemtype, L, translator, err_func);
                    if (pelemtype.IsValueType)
                    {
                        il.Emit(OpCodes.Stobj, pelemtype);
                    }
                    else
                    {
                        il.Emit(OpCodes.Stind_Ref);
                    }

                }
            }

            if (has_return)
            {
                il.Emit(OpCodes.Ldloc, ret);
            }

            //LuaAPI.lua_settop(L, err_func - 1);
            il.Emit(OpCodes.Ldloc, L);
            il.Emit(OpCodes.Ldloc, err_func);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Sub);
            il.Emit(OpCodes.Call, LuaAPI_lua_settop);

            il.Emit(OpCodes.Ret);
        }

        private MethodInfo ObjectTranslatorPool_FindTranslator = typeof(ObjectTranslatorPool).GetMethod("FindTranslator");
        private Type[] parameterTypeOfWrap = new Type[] { typeof(RealStatePtr) };
        private MethodInfo ObjectTranslator_Assignable = typeof(ObjectTranslator).GetMethod("Assignable", new Type[] { typeof(RealStatePtr),
               typeof(int), typeof(Type)});

        private MethodInfo Utils_BeginObjectRegister = typeof(Utils).GetMethod("BeginObjectRegister");
        private MethodInfo Utils_EndObjectRegister = typeof(Utils).GetMethod("EndObjectRegister");
        private MethodInfo Utils_BeginClassRegister = typeof(Utils).GetMethod("BeginClassRegister");
        private MethodInfo Utils_EndClassRegister = typeof(Utils).GetMethod("EndClassRegister");
        private MethodInfo Utils_RegisterFunc = typeof(Utils).GetMethod("RegisterFunc");
        private MethodInfo Utils_RegisterObject = typeof(Utils).GetMethod("RegisterObject");

        private ConstructorInfo LuaCSFunction_Constructor = typeof(LuaCSFunction).GetConstructor(new Type[] { typeof(object), typeof(IntPtr) });

        private MethodInfo String_Concat = typeof(string).GetMethod("Concat", new Type[] { typeof(object), typeof(object) });

        void checkType(ILGenerator il, Type type, LocalBuilder translator, int argPos, Label endOfBlock, bool isVParam, bool isDefault)
        {
            Label endOfCheckType = il.DefineLabel();

            if (isVParam || isDefault)
            {
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldc_I4, argPos);
                il.Emit(OpCodes.Call, LuaAPI_lua_type);
                il.Emit(OpCodes.Ldc_I4_M1);
                il.Emit(OpCodes.Beq, endOfCheckType);
            }

            il.Emit(OpCodes.Ldloc, translator);
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldc_I4, argPos);
            il.Emit(OpCodes.Ldtoken, isVParam ? type.GetElementType() : type);
            il.Emit(OpCodes.Call, Type_GetTypeFromHandle); // typeof(DeclaringType)
            il.Emit(OpCodes.Callvirt, ObjectTranslator_Assignable);
            il.Emit(OpCodes.Brfalse, endOfBlock);

            il.MarkLabel(endOfCheckType);
        }

        void emitRegisterFunc(ILGenerator il, MethodBuilder method, int index, string name)
        {
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldc_I4, index);
            il.Emit(OpCodes.Ldstr, name);
            il.Emit(OpCodes.Ldnull);
            il.Emit(OpCodes.Ldftn, method);
            il.Emit(OpCodes.Newobj, LuaCSFunction_Constructor);
            il.Emit(OpCodes.Call, Utils_RegisterFunc);
        }

        void emitCatchBlock(ILGenerator il, LocalBuilder ex, LocalBuilder wrapRet, Label retPoint, Label exceptionBlock)
        {
            il.BeginCatchBlock(typeof(Exception));
            il.Emit(OpCodes.Stloc, ex);
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldstr, "c# exception:");
            il.Emit(OpCodes.Ldloc, ex);
            il.Emit(OpCodes.Call, String_Concat);
            il.Emit(OpCodes.Call, LuaAPI_luaL_error);
            il.Emit(OpCodes.Stloc, wrapRet);
            il.Emit(OpCodes.Leave, retPoint);
            il.Emit(OpCodes.Leave, exceptionBlock);

            il.EndExceptionBlock();
        }

        public MethodBuilder emitFieldWrap(TypeBuilder typeBuilder, FieldInfo field, bool genGetter)
        {
            MethodBuilder methodBuilder = typeBuilder.DefineMethod(field.Name + (genID++), MethodAttributes.Static, typeof(int), parameterTypeOfWrap);
            methodBuilder.DefineParameter(1, ParameterAttributes.None, "L");

            ILGenerator il = methodBuilder.GetILGenerator();

            LocalBuilder L = il.DeclareLocal(typeof(RealStatePtr));
            LocalBuilder translator = il.DeclareLocal(typeof(ObjectTranslator));
            LocalBuilder fieldStore = il.DeclareLocal(field.FieldType);
            LocalBuilder wrapRet = il.DeclareLocal(typeof(int));
            LocalBuilder ex = il.DeclareLocal(typeof(Exception));

            Label exceptionBlock = il.BeginExceptionBlock();
            Label retPoint = il.DefineLabel();

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Stloc, L);

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Call, ObjectTranslatorPool_FindTranslator);
            il.Emit(OpCodes.Stloc, translator);

            if (genGetter)
            {
                if (!field.IsStatic)
                {
                    EmitGetObject(il, 1, field.DeclaringType, L, translator, null);
                    il.Emit(OpCodes.Ldfld, field);
                }
                else
                {
                    il.Emit(OpCodes.Ldsfld, field);
                }
                il.Emit(OpCodes.Stloc, fieldStore);
                emitPush(il, field.FieldType, 2, false, L, translator, false);
            }
            else
            {
                if (!field.IsStatic)
                {
                    EmitGetObject(il, 1, field.DeclaringType, L, translator, null);
                    LocalBuilder self = null;
                    if (field.DeclaringType.IsValueType)
                    {
                        self = il.DeclareLocal(field.DeclaringType);
                        il.Emit(OpCodes.Stloc, self);
                        il.Emit(OpCodes.Ldloca, self);
                    }
                    EmitGetObject(il, 2, field.FieldType, L, translator, null);
                    il.Emit(OpCodes.Stfld, field);
                    if (self != null)
                    {
                        emitUpdateIfNeeded(il, L, translator, field.DeclaringType, 1, self.LocalIndex);
                    }
                }
                else
                {
                    EmitGetObject(il, 1, field.FieldType, L, translator, null);
                    il.Emit(OpCodes.Stsfld, field);
                }
            }

            il.Emit(OpCodes.Leave, exceptionBlock);

            emitCatchBlock(il, ex, wrapRet, retPoint, exceptionBlock);

            il.Emit(genGetter ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
            il.Emit(OpCodes.Ret);

            il.MarkLabel(retPoint);
            il.Emit(OpCodes.Ldloc, wrapRet);
            il.Emit(OpCodes.Ret);

            return methodBuilder;
        }

        public MethodBuilder emitPropertyWrap(TypeBuilder typeBuilder, PropertyInfo prop, MethodInfo op, bool genGetter)
        {
            MethodBuilder methodBuilder = typeBuilder.DefineMethod(prop.Name + (genID++), MethodAttributes.Static, typeof(int), parameterTypeOfWrap);
            methodBuilder.DefineParameter(1, ParameterAttributes.None, "L");

            ILGenerator il = methodBuilder.GetILGenerator();

            LocalBuilder L = il.DeclareLocal(typeof(RealStatePtr));
            LocalBuilder translator = il.DeclareLocal(typeof(ObjectTranslator));
            LocalBuilder propStore = il.DeclareLocal(prop.PropertyType);
            LocalBuilder wrapRet = il.DeclareLocal(typeof(int));
            LocalBuilder ex = il.DeclareLocal(typeof(Exception));

            Label exceptionBlock = il.BeginExceptionBlock();
            Label retPoint = il.DefineLabel();

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Stloc, L);

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Call, ObjectTranslatorPool_FindTranslator);
            il.Emit(OpCodes.Stloc, translator);

            if (genGetter)
            {
                if (!op.IsStatic)
                {
                    EmitGetObject(il, 1, prop.DeclaringType, L, translator, null);
                    if (prop.DeclaringType.IsValueType)
                    {
                        var self = il.DeclareLocal(prop.DeclaringType);
                        il.Emit(OpCodes.Stloc, self);
                        il.Emit(OpCodes.Ldloca, self);
                        il.Emit(OpCodes.Call, op);
                        emitUpdateIfNeeded(il, L, translator, prop.DeclaringType, 1, self.LocalIndex);
                    }
                    else
                    {
                        il.Emit(OpCodes.Callvirt, op);
                    }
                }
                else
                {
                    il.Emit(OpCodes.Call, op);
                }
                il.Emit(OpCodes.Stloc, propStore);
                emitPush(il, prop.PropertyType, (short)propStore.LocalIndex, false, L, translator, false);
            }
            else
            {
                if (!op.IsStatic)
                {
                    EmitGetObject(il, 1, prop.DeclaringType, L, translator, null);
                    LocalBuilder self = null;
                    if (prop.DeclaringType.IsValueType)
                    {
                        self = il.DeclareLocal(prop.DeclaringType);
                        il.Emit(OpCodes.Stloc, self);
                        il.Emit(OpCodes.Ldloca, self);
                    }
                    EmitGetObject(il, 2, prop.PropertyType, L, translator, null);
                    il.Emit(prop.DeclaringType.IsValueType ? OpCodes.Call : OpCodes.Callvirt, op);
                    if (self != null)
                    {
                        emitUpdateIfNeeded(il, L, translator, prop.DeclaringType, 1, self.LocalIndex);
                    }
                }
                else
                {
                    EmitGetObject(il, 1, prop.PropertyType, L, translator, null);
                    il.Emit(OpCodes.Call, op);
                }
            }

            il.Emit(OpCodes.Leave, exceptionBlock);

            emitCatchBlock(il, ex, wrapRet, retPoint, exceptionBlock);

            il.Emit(genGetter ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
            il.Emit(OpCodes.Ret);

            il.MarkLabel(retPoint);
            il.Emit(OpCodes.Ldloc, wrapRet);
            il.Emit(OpCodes.Ret);

            return methodBuilder;
        }

        static HashSet<MemberInfo> BlackList = new HashSet<MemberInfo>();

        static void addToBlackList(List<string> info)
        {
            try
            {
                var type = Type.GetType(info[0], true);
                var members = type.GetMember(info[1], BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly);
                foreach(var member in members)
                {
                    if (member.MemberType == MemberTypes.Method)
                    {
                        var mb = member as MethodBase;
                        var parameters = mb.GetParameters();
                        if (parameters.Length != info.Count - 2)
                        {
                            continue;
                        }

                        bool paramsMatch = true;

                        for (int i = 0; i < parameters.Length; i++)
                        {
                            if (parameters[i].ParameterType.FullName != info[i + 2])
                            {
                                paramsMatch = false;
                                break;
                            }
                        }
                        if (paramsMatch)
                        {
                            BlackList.Add(member);
                        }
                    }
                    else if (info.Count == 2)
                    {
                        BlackList.Add(member);
                    }
                }
            } catch { }
        }

        static void initBlackList()
        {
            foreach (var t in Utils.GetAllTypes(true))
            {
                if (!t.IsAbstract || !t.IsSealed) continue;

                var fields = t.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
                for (int i = 0; i < fields.Length; i++)
                {
                    var field = fields[i];
                    if (field.IsDefined(typeof(BlackListAttribute), false)
                        && (typeof(List<List<string>>)).IsAssignableFrom(field.FieldType))
                    {
                        foreach (var info in (field.GetValue(null) as List<List<string>>))
                        {
                            addToBlackList(info);
                        }
                    }
                }

                var props = t.GetProperties(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
                for (int i = 0; i < props.Length; i++)
                {
                    var prop = props[i];
                    if (prop.IsDefined(typeof(BlackListAttribute), false)
                        && (typeof(List<List<string>>)).IsAssignableFrom(prop.PropertyType))
                    {
                        foreach (var info in (prop.GetValue(null, null) as List<List<string>>))
                        {
                            addToBlackList(info);
                        }
                    }
                }
            }
        }

        static bool isMemberInBlackList(MemberInfo mb)
        {
            if (mb is FieldInfo && (mb as FieldInfo).FieldType.IsPointer) return true;
            if (mb is PropertyInfo && (mb as PropertyInfo).PropertyType.IsPointer) return true;

            if (mb.IsDefined(typeof(BlackListAttribute), false) || mb.IsDefined(typeof(ObsoleteAttribute), false)) return true;

            return BlackList.Contains(mb);
        }

        static bool isMethodInBlackList(MethodBase mb)
        {
            if (mb.GetParameters().Any(pInfo => pInfo.ParameterType.IsPointer)) return true;
            if (mb is MethodInfo && (mb as MethodInfo).ReturnType.IsPointer) return false;

            if (mb.IsDefined(typeof(BlackListAttribute), false) || mb.IsDefined(typeof(ObsoleteAttribute), false)) return true;

            return BlackList.Contains(mb);
        }

        public Type EmitTypeWrap(Type toBeWrap)
        {
            TypeBuilder wrapTypeBuilder = CodeEmitModule.DefineType(toBeWrap.Name + "Wrap" + (genID++), TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Abstract | TypeAttributes.Sealed);

            var methodBuilder = wrapTypeBuilder.DefineMethod("__Register", MethodAttributes.Static | MethodAttributes.Public, null, parameterTypeOfWrap);
            methodBuilder.DefineParameter(1, ParameterAttributes.None, "L");

            ILGenerator il = methodBuilder.GetILGenerator();

            LocalBuilder translator = il.DeclareLocal(typeof(ObjectTranslator));

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Call, ObjectTranslatorPool_FindTranslator);
            il.Emit(OpCodes.Stloc, translator);

            var instanceFlag = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly;
            var staticFlag = BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly;

            var instanceFields = toBeWrap.GetFields(instanceFlag).Where(m => !isMemberInBlackList(m));
            var instanceProperties = toBeWrap.GetProperties(instanceFlag).Where(m => !isMemberInBlackList(m));
            var extensionMethods = Utils.GetExtensionMethodsOf(toBeWrap);
            extensionMethods = (extensionMethods == null) ? Enumerable.Empty<MethodInfo>() : extensionMethods.Where(m => !isMemberInBlackList(m));
            var instanceMethods = toBeWrap.GetMethods(instanceFlag)
                .Where(m => !isMethodInBlackList(m))
                .Concat(extensionMethods)
                .Where(m => Utils.IsSupportedMethod(m))
                .Where(m => !m.IsSpecialName
                    || (
                         ((m.Name == "get_Item" && m.GetParameters().Length == 1) || (m.Name == "set_Item" && m.GetParameters().Length == 2))
                         && m.GetParameters()[0].ParameterType.IsAssignableFrom(typeof(string))
                       )
                ).GroupBy(m => m.Name).ToList();
            var supportOperators = toBeWrap.GetMethods(staticFlag)
                .Where(m => !isMethodInBlackList(m))
                .Where(m => m.IsSpecialName && InternalGlobals.supportOp.ContainsKey(m.Name))
                .GroupBy(m => m.Name);

            //begin obj
            il.Emit(OpCodes.Ldtoken, toBeWrap);
            il.Emit(OpCodes.Call, Type_GetTypeFromHandle); // typeof(type)
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldloc, translator);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Ldc_I4_M1);
            il.Emit(OpCodes.Call, Utils_BeginObjectRegister);

            foreach(var field in instanceFields)
            {
                emitRegisterFunc(il, emitFieldWrap(wrapTypeBuilder, field, true), Utils.GETTER_IDX, field.Name);
                emitRegisterFunc(il, emitFieldWrap(wrapTypeBuilder, field, false), Utils.SETTER_IDX, field.Name);
            }

            List<MethodBase> itemGetter = new List<MethodBase>();
            List<MethodBase> itemSetter = new List<MethodBase>();

            foreach(var prop in instanceProperties)
            {
                var getter = prop.GetGetMethod();
                if (getter != null && getter.IsPublic)
                {
                    if (prop.GetIndexParameters().Length > 0)
                    {
                        if (!prop.GetIndexParameters()[0].ParameterType.IsAssignableFrom(typeof(string)))
                        {
                            itemGetter.Add(getter);
                        }
                    }
                    else
                    {
                        emitRegisterFunc(il, emitPropertyWrap(wrapTypeBuilder, prop, getter, true), Utils.GETTER_IDX, prop.Name);
                    }
                }

                var setter = prop.GetSetMethod();
                if (setter != null && setter.IsPublic)
                {
                    if (prop.GetIndexParameters().Length > 0)
                    {
                        if (!prop.GetIndexParameters()[0].ParameterType.IsAssignableFrom(typeof(string)))
                        {
                            itemSetter.Add(setter);
                        }
                    }
                    else
                    {
                        emitRegisterFunc(il, emitPropertyWrap(wrapTypeBuilder, prop, setter, false), Utils.SETTER_IDX, prop.Name);
                    }
                }
            }

            foreach (var group in instanceMethods)
            {
                emitRegisterFunc(il, emitMethodWrap(wrapTypeBuilder, group.Cast<MethodBase>().ToList(), false, toBeWrap), Utils.METHOD_IDX, group.Key);
            }

            foreach (var group in supportOperators)
            {
                emitRegisterFunc(il, emitMethodWrap(wrapTypeBuilder, group.Cast<MethodBase>().ToList(), false, toBeWrap), Utils.OBJ_META_IDX, InternalGlobals.supportOp[group.Key]);
            }

            foreach (var ev in toBeWrap.GetEvents(instanceFlag).Where(m => !isMemberInBlackList(m)))
            {
                emitRegisterFunc(il, emitEventWrap(wrapTypeBuilder, ev), Utils.METHOD_IDX, ev.Name);
            }

            //end obj
            il.Emit(OpCodes.Ldtoken, toBeWrap);
            il.Emit(OpCodes.Call, Type_GetTypeFromHandle); // typeof(type)
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldloc, translator);
            il.Emit(OpCodes.Ldnull);
            if (itemGetter.Count > 0)
            {
                il.Emit(OpCodes.Ldftn, emitMethodWrap(wrapTypeBuilder, itemGetter, true, toBeWrap));
                il.Emit(OpCodes.Newobj, LuaCSFunction_Constructor);
            }
            il.Emit(OpCodes.Ldnull);
            if (itemSetter.Count > 0)
            {
                il.Emit(OpCodes.Ldftn, emitMethodWrap(wrapTypeBuilder, itemSetter, true, toBeWrap));
                il.Emit(OpCodes.Newobj, LuaCSFunction_Constructor);
            }
            il.Emit(OpCodes.Ldnull);
            il.Emit(OpCodes.Ldnull);
            il.Emit(OpCodes.Ldnull);
            il.Emit(OpCodes.Call, Utils_EndObjectRegister);

            // begin class
            il.Emit(OpCodes.Ldtoken, toBeWrap);
            il.Emit(OpCodes.Call, Type_GetTypeFromHandle); // typeof(type)
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldnull);
            il.Emit(OpCodes.Ldftn, emitMethodWrap(wrapTypeBuilder,
                toBeWrap.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase)
                .Where(m => !isMethodInBlackList(m))
                .Cast<MethodBase>().ToList(), false, toBeWrap, toBeWrap.ToString() + " constructor"));
            il.Emit(OpCodes.Newobj, LuaCSFunction_Constructor);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Call, Utils_BeginClassRegister);

            var staticMethods = toBeWrap.GetMethods(staticFlag)
                .Where(m => !isMethodInBlackList(m))
                .Where(m => Utils.IsSupportedMethod(m))
                .Where(m => !m.IsSpecialName).GroupBy(m => m.Name);

            var staticFields = toBeWrap.GetFields(staticFlag).Where(m => !isMemberInBlackList(m));

            var staticProperties = toBeWrap.GetProperties(staticFlag).Where(m => !isMemberInBlackList(m));

            foreach (var group in staticMethods)
            {
                emitRegisterFunc(il, emitMethodWrap(wrapTypeBuilder, group.Cast<MethodBase>().ToList(), false, toBeWrap), Utils.CLS_IDX, group.Key);
            }

            foreach (var ev in toBeWrap.GetEvents(staticFlag).Where(m => !isMemberInBlackList(m)))
            {
                emitRegisterFunc(il, emitEventWrap(wrapTypeBuilder, ev), Utils.CLS_IDX, ev.Name);
            }

            foreach (var prop in staticProperties)
            {
                var getter = prop.GetGetMethod();
                if (getter != null && getter.IsPublic)
                {
                    emitRegisterFunc(il, emitPropertyWrap(wrapTypeBuilder, prop, getter, true), Utils.GETTER_IDX, prop.Name);
                }

                var setter = prop.GetSetMethod();
                if (setter != null && setter.IsPublic)
                {
                    emitRegisterFunc(il, emitPropertyWrap(wrapTypeBuilder, prop, setter, false), Utils.SETTER_IDX, prop.Name);
                }
            }

            foreach (var field in staticFields)
            {
                if (field.IsInitOnly || field.IsLiteral)
                {
                    il.Emit(OpCodes.Ldarg_0);
                    il.Emit(OpCodes.Ldloc, translator);
                    il.Emit(OpCodes.Ldc_I4, Utils.CLS_IDX);
                    il.Emit(OpCodes.Ldstr, field.Name);
                    if (field.IsLiteral)
                    {
                        LocalBuilder literalStore = il.DeclareLocal(field.FieldType);
                        emitLiteralLoad(il, field.FieldType, field.GetValue(null), literalStore.LocalIndex);
                        il.Emit(OpCodes.Stloc, literalStore);
                        il.Emit(OpCodes.Ldloc, literalStore);
                    }
                    else
                    {
                        il.Emit(OpCodes.Ldsfld, field);
                    }
                    if (field.FieldType.IsValueType)
                    {
                        il.Emit(OpCodes.Box, field.FieldType);
                    }
                    il.Emit(OpCodes.Call, Utils_RegisterObject);
                }
                else
                {
                    emitRegisterFunc(il, emitFieldWrap(wrapTypeBuilder, field, true), Utils.CLS_GETTER_IDX, field.Name);
                    emitRegisterFunc(il, emitFieldWrap(wrapTypeBuilder, field, false), Utils.CLS_SETTER_IDX, field.Name);
                }
            }

            //end class
            il.Emit(OpCodes.Ldtoken, toBeWrap);
            il.Emit(OpCodes.Call, Type_GetTypeFromHandle); // typeof(type)
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldloc, translator);
            il.Emit(OpCodes.Call, Utils_EndClassRegister);

            il.Emit(OpCodes.Ret);

            return wrapTypeBuilder.CreateType();
        }

        MethodBuilder emitEventWrap(TypeBuilder typeBuilder, EventInfo ev)
        {
            var addEvent = ev.GetAddMethod();
            var removeEvent = ev.GetRemoveMethod();

            if (addEvent == null && removeEvent == null)
            {
                return null;
            }

            bool isStatic = addEvent != null ? addEvent.IsStatic : removeEvent.IsStatic;

            var methodBuilder = typeBuilder.DefineMethod(ev.Name + (genID++), MethodAttributes.Static, typeof(int), parameterTypeOfWrap);
            methodBuilder.DefineParameter(1, ParameterAttributes.None, "L");

            ILGenerator il = methodBuilder.GetILGenerator();

            LocalBuilder wrapRet = il.DeclareLocal(typeof(int));
            LocalBuilder ex = il.DeclareLocal(typeof(Exception));
            LocalBuilder L = il.DeclareLocal(typeof(RealStatePtr));
            LocalBuilder translator = il.DeclareLocal(typeof(ObjectTranslator));
            LocalBuilder callback = il.DeclareLocal(ev.EventHandlerType);

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Stloc, L);

            Label exceptionBlock = il.BeginExceptionBlock();
            Label retPoint = il.DefineLabel();

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Call, ObjectTranslatorPool_FindTranslator);
            il.Emit(OpCodes.Stloc, translator);

            EmitGetObject(il, isStatic ? 2 : 3, ev.EventHandlerType, L, translator, null);
            il.Emit(OpCodes.Stloc, callback);
            il.Emit(OpCodes.Ldloc, callback);
            Label ifBlock = il.DefineLabel();
            il.Emit(OpCodes.Brtrue, ifBlock);

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldstr, string.Format("#{0}, need {1}", isStatic ? 2 : 3, ev.EventHandlerType));
            il.Emit(OpCodes.Call, LuaAPI_luaL_error);
            il.Emit(OpCodes.Stloc, wrapRet);
            il.Emit(OpCodes.Leave, retPoint);
            il.MarkLabel(ifBlock);

            if (addEvent != null)
            {
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(isStatic ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_2);
                il.Emit(OpCodes.Ldstr, "+");
                il.Emit(OpCodes.Call, LuaAPI_xlua_is_eq_str);
                ifBlock = il.DefineLabel();
                il.Emit(OpCodes.Brfalse, ifBlock);

                if (!isStatic)
                {
                    EmitGetObject(il, 1, ev.DeclaringType, L, translator, null);
                    if (ev.DeclaringType.IsValueType)
                    {
                        var self = il.DeclareLocal(ev.DeclaringType);
                        il.Emit(OpCodes.Stloc, self);
                        il.Emit(OpCodes.Ldloca, self);
                    }
                }
                il.Emit(OpCodes.Ldloc, callback);
                il.Emit(OpCodes.Call, addEvent);
                il.Emit(OpCodes.Ldc_I4_0);
                il.Emit(OpCodes.Leave, retPoint);
                il.MarkLabel(ifBlock);
            }

            if (removeEvent != null)
            {
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(isStatic ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_2);
                il.Emit(OpCodes.Ldstr, "-");
                il.Emit(OpCodes.Call, LuaAPI_xlua_is_eq_str);
                ifBlock = il.DefineLabel();
                il.Emit(OpCodes.Brfalse, ifBlock);

                if (!isStatic)
                {
                    EmitGetObject(il, 1, ev.DeclaringType, L, translator, null);
                    if (ev.DeclaringType.IsValueType)
                    {
                        var self = il.DeclareLocal(ev.DeclaringType);
                        il.Emit(OpCodes.Stloc, self);
                        il.Emit(OpCodes.Ldloca, self);
                    }
                }
                il.Emit(OpCodes.Ldloc, callback);
                il.Emit(OpCodes.Call, removeEvent);
                il.Emit(OpCodes.Ldc_I4_0);
                il.Emit(OpCodes.Leave, retPoint);
                il.MarkLabel(ifBlock);
            }

            il.Emit(OpCodes.Leave, exceptionBlock);

            emitCatchBlock(il, ex, wrapRet, retPoint, exceptionBlock);

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldstr, "invalid arguments to " + ev.DeclaringType + "." + ev.Name + "!");
            il.Emit(OpCodes.Call, LuaAPI_luaL_error);
            il.Emit(OpCodes.Ret);

            il.MarkLabel(retPoint);
            il.Emit(OpCodes.Ldloc, wrapRet);
            il.Emit(OpCodes.Ret);

            return methodBuilder;
        }

        void emitUpdateIfNeeded(ILGenerator il, LocalBuilder L, LocalBuilder translator, Type type, int luaIndex, int localIndex)
        {
            if (type.IsValueType && !type.IsPrimitive && !type.IsEnum() && type != typeof(decimal))
            {
                //UnityEngine.Debug.LogWarning("-----------------emit update:" + type);
                il.Emit(OpCodes.Ldloc, translator);
                il.Emit(OpCodes.Ldloc, L);
                il.Emit(OpCodes.Ldc_I4, luaIndex);
                il.Emit(OpCodes.Ldloc, localIndex);
                il.Emit(OpCodes.Box, type);
                il.Emit(OpCodes.Callvirt, ObjectTranslator_Update);
            }
        }

        //private MethodInfo UnityEngine_Debug_Log = typeof(UnityEngine.Debug).GetMethod("Log", new Type[] { typeof(object)});
        int firstDefaultValue(MethodBase method)
        {
            var parameters = method.GetParameters();
            for(int i = 0; i < parameters.Length; i++)
            {
                if (parameters[i].IsOptional) return i;
            }
            return -1;
        }

        MethodBuilder emitMethodWrap(TypeBuilder typeBuilder, List<MethodBase> methodsToCall, bool isIndexer, Type declaringType, string methodDesciption = null)
        {
            string wrapName = (methodsToCall.Count > 0 ? methodsToCall[0].Name : "Constructor");
            var methodBuilder = typeBuilder.DefineMethod(wrapName + (genID++), MethodAttributes.Static, typeof(int), parameterTypeOfWrap);
            methodBuilder.DefineParameter(1,  ParameterAttributes.None, "L");

            bool needCheckParameterType = (methodsToCall.Count > 1)  || isIndexer;

            if (methodsToCall.Count == 0 || methodsToCall[0].IsConstructor)
            {
                needCheckParameterType = true;
            }

            if (methodsToCall.Count == 1 && firstDefaultValue(methodsToCall[0]) != -1)
            {
                needCheckParameterType = true;
            }

            ILGenerator il = methodBuilder.GetILGenerator();

            LocalBuilder wrapRet = il.DeclareLocal(typeof(int));
            LocalBuilder ex = il.DeclareLocal(typeof(Exception));
            LocalBuilder L = il.DeclareLocal(typeof(RealStatePtr));
            LocalBuilder translator = il.DeclareLocal(typeof(ObjectTranslator));
            LocalBuilder top = il.DeclareLocal(typeof(int));

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Stloc, L);

            Label exceptionBlock = il.BeginExceptionBlock();
            Label retPoint = il.DefineLabel();
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Call, ObjectTranslatorPool_FindTranslator);
            il.Emit(OpCodes.Stloc, translator);

            if (needCheckParameterType)
            {
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Call, LuaAPI_lua_gettop);
                il.Emit(OpCodes.Stloc, top);
            }

            for (int i = 0; i < methodsToCall.Count; i++)
            {
                var method = methodsToCall[i];
                if ((method is MethodInfo) && method.ContainsGenericParameters)
                {
                    method = Utils.MakeGenericMethodWithConstraints(method as MethodInfo);
                }
                bool isStatic = method.IsStatic;
                var paramInfos = method.GetParameters();
                int minInParamCount = 0;
                int maxInParamCount = 0;
                int outParamCount = 0;
                bool hasParams = paramInfos.Length > 0 && paramInfos[paramInfos.Length - 1].IsDefined(typeof(ParamArrayAttribute), false);
                bool hasOptional = false;

                LocalBuilder methodReturn = null;

                for (int j = 0; j < paramInfos.Length; j++)
                {
                    if (!paramInfos[j].IsOut)
                    {
                        if (!paramInfos[j].IsOptional && (!hasParams || j != paramInfos.Length - 1))
                        {
                            minInParamCount++;
                        }
                        maxInParamCount++;
                    }
                    if (paramInfos[j].IsOptional)
                    {
                        hasOptional = true;
                    }
                    if (paramInfos[j].ParameterType.IsByRef)
                    {
                        outParamCount++;
                    }
                }

                Label endOfBlock = il.DefineLabel();

                if (needCheckParameterType)
                {
                    il.Emit(OpCodes.Ldloc, top);
                    il.Emit(OpCodes.Ldc_I4, minInParamCount + (isStatic ? 0 : 1));
                    il.Emit((hasParams || hasOptional) ? OpCodes.Blt : OpCodes.Bne_Un, endOfBlock);

                    if (hasOptional && !hasParams)
                    {
                        il.Emit(OpCodes.Ldloc, top);
                        il.Emit(OpCodes.Ldc_I4, maxInParamCount + (isStatic ? 0 : 1));
                        il.Emit(OpCodes.Bgt, endOfBlock);
                    }
                    
                    if (!isStatic && !method.IsConstructor)
                    {
                        checkType(il, method.DeclaringType, translator, 1, endOfBlock, false, false);
                    }

                    int argPos = isStatic ? 1 : 2;

                    for (int j = 0; j < paramInfos.Length; j++)
                    {
                        var paramInfo = paramInfos[j];
                        if (!paramInfo.IsOut)
                        {
                            var rawParamType = paramInfo.ParameterType;
                            if (rawParamType.IsByRef)
                            {
                                rawParamType = rawParamType.GetElementType();
                            }
                            checkType(il, rawParamType, translator, argPos++, endOfBlock, 
                                hasParams && (j == paramInfos.Length - 1), paramInfo.IsOptional);
                        }
                    }
                }

                int luaPos = isStatic ? 1 : 2;

                int argStoreStart = -1;

                for (int j = 0; j < paramInfos.Length; j++)
                {
                    var paramInfo = paramInfos[j];
                    var paramRawType = paramInfo.ParameterType.IsByRef ? paramInfo.ParameterType.GetElementType() :
                        paramInfo.ParameterType;
                    var argStore = il.DeclareLocal(paramRawType);
                    if (paramInfo.IsOptional)
                    {
                        //UnityEngine.Debug.Log(paramInfo.Name + "," + paramRawType + "," + paramInfo.DefaultValue);
                        emitLiteralLoad(il, paramRawType, paramInfo.DefaultValue, argStore.LocalIndex);
                        il.Emit(OpCodes.Stloc, argStore);
                    }
                    //UnityEngine.Debug.LogWarning(declaringType.Name + "." + method.Name + "." + paramInfos[j].Name + " pos(d):" + argStore.LocalIndex + ", pt:" + paramRawType + ", j:" + j);
                    if (argStoreStart == -1)
                    {
                        argStoreStart = argStore.LocalIndex;
                    }
                    
                }
                for (int j = 0; j < paramInfos.Length; j++)
                {
                    var paramInfo = paramInfos[j];
                    var paramRawType = paramInfo.ParameterType.IsByRef ? paramInfo.ParameterType.GetElementType() :
                        paramInfo.ParameterType;
                    if (!paramInfo.IsOut)
                    {
                        Label endOfGetValue = il.DefineLabel();
                        if (paramInfo.IsOptional)
                        {
                            il.Emit(OpCodes.Ldarg_0);
                            il.Emit(OpCodes.Ldc_I4, luaPos);
                            il.Emit(OpCodes.Call, LuaAPI_lua_type);
                            il.Emit(OpCodes.Ldc_I4_M1);
                            il.Emit(OpCodes.Beq, endOfGetValue);
                        }
                        EmitGetObject(il, luaPos++, paramRawType, L, translator, null, hasParams && (j == paramInfos.Length - 1));
                        il.Emit(OpCodes.Stloc, argStoreStart + j);
                        il.MarkLabel(endOfGetValue);
                    }
                }

                LocalBuilder valueTypeTmp = null;

                if (!isStatic && (!method.IsConstructor || method.DeclaringType.IsValueType))
                {
                    if (!method.IsConstructor)
                    {
                        EmitGetObject(il, 1, method.DeclaringType, L, translator, null);
                    }
                    if (method.DeclaringType.IsValueType)
                    {
                        if (method.IsConstructor)
                        {
                            methodReturn = il.DeclareLocal(method.DeclaringType);
                            il.Emit(OpCodes.Ldloca, methodReturn);
                        }
                        else
                        {
                            valueTypeTmp = il.DeclareLocal(method.DeclaringType);
                            il.Emit(OpCodes.Stloc, valueTypeTmp);
                            il.Emit(OpCodes.Ldloca, valueTypeTmp);
                        }
                    }
                }

                for (int j = 0; j < paramInfos.Length; j++)
                {
                    //UnityEngine.Debug.LogWarning(declaringType.Name + "." + method.Name + "." + paramInfos[j].Name +" pos:" + (argStoreStart + j) + ", op:" + (paramInfos[j].ParameterType.IsByRef ? OpCodes.Ldloca : OpCodes.Ldloc) + ", j:" + j );
                    il.Emit(paramInfos[j].ParameterType.IsByRef ? OpCodes.Ldloca : OpCodes.Ldloc, argStoreStart + j);
                }

                if (method.IsConstructor)
                {
                    if (method.DeclaringType.IsValueType)
                    {
                        il.Emit(OpCodes.Call, method as ConstructorInfo);
                    }
                    else
                    {
                        il.Emit(OpCodes.Newobj, method as ConstructorInfo);
                    }
                }
                else
                {
                    il.Emit(isStatic ? OpCodes.Call : OpCodes.Callvirt, method as MethodInfo);
                }

                if (valueTypeTmp != null)
                {
                    emitUpdateIfNeeded(il, L, translator, method.DeclaringType, 1, valueTypeTmp.LocalIndex);
                }

                if (isIndexer)
                {
                    il.Emit(OpCodes.Ldarg_0);
                    il.Emit(OpCodes.Ldc_I4_1);
                    il.Emit(OpCodes.Call, LuaAPI_lua_pushboolean);
                }

                bool hasReturn = false;

                MethodInfo methodInfo = method as MethodInfo;
                if (methodInfo == null || methodInfo.ReturnType != typeof(void))
                {
                    hasReturn = true;
                    Type returnType = methodInfo == null ? method.DeclaringType : methodInfo.ReturnType;
                    if (methodReturn == null)
                    {
                        methodReturn = il.DeclareLocal(returnType);
                        il.Emit(OpCodes.Stloc, methodReturn);
                    }
                    emitPush(il, returnType, (short)methodReturn.LocalIndex, false, L, translator, false);
                }

                int luaIndex = isStatic ? 1 : 2;
                for (int j = 0; j < paramInfos.Length; j++)
                {
                    if (paramInfos[j].ParameterType.IsByRef)
                    {
                        var rawParamType = paramInfos[j].ParameterType.GetElementType();
                        emitPush(il, rawParamType,
                            (short)(argStoreStart + j), false, L, translator, false);
                        if (!paramInfos[j].IsOut)
                        {
                            emitUpdateIfNeeded(il, L, translator, rawParamType, luaIndex, argStoreStart + j);
                        }
                    }
                    if (!paramInfos[j].IsOut)
                    {
                        luaIndex++;
                    }
                }

                il.Emit(OpCodes.Ldc_I4, outParamCount + (hasReturn ? 1 : 0) + (isIndexer ? 1 : 0));
                il.Emit(OpCodes.Stloc, wrapRet);
                il.Emit(OpCodes.Leave, retPoint);
                //il.Emit(OpCodes.Ret);

                if (needCheckParameterType)
                {
                    il.MarkLabel(endOfBlock);
                }
            }

            if (declaringType.IsValueType && (methodsToCall.Count == 0 || methodsToCall[0].IsConstructor))
            {
                Label endOfBlock = il.DefineLabel();
                il.Emit(OpCodes.Ldloc, top);
                il.Emit(OpCodes.Ldc_I4_1);
                il.Emit(OpCodes.Bne_Un, endOfBlock);

                var methodReturn = il.DeclareLocal(declaringType);

                il.Emit(OpCodes.Ldloca, methodReturn);
                il.Emit(OpCodes.Initobj, declaringType);
                emitPush(il, declaringType, (short)methodReturn.LocalIndex, false, L, translator, false);
                il.Emit(OpCodes.Ldc_I4_1);
                il.Emit(OpCodes.Stloc, wrapRet);
                il.Emit(OpCodes.Leave_S, retPoint);
                il.MarkLabel(endOfBlock);
            }

            il.Emit(OpCodes.Leave, exceptionBlock);
            emitCatchBlock(il, ex, wrapRet, retPoint, exceptionBlock);

            if (needCheckParameterType)
            {
                if (isIndexer)
                {
                    il.Emit(OpCodes.Ldarg_0);
                    il.Emit(OpCodes.Ldc_I4_0);
                    il.Emit(OpCodes.Call, LuaAPI_lua_pushboolean);
                    il.Emit(OpCodes.Ldc_I4_1);
                    il.Emit(OpCodes.Ret);
                }
                else
                {
                    il.Emit(OpCodes.Ldarg_0);
                    if (methodDesciption == null)
                    {
                        if (methodsToCall.Count > 0)
                        {
                            methodDesciption = declaringType + "." + methodsToCall[0].Name;
                        }
                        else
                        {
                            methodDesciption = "unknow method in " + declaringType;
                        }
                    }
                    il.Emit(OpCodes.Ldstr, "invalid arguments to " + methodDesciption + "!");
                    il.Emit(OpCodes.Call, LuaAPI_luaL_error);
                    il.Emit(OpCodes.Ret);
                }
            }

            il.MarkLabel(retPoint);
            il.Emit(OpCodes.Ldloc, wrapRet);
            il.Emit(OpCodes.Ret);

            return methodBuilder;
        }
    }
}

#endif

/*
 * Tencent is pleased to support the open source community by making xLua available.
 * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
 * Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
 * http://opensource.org/licenses/MIT
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
*/

#if (UNITY_EDITOR || XLUA_GENERAL) && !NET_STANDARD_2_0
using System.Collections.Generic;
using System.Reflection.Emit;
using System.Reflection;
using System;
using System.Linq;

#if USE_UNI_LUA
using LuaAPI = UniLua.Lua;
using RealStatePtr = UniLua.ILuaState;
using LuaCSFunction = UniLua.CSharpFunctionDelegate;
#else
using LuaAPI = XLua.LuaDLL.Lua;
using RealStatePtr = System.IntPtr;
using LuaCSFunction = XLua.LuaDLL.lua_CSFunction;
#endif

namespace XLua
{
    public class CodeEmit
    {
        private ModuleBuilder codeEmitModule = null;
        private ulong genID = 0;

        private MethodInfo LuaEnv_ThrowExceptionFromError = typeof(LuaEnv).GetMethod("ThrowExceptionFromError");
        private FieldInfo LuaBase_luaEnv = typeof(LuaBase).GetField("luaEnv", BindingFlags.NonPublic | BindingFlags.Instance);
        private MethodInfo DelegateBridgeBase_errorFuncRef_getter = typeof(LuaBase).GetProperty("_errorFuncRef", BindingFlags.NonPublic | BindingFlags.Instance).GetGetMethod(true);
        private MethodInfo LuaAPI_load_error_func = typeof(LuaAPI).GetMethod("load_error_func");
        private MethodInfo LuaBase_translator_getter  = typeof(LuaBase).GetProperty("_translator", BindingFlags.NonPublic | BindingFlags.Instance).GetGetMethod(true);
        private FieldInfo LuaBase_luaReference = typeof(LuaBase).GetField("luaReference", BindingFlags.NonPublic | BindingFlags.Instance);
        private MethodInfo LuaAPI_lua_getref = typeof(LuaAPI).GetMethod("lua_getref");
        private MethodInfo Type_GetTypeFromHandle = typeof(Type).GetMethod("GetTypeFromHandle", new Type[] { typeof(RuntimeTypeHandle) });
        private MethodInfo ObjectTranslator_PushAny = typeof(ObjectTranslator).GetMethod("PushAny");
        private MethodInfo ObjectTranslator_PushParams = typeof(ObjectTranslator).GetMethod("PushParams");
        private MethodInfo LuaBase_L_getter = typeof(LuaBase).GetProperty("_L", BindingFlags.NonPublic | BindingFlags.Instance).GetGetMethod(true);
        private MethodInfo LuaAPI_lua_pcall = typeof(LuaAPI).GetMethod("lua_pcall");
        private MethodInfo LuaAPI_lua_type = typeof(LuaAPI).GetMethod("lua_type");
        private MethodInfo ObjectTranslator_GetObject = typeof(ObjectTranslator).GetMethod("GetObject", new Type[] { typeof(RealStatePtr),
               typeof(int), typeof(Type)});
        private MethodInfo ObjectTranslator_GetParams = typeof(ObjectTranslator).GetMethod("GetParams", new Type[] { typeof(RealStatePtr), typeof(int) });
        private MethodInfo ObjectTranslator_Update = typeof(ObjectTranslator).GetMethod("Update");
        private MethodInfo LuaAPI_lua_pushvalue = typeof(LuaAPI).GetMethod("lua_pushvalue");
        private MethodInfo LuaAPI_lua_remove = typeof(LuaAPI).GetMethod("lua_remove");
        private MethodInfo LuaAPI_lua_pushstring = typeof(LuaAPI).GetMethod("lua_pushstring", new Type[] { typeof(RealStatePtr), typeof(string)});
        private MethodInfo LuaAPI_lua_gettop = typeof(LuaAPI).GetMethod("lua_gettop");
        private MethodInfo LuaAPI_xlua_pgettable = typeof(LuaAPI).GetMethod("xlua_pgettable");
        private MethodInfo LuaAPI_xlua_psettable = typeof(LuaAPI).GetMethod("xlua_psettable");
        private MethodInfo LuaAPI_lua_pop = typeof(LuaAPI).GetMethod("lua_pop");
        private MethodInfo LuaAPI_lua_settop = typeof(LuaAPI).GetMethod("lua_settop");
        private MethodInfo LuaAPI_luaL_error = typeof(LuaAPI).GetMethod("luaL_error");
        private MethodInfo LuaAPI_xlua_is_eq_str = typeof(LuaAPI).GetMethod("xlua_is_eq_str", new Type[] {
        typeof(RealStatePtr), typeof(int), typeof(string)});

        private MethodInfo LuaAPI_xlua_pushinteger = typeof(LuaAPI).GetMethod("xlua_pushinteger");
        private MethodInfo LuaAPI_lua_pushint64 = typeof(LuaAPI).GetMethod("lua_pushint64");
        private MethodInfo LuaAPI_lua_pushnumber = typeof(LuaAPI).GetMethod("lua_pushnumber");
        private MethodInfo LuaAPI_xlua_pushuint = typeof(LuaAPI).GetMethod("xlua_pushuint");
        private MethodInfo LuaAPI_lua_pushuint64 = typeof(LuaAPI).GetMethod("lua_pushuint64");
        private MethodInfo LuaAPI_lua_pushboolean = typeof(LuaAPI).GetMethod("lua_pushboolean");
        private MethodInfo LuaAPI_lua_pushbytes = typeof(LuaAPI).GetMethod("lua_pushstring", new Type[] { typeof(RealStatePtr), typeof(byte[]) });
        private MethodInfo LuaAPI_lua_pushlightuserdata = typeof(LuaAPI).GetMethod("lua_pushlightuserdata");
        private MethodInfo ObjectTranslator_PushDecimal = typeof(ObjectTranslator).GetMethod("PushDecimal");
        private MethodInfo ObjectTranslator_GetDecimal = typeof(ObjectTranslator).GetMethod("GetDecimal");

        private Dictionary<Type, MethodInfo> fixPush;

        private MethodInfo LuaAPI_xlua_tointeger = typeof(LuaAPI).GetMethod("xlua_tointeger");
        private MethodInfo LuaAPI_lua_tonumber = typeof(LuaAPI).GetMethod("lua_tonumber");
        private MethodInfo LuaAPI_lua_tostring = typeof(LuaAPI).GetMethod("lua_tostring");
        private MethodInfo LuaAPI_lua_toboolean = typeof(LuaAPI).GetMethod("lua_toboolean");
        private MethodInfo LuaAPI_lua_tobytes = typeof(LuaAPI).GetMethod("lua_tobytes");
        private MethodInfo LuaAPI_lua_touserdata = typeof(LuaAPI).GetMethod("lua_touserdata");
        private MethodInfo LuaAPI_xlua_touint = typeof(LuaAPI).GetMethod("xlua_touint");
        private MethodInfo LuaAPI_lua_touint64 = typeof(LuaAPI).GetMethod("lua_touint64");
        private MethodInfo LuaAPI_lua_toint64 = typeof(LuaAPI).GetMethod("lua_toint64");

        private Dictionary<Type, MethodInfo> typedCaster;
        private Dictionary<Type, MethodInfo> fixCaster;

        public CodeEmit()
        {
            fixPush = new Dictionary<Type, MethodInfo>()
            {
                {typeof(byte), LuaAPI_xlua_pushinteger},
                {typeof(char), LuaAPI_xlua_pushinteger},
                {typeof(short), LuaAPI_xlua_pushinteger},
                {typeof(int), LuaAPI_xlua_pushinteger},
                {typeof(long), LuaAPI_lua_pushint64},
                {typeof(sbyte), LuaAPI_xlua_pushinteger},
                {typeof(float), LuaAPI_lua_pushnumber},
                {typeof(ushort), LuaAPI_xlua_pushinteger},
                {typeof(uint), LuaAPI_xlua_pushuint},
                {typeof(ulong), LuaAPI_lua_pushuint64},
                {typeof(double), LuaAPI_lua_pushnumber},
                {typeof(string), LuaAPI_lua_pushstring},
                {typeof(byte[]), LuaAPI_lua_pushbytes},
                {typeof(bool), LuaAPI_lua_pushboolean},
                {typeof(IntPtr), LuaAPI_lua_pushlightuserdata},
            };

            fixCaster = new Dictionary<Type, MethodInfo>()
            {
                {typeof(double), LuaAPI_lua_tonumber},
                {typeof(string), LuaAPI_lua_tostring},
                {typeof(bool), LuaAPI_lua_toboolean},
                {typeof(byte[]), LuaAPI_lua_tobytes},
                {typeof(IntPtr), LuaAPI_lua_touserdata},
                {typeof(uint), LuaAPI_xlua_touint},
                {typeof(ulong), LuaAPI_lua_touint64},
                {typeof(int), LuaAPI_xlua_tointeger},
                {typeof(long), LuaAPI_lua_toint64},
            };

            typedCaster = new Dictionary<Type, MethodInfo>()
            {
                {typeof(byte), LuaAPI_xlua_tointeger},
                {typeof(char), LuaAPI_xlua_tointeger},
                {typeof(short), LuaAPI_xlua_tointeger},
                {typeof(sbyte), LuaAPI_xlua_tointeger},
                {typeof(float), LuaAPI_lua_tonumber},
                {typeof(ushort), LuaAPI_xlua_tointeger},
            };

            initBlackList();
        }

        private void emitPush(ILGenerator il, Type type, short dataPos, bool isParam, LocalBuilder L, LocalBuilder translator, bool isArg)
        {
            var paramElemType = type.IsByRef ? type.GetElementType() : type;
            var ldd = isArg ? OpCodes.Ldarg : OpCodes.Ldloc;
            MethodInfo pusher;
            if (fixPush.TryGetValue(paramElemType, out pusher))
            {
                il.Emit(OpCodes.Ldloc, L);
                il.Emit(ldd, dataPos);

                if (type.IsByRef)
                {
                    if (paramElemType.IsValueType)
                    {
                        il.Emit(OpCodes.Ldobj, paramElemType);
                    }
                    else
                    {
                        il.Emit(OpCodes.Ldind_Ref);
                    }
                }

                il.Emit(OpCodes.Call, pusher);
            }
            else if (paramElemType == typeof(decimal))
            {
                il.Emit(OpCodes.Ldloc, translator);
                il.Emit(OpCodes.Ldloc, L);
                il.Emit(ldd, dataPos);
                if (type.IsByRef)
                {
                    il.Emit(OpCodes.Ldobj, paramElemType);
                }
                il.Emit(OpCodes.Callvirt, ObjectTranslator_PushDecimal);
            }
            else
            {
                il.Emit(OpCodes.Ldloc, translator);
                il.Emit(OpCodes.Ldloc, L);
                il.Emit(ldd, dataPos);
                if (type.IsByRef)
                {
                    if (paramElemType.IsValueType)
                    {
                        il.Emit(OpCodes.Ldobj, paramElemType);
                        il.Emit(OpCodes.Box, paramElemType);
                    }
                    else
                    {
                        il.Emit(OpCodes.Ldind_Ref);
                    }
                }
                else if (type.IsValueType)
                {
                    il.Emit(OpCodes.Box, type);
                }
                if (isParam)
                {
                    il.Emit(OpCodes.Callvirt, ObjectTranslator_PushParams);
                }
                else
                {
                    il.Emit(OpCodes.Callvirt, ObjectTranslator_PushAny);
                }
            }
        }

        private ModuleBuilder CodeEmitModule
        {
            get
            {
                if (codeEmitModule == null)
                {
                    var assemblyName = new AssemblyName();
                    assemblyName.Name = "XLuaCodeEmit";
                    codeEmitModule = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run)
                        .DefineDynamicModule("XLuaCodeEmit");
                }
                return codeEmitModule;
            }
        }

        public Type EmitDelegateImpl(IEnumerable<IGrouping<MethodInfo, Type>> groups)
        {
            TypeBuilder impl_type_builder = CodeEmitModule.DefineType("XLuaGenDelegateImpl" + (genID++), TypeAttributes.Public, typeof(DelegateBridge));

            MethodBuilder get_deleate_by_type = impl_type_builder.DefineMethod("GetDelegateByType", MethodAttributes.Public
                    | MethodAttributes.HideBySig
                    | MethodAttributes.NewSlot
                    | MethodAttributes.Virtual
                    | MethodAttributes.Final,
                    typeof(System.Delegate), new Type[] { typeof(System.Type) });

            ILGenerator get_deleate_by_type_il = get_deleate_by_type.GetILGenerator();

            foreach (var group in groups)
            {
                var to_be_impl = group.Key;

                var method_builder = defineImplementMethod(impl_type_builder, to_be_impl, to_be_impl.Attributes, "__Gen_Delegate_Imp" + (genID++));

                emitMethodImpl(to_be_impl, method_builder.GetILGenerator(), false);

                foreach(var dt in group)
                {
                    Label end_of_if = get_deleate_by_type_il.DefineLabel();
                    get_deleate_by_type_il.Emit(OpCodes.Ldarg_1);
                    get_deleate_by_type_il.Emit(OpCodes.Ldtoken, dt);
                    get_deleate_by_type_il.Emit(OpCodes.Call, Type_GetTypeFromHandle); // typeof(type)
                    get_deleate_by_type_il.Emit(OpCodes.Bne_Un, end_of_if);

                    get_deleate_by_type_il.Emit(OpCodes.Ldarg_0);
                    get_deleate_by_type_il.Emit(OpCodes.Ldftn, method_builder);
                    get_deleate_by_type_il.Emit(OpCodes.Newobj, dt.GetConstructor(new Type[] { typeof(object), typeof(IntPtr) }));
                    get_deleate_by_type_il.Emit(OpCodes.Ret);
                    get_deleate_by_type_il.MarkLabel(end_of_if);
                }
            }

            // Constructor
            var ctor_param_types = new Type[] { typeof(int), typeof(LuaEnv) };
            ConstructorInfo parent_ctor = typeof(DelegateBridge).GetConstructor(ctor_param_types);
            var ctor_builder = impl_type_builder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, ctor_param_types);
            var ctor_il = ctor_builder.GetILGenerator();
            ctor_il.Emit(OpCodes.Ldarg_0);
            ctor_il.Emit(OpCodes.Ldarg_1);
            ctor_il.Emit(OpCodes.Ldarg_2);
            ctor_il.Emit(OpCodes.Call, parent_ctor);
            ctor_il.Emit(OpCodes.Ret);

            // end of GetDelegateByType
            get_deleate_by_type_il.Emit(OpCodes.Ldnull);
            get_deleate_by_type_il.Emit(OpCodes.Ret);

            impl_type_builder.DefineMethodOverride(get_deleate_by_type, typeof(DelegateBridgeBase).GetMethod("GetDelegateByType"));


            return impl_type_builder.CreateType();
        }

        private void EmitGetObject(ILGenerator il, int offset, Type type, LocalBuilder L, LocalBuilder translator, LocalBuilder offsetBase, bool isParam = false)
        {
            if (!fixCaster.ContainsKey(type) && !typedCaster.ContainsKey(type))
            {
                il.Emit(OpCodes.Ldloc, translator); // translator
            }
            il.Emit(OpCodes.Ldloc, L); // L
            if (offsetBase != null)
            {
                il.Emit(OpCodes.Ldloc, offsetBase); // err_func
                il.Emit(OpCodes.Ldc_I4, offset);
                il.Emit(OpCodes.Add);
            }
            else
            {
                il.Emit(OpCodes.Ldc_I4, offset);
            }

            MethodInfo caster;
            
            if (fixCaster.TryGetValue(type, out caster))
            {
                il.Emit(OpCodes.Call, caster);
            }
            else if (typedCaster.TryGetValue(type, out caster))
            {
                il.Emit(OpCodes.Call, caster);
                if (type == typeof(byte))
                {
                    il.Emit(OpCodes.Conv_U1);
                }
                else if(type == typeof(char))
                {
                    il.Emit(OpCodes.Conv_U2);
                }
                else if (type == typeof(short))
                {
                    il.Emit(OpCodes.Conv_I2);
                }
                else if (type == typeof(sbyte))
                {
                    il.Emit(OpCodes.Conv_I1);
                }
                else if (type == typeof(ushort))
                {
                    il.Emit(OpCodes.Conv_U2);
                }
                else if (type == typeof(float))
                {
                    il.Emit(OpCodes.Conv_R4);
                }
                else
                {
                    throw new InvalidProgramException(type + " is not a type need cast");
                }
            }
            else if (type == typeof(decimal))
            {
                il.Emit(OpCodes.Callvirt, ObjectTranslator_GetDecimal);
            }
            else
            {
                if (isParam)
                {
                    il.Emit(OpCodes.Callvirt, ObjectTranslator_GetParams.MakeGenericMethod(new Type[] { type.GetElementType() }));
                }
                else
                {
                    il.Emit(OpCodes.Ldtoken, type);
                    il.Emit(OpCodes.Call, Type_GetTypeFromHandle); // typeof(type)
                    il.Emit(OpCodes.Callvirt, ObjectTranslator_GetObject);
                }
                if (type.IsValueType)
                {
                    Label not_null = il.DefineLabel();
                    Label null_done = il.DefineLabel();
                    LocalBuilder local_new = il.DeclareLocal(type);

                    il.Emit(OpCodes.Dup);
                    il.Emit(OpCodes.Brtrue_S, not_null);

                    il.Emit(OpCodes.Pop);
                    il.Emit(OpCodes.Ldloca, local_new);
                    il.Emit(OpCodes.Initobj, type);
                    il.Emit(OpCodes.Ldloc, local_new);
                    il.Emit(OpCodes.Br_S, null_done);

                    il.MarkLabel(not_null);
                    il.Emit(OpCodes.Unbox_Any, type);
                    il.MarkLabel(null_done);
                }
                else if (type != typeof(object))
                {
                    il.Emit(OpCodes.Castclass, type);
                }
            }
        }

        HashSet<Type> gen_interfaces = new HashSet<Type>();

        public void SetGenInterfaces(List<Type> gen_interfaces)
        {
            gen_interfaces.ForEach((item) =>
            {
                if (!this.gen_interfaces.Contains(item))
                {
                    this.gen_interfaces.Add(item);
                }
            });
        }

        public Type EmitInterfaceImpl(Type to_be_impl)
        {
            if (!to_be_impl.IsInterface)
            {
                throw new InvalidOperationException("interface expected, but got " + to_be_impl);
            }

            if (!gen_interfaces.Contains(to_be_impl))
            {
                throw new InvalidCastException("This type must add to CSharpCallLua: " + to_be_impl.GetFriendlyName());
            }

            TypeBuilder impl_type_builder = CodeEmitModule.DefineType("XLuaGenInterfaceImpl" + (genID++), TypeAttributes.Public | TypeAttributes.Class, typeof(LuaBase), new Type[] { to_be_impl});

            foreach(var member in (new Type[] { to_be_impl }.Concat(to_be_impl.GetInterfaces()).SelectMany(i=> i.GetMembers())))
            {
                if (member.MemberType == MemberTypes.Method)
                {
                    MethodInfo method = member as MethodInfo;
                    if (method.Name.StartsWith("get_") || method.Name.StartsWith("set_") ||
                        method.Name.StartsWith("add_") || method.Name.StartsWith("remove_"))
                    {
                        continue;
                    }

                    var method_builder = defineImplementMethod(impl_type_builder, method,
                        MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual);

                    emitMethodImpl(method, method_builder.GetILGenerator(), true);
                }
                else if (member.MemberType == MemberTypes.Property)
                {
                    PropertyInfo property = member as PropertyInfo;
                    PropertyBuilder prop_builder = impl_type_builder.DefineProperty(property.Name, property.Attributes, property.PropertyType, Type.EmptyTypes);
                    if (property.Name == "Item")
                    {
                        if (property.CanRead)
                        {
                            var getter_buildler = defineImplementMethod(impl_type_builder, property.GetGetMethod(), 
                                MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig);
                            emitMethodImpl(property.GetGetMethod(), getter_buildler.GetILGenerator(), true);
                            prop_builder.SetGetMethod(getter_buildler);
                        }
                        if (property.CanWrite)
                        {
                            var setter_buildler = defineImplementMethod(impl_type_builder, property.GetSetMethod(),
                                MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig);
                            emitMethodImpl(property.GetSetMethod(), setter_buildler.GetILGenerator(), true);
                            prop_builder.SetSetMethod(setter_buildler);
                        }
                        continue;
                    }
                    if (property.CanRead)
                    {
                        MethodBuilder getter_buildler = impl_type_builder.DefineMethod("get_" + property.Name, 
                            MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
                            property.PropertyType, Type.EmptyTypes);

                        ILGenerator il = getter_buildler.GetILGenerator();

                        LocalBuilder L = il.DeclareLocal(typeof(RealStatePtr));
                        LocalBuilder oldTop = il.DeclareLocal(typeof(int));
                        LocalBuilder translator = il.DeclareLocal(typeof(ObjectTranslator));
                        LocalBuilder ret = il.DeclareLocal(property.PropertyType);

                        // L = LuaBase.L;
                        il.Emit(OpCodes.Ldarg_0);
                        il.Emit(OpCodes.Callvirt, LuaBase_L_getter);
                        il.Emit(OpCodes.Stloc, L);

                        //oldTop = LuaAPI.lua_gettop(L);
                        il.Emit(OpCodes.Ldloc, L);
                        il.Emit(OpCodes.Call, LuaAPI_lua_gettop);
                        il.Emit(OpCodes.Stloc, oldTop);

                        //translator = LuaBase.translator;
                        il.Emit(OpCodes.Ldarg_0);
                        il.Emit(OpCodes.Callvirt, LuaBase_translator_getter);
                        il.Emit(OpCodes.Stloc, translator);

                        //LuaAPI.lua_getref(L, luaReference);
                        il.Emit(OpCodes.Ldloc, L);
                        il.Emit(OpCodes.Ldarg_0);
                        il.Emit(OpCodes.Ldfld, LuaBase_luaReference);
                        il.Emit(OpCodes.Call, LuaAPI_lua_getref);

                        //LuaAPI.lua_pushstring(L, "xxx");
                        il.Emit(OpCodes.Ldloc, L);
                        il.Emit(OpCodes.Ldstr, property.Name);
                        il.Emit(OpCodes.Call, LuaAPI_lua_pushstring);

                        //LuaAPI.xlua_pgettable(L, -2)
                        il.Emit(OpCodes.Ldloc, L);
                        il.Emit(OpCodes.Ldc_I4_S, (sbyte)-2);
                        il.Emit(OpCodes.Call, LuaAPI_xlua_pgettable);
                        Label gettable_no_exception = il.DefineLabel();
                        il.Emit(OpCodes.Brfalse, gettable_no_exception);

                        il.Emit(OpCodes.Ldarg_0);
                        il.Emit(OpCodes.Ldfld, LuaBase_luaEnv);
                        il.Emit(OpCodes.Ldloc, oldTop);
                        il.Emit(OpCodes.Callvirt, LuaEnv_ThrowExceptionFromError);
                        il.MarkLabel(gettable_no_exception);

                        EmitGetObject(il, -1, property.PropertyType, L, translator, null);
                        il.Emit(OpCodes.Stloc, ret);

                        //LuaAPI.lua_pop(L, 2);
                        il.Emit(OpCodes.Ldloc, L);
                        il.Emit(OpCodes.Ldc_I4_S, (sbyte)2);
                        il.Emit(OpCodes.Call, LuaAPI_lua_pop);

                        il.Emit(OpCodes.Ldloc, ret);
                        il.Emit(OpCodes.Ret);

                        prop_builder.SetGetMethod(getter_buildler);
                    }
                    if (property.CanWrite)
                    {
                        MethodBuilder setter_builder = impl_type_builder.DefineMethod("set_" + property.Name, 
                            MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, 
                            null, new Type[] { property.PropertyType });

                        ILGenerator il = setter_builder.GetILGenerator();

                        LocalBuilder L = il.DeclareLocal(typeof(RealStatePtr));
                        LocalBuilder oldTop = il.DeclareLocal(typeof(int));
                        LocalBuilder translator = il.DeclareLocal(typeof(ObjectTranslator));

                        // L = LuaBase.L;
                        il.Emit(OpCodes.Ldarg_0);
                        il.Emit(OpCodes.Callvirt, LuaBase_L_getter);
                        il.Emit(OpCodes.Stloc, L);

                        //oldTop = LuaAPI.lua_gettop(L);
                        il.Emit(OpCodes.Ldloc, L);
                        il.Emit(OpCodes.Call, LuaAPI_lua_gettop);
                        il.Emit(OpCodes.Stloc, oldTop);

                        //translator = LuaBase.translator;
                        il.Emit(OpCodes.Ldarg_0);
                        il.Emit(OpCodes.Callvirt, LuaBase_translator_getter);
                        il.Emit(OpCodes.Stloc, translator);

                        //LuaAPI.lua_getref(L, luaReference);
                        il.Emit(OpCodes.Ldloc, L);
                        il.Emit(OpCodes.Ldarg_0);
                        il.Emit(OpCodes.Ldfld, LuaBase_luaReference);
                        il.Emit(OpCodes.Call, LuaAPI_lua_getref);

                        //LuaAPI.lua_pushstring(L, "xxx");
                        il.Emit(OpCodes.Ldloc, L);
                        il.Emit(OpCodes.Ldstr, property.Name);
                        il.Emit(OpCodes.Call, LuaAPI_lua_pushstring);

                        //translator.Push(L, value);
                        emitPush(il, property.PropertyType, 1, false, L, translator, true);

                        //LuaAPI.xlua_psettable(L, -2)
                        il.Emit(OpCodes.Ldloc, L);
                        il.Emit(OpCodes.Ldc_I4_S, (sbyte)-3);
                        il.Emit(OpCodes.Call, LuaAPI_xlua_psettable);
                        Label settable_no_exception = il.DefineLabel();
                        il.Emit(OpCodes.Brfalse, settable_no_exception);

                        il.Emit(OpCodes.Ldarg_0);
                        il.Emit(OpCodes.Ldfld, LuaBase_luaEnv);
                        il.Emit(OpCodes.Ldloc, oldTop);
                        il.Emit(OpCodes.Callvirt, LuaEnv_ThrowExceptionFromError);
                        il.MarkLabel(settable_no_exception);

                        //LuaAPI.lua_pop(L, 1);
                        il.Emit(OpCodes.Ldloc, L);
                        il.Emit(OpCodes.Ldc_I4_S, (sbyte)1);
                        il.Emit(OpCodes.Call, LuaAPI_lua_pop);

                        il.Emit(OpCodes.Ret);

                        prop_builder.SetSetMethod(setter_builder);

                    }
                }
                else if(member.MemberType == MemberTypes.Event)
                {
                    
                    EventInfo event_info = member as EventInfo;
                    EventBuilder event_builder = impl_type_builder.DefineEvent(event_info.Name, event_info.Attributes, event_info.EventHandlerType);
                    if (event_info.GetAddMethod() != null)
                    {
                        var add_buildler = defineImplementMethod(impl_type_builder, event_info.GetAddMethod(),
                            MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig);
                        emitMethodImpl(event_info.GetAddMethod(), add_buildler.GetILGenerator(), true);
                        event_builder.SetAddOnMethod(add_buildler);
                    }
                    if (event_info.GetRemoveMethod() != null)
                    {
                        var remove_buildler = defineImplementMethod(impl_type_builder, event_info.GetRemoveMethod(),
                            MethodAttributes.Virtual | MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig);
                        emitMethodImpl(event_info.GetRemoveMethod(), remove_buildler.GetILGenerator(), true);
                        event_builder.SetRemoveOnMethod(remove_buildler);
                    }
                }
            }
            

            // Constructor
            var ctor_param_types = new Type[] { typeof(int), typeof(LuaEnv) };
            ConstructorInfo parent_ctor = typeof(LuaBase).GetConstructor(ctor_param_types);
            var ctor_builder = impl_type_builder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, ctor_param_types);
            var ctor_il = ctor_builder.GetILGenerator();
            ctor_il.Emit(OpCodes.Ldarg_0);
            ctor_il.Emit(OpCodes.Ldarg_1);
            ctor_il.Emit(OpCodes.Ldarg_2);
            ctor_il.Emit(OpCodes.Call, parent_ctor);
            ctor_il.Emit(OpCodes.Ret);

            return impl_type_builder.CreateType();
        }

        private void emitEmptyMethod(ILGenerator il, Type returnType)
        {
            if(returnType != typeof(void))
            {
                if (returnType.IsValueType)
                {
                    LocalBuilder local_new = il.DeclareLocal(returnType);
                    il.Emit(OpCodes.Ldloca, local_new);
                    il.Emit(OpCodes.Initobj, returnType);
                    il.Emit(OpCodes.Ldloc, local_new);
                }
                else
                {
                    il.Emit(OpCodes.Ldnull);
                }
            }
            il.Emit(OpCodes.Ret);
        }

        private MethodBuilder defineImplementMethod(TypeBuilder type_builder, MethodInfo to_be_impl, MethodAttributes attributes, string methodName = null)
        {
            var parameters = to_be_impl.GetParameters();

            Type[] param_types = new Type[parameters.Length];
            for (int i = 0; i < parameters.Length; ++i)
            {
                param_types[i] = parameters[i].ParameterType;
            }

            var method_builder = type_builder.DefineMethod(methodName == null ? to_be_impl.Name : methodName, attributes, to_be_impl.ReturnType, param_types);
            for (int i = 0; i < parameters.Length; ++i)
            {
                method_builder.DefineParameter(i + 1, parameters[i].Attributes, parameters[i].Name);
            }
            return method_builder;
        }

        ConstructorInfo decimalConstructor = typeof(decimal).GetConstructor(new Type[] {
            typeof(int), typeof(int), typeof(int), typeof(bool), typeof(byte)
        });

        private void emitLiteralLoad(ILGenerator il, Type type, object obj, int localIndex)
        {
            if (!type.IsValueType && ReferenceEquals(obj, null))
            {
                il.Emit(OpCodes.Ldnull);
            }
            else if(type.IsPrimitive || type.IsEnum())
            {
                if (type.IsEnum())
                {
                    type = Enum.GetUnderlyingType(type);
                }
                if (typeof(bool) == type)
                {
                    if ((bool)obj == true)
                    {
                        il.Emit(OpCodes.Ldc_I4_1);
                    }
                    else
                    {
                        il.Emit(OpCodes.Ldc_I4_0);
                    }
                }
                else if (typeof(uint) == type)
                {
                    il.Emit(OpCodes.Ldc_I4, (int)Convert.ToUInt32(obj));
                }
                else if(typeof(byte) == type || typeof(sbyte) == type || typeof(short) == type ||
                    typeof(ushort) == type || typeof(int) == type || typeof(char) == type)
                {
                    il.Emit(OpCodes.Ldc_I4, Convert.ToInt32(obj));
                }
                else if (typeof(long) == type)
                {
                    il.Emit(OpCodes.Ldc_I8, Convert.ToInt64(obj));
                }
                else if (typeof(ulong) == type)
                {
                    il.Emit(OpCodes.Ldc_I8, (long)Convert.ToUInt64(obj));
                }
                else if (typeof(IntPtr) == type || typeof(UIntPtr) == type)
                {
                    il.Emit(OpCodes.Ldloca, localIndex);
                    il.Emit(OpCodes.Initobj, type);
                    il.Emit(OpCodes.Ldloc, localIndex);
                }
                else if (typeof(float) == type)
                {
                    il.Emit(OpCodes.Ldc_R4, Convert.ToSingle(obj));
                }
                else if (typeof(double) == type)
                {
                    il.Emit(OpCodes.Ldc_R8, Convert.ToDouble(obj));
                }
                else
                {
                    throw new Exception(type + " is not primitive or enum!");
                }
            }
            else if (type == typeof(string))
            {
                il.Emit(OpCodes.Ldstr, obj as string);
            }
            else if (type == typeof(decimal))
            {
                var buffer = decimal.GetBits(Convert.ToDecimal(obj));
                il.Emit(OpCodes.Ldc_I4, buffer[0]);
                il.Emit(OpCodes.Ldc_I4, buffer[1]);
                il.Emit(OpCodes.Ldc_I4, buffer[2]);
                //UnityEngine.Debug.Log(string.Format("{0}.{1}.{2}.{3}--{4}", buffer[0], buffer[1], buffer[2], buffer[3], obj));
                il.Emit(OpCodes.Ldc_I4, (buffer[3] & 0x80000000) == 0 ? 0 : 1);
                il.Emit(OpCodes.Ldc_I4, (buffer[3] >> 16) & 0xFF);
                il.Emit(OpCodes.Newobj, decimalConstructor);
            }
            else if (type.IsValueType) 
            {
                il.Emit(OpCodes.Ldloca, localIndex);
                il.Emit(OpCodes.Initobj, type);
                il.Emit(OpCodes.Ldloc, localIndex);
            }
            else
            {
                il.Emit(OpCodes.Ldnull);
            }
        }

        private void emitMethodImpl(MethodInfo to_be_impl, ILGenerator il, bool isObj)
        {
            var parameters = to_be_impl.GetParameters();

            LocalBuilder L = il.DeclareLocal(typeof(RealStatePtr));//RealStatePtr L;  0
            LocalBuilder err_func = il.DeclareLocal(typeof(int));//int err_func; 1
            LocalBuilder translator = il.DeclareLocal(typeof(ObjectTranslator));//ObjectTranslator translator; 2
            LocalBuilder ret = null;
            bool has_return = to_be_impl.ReturnType != typeof(void);
            if (has_return)
            {
                ret = il.DeclareLocal(to_be_impl.ReturnType); //ReturnType ret; 3
            }

            // L = LuaBase.L;
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Callvirt, LuaBase_L_getter);
            il.Emit(OpCodes.Stloc, L);

            //err_func =LuaAPI.load_error_func(L, errorFuncRef);
            il.Emit(OpCodes.Ldloc, L);
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Callvirt, DelegateBridgeBase_errorFuncRef_getter);
            il.Emit(OpCodes.Call, LuaAPI_load_error_func);
            il.Emit(OpCodes.Stloc, err_func);

            //translator = LuaBase.translator;
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Callvirt, LuaBase_translator_getter);
            il.Emit(OpCodes.Stloc, translator);

            //LuaAPI.lua_getref(L, luaReference);
            il.Emit(OpCodes.Ldloc, L);
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldfld, LuaBase_luaReference);
            il.Emit(OpCodes.Call, LuaAPI_lua_getref);

            if (isObj)
            {
                //LuaAPI.lua_pushstring(L, "xxx");
                il.Emit(OpCodes.Ldloc, L);
                il.Emit(OpCodes.Ldstr, to_be_impl.Name);
                il.Emit(OpCodes.Call, LuaAPI_lua_pushstring);

                //LuaAPI.xlua_pgettable(L, -2)
                il.Emit(OpCodes.Ldloc, L);
                il.Emit(OpCodes.Ldc_I4_S, (sbyte)-2);
                il.Emit(OpCodes.Call, LuaAPI_xlua_pgettable);
                Label gettable_no_exception = il.DefineLabel();
                il.Emit(OpCodes.Brfalse, gettable_no_exception);

                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldfld, LuaBase_luaEnv);
                il.Emit(OpCodes.Ldloc, err_func);
                il.Emit(OpCodes.Ldc_I4_1);
                il.Emit(OpCodes.Sub);
                il.Emit(OpCodes.Callvirt, LuaEnv_ThrowExceptionFromError);
                il.MarkLabel(gettable_no_exception);

                //LuaAPI.lua_pushvalue(L, -2);
                il.Emit(OpCodes.Ldloc, L);
                il.Emit(OpCodes.Ldc_I4_S, (sbyte)-2);
                il.Emit(OpCodes.Call, LuaAPI_lua_pushvalue);

                //LuaAPI.lua_remove(L, -3);
                il.Emit(OpCodes.Ldloc, L);
                il.Emit(OpCodes.Ldc_I4_S, (sbyte)-3);
                il.Emit(OpCodes.Call, LuaAPI_lua_remove);
            }

            int in_param_count = 0;
            int out_param_count = 0;
            bool has_params = false;
            //translator.PushAny(L, param_in)
            for (int i = 0; i < parameters.Length; ++i)
            {
                var pinfo = parameters[i];
                if (!pinfo.IsOut)
                {
                    var ptype = pinfo.ParameterType;
                    bool isParam = pinfo.IsDefined(typeof(ParamArrayAttribute), false);
                    emitPush(il, ptype, (short)(i + 1), isParam, L, translator, true);
                    if (isParam)
                    {
                        has_params = true;
                    }
                    else
                    {
                        ++in_param_count;
                    }
                }

                if (pinfo.ParameterType.IsByRef)
                {
                    ++out_param_count;
                }
            }

            il.Emit(OpCodes.Ldloc, L);
            il.Emit(OpCodes.Ldc_I4, in_param_count + (isObj ? 1 : 0));
            if (has_params)
            {
                Label l1 = il.DefineLabel();

                il.Emit(OpCodes.Ldarg, (short)parameters.Length);
                il.Emit(OpCodes.Brfalse, l1);

                il.Emit(OpCodes.Ldarg, (short)parameters.Length);
                il.Emit(OpCodes.Ldlen);
                il.Emit(OpCodes.Add);
                il.MarkLabel(l1);
            }
            il.Emit(OpCodes.Ldc_I4, out_param_count + (has_return ? 1 : 0));
            il.Emit(OpCodes.Ldloc, err_func);
            il.Emit(OpCodes.Call, LuaAPI_lua_pcall);
            Label no_exception = il.DefineLabel();
            il.Emit(OpCodes.Brfalse, no_exception);

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldfld, LuaBase_luaEnv);
            il.Emit(OpCodes.Ldloc, err_func);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Sub);
            il.Emit(OpCodes.Callvirt, LuaEnv_ThrowExceptionFromError);
            il.MarkLabel(no_exception);

            int offset = 1;
            if (has_return)
            {
                EmitGetObject(il, offset++, to_be_impl.ReturnType, L, translator, err_func);
                il.Emit(OpCodes.Stloc, ret);
            }

            for (int i = 0; i < parameters.Length; ++i)
            {
                var pinfo = parameters[i];
                var ptype = pinfo.ParameterType;
                if (ptype.IsByRef)
                {
                    il.Emit(OpCodes.Ldarg, (short)(i + 1));
                    var pelemtype = ptype.GetElementType();
                    EmitGetObject(il, offset++, pelemtype, L, translator, err_func);
                    if (pelemtype.IsValueType)
                    {
                        il.Emit(OpCodes.Stobj, pelemtype);
                    }
                    else
                    {
                        il.Emit(OpCodes.Stind_Ref);
                    }

                }
            }

            if (has_return)
            {
                il.Emit(OpCodes.Ldloc, ret);
            }

            //LuaAPI.lua_settop(L, err_func - 1);
            il.Emit(OpCodes.Ldloc, L);
            il.Emit(OpCodes.Ldloc, err_func);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Sub);
            il.Emit(OpCodes.Call, LuaAPI_lua_settop);

            il.Emit(OpCodes.Ret);
        }

        private MethodInfo ObjectTranslatorPool_FindTranslator = typeof(ObjectTranslatorPool).GetMethod("FindTranslator");
        private Type[] parameterTypeOfWrap = new Type[] { typeof(RealStatePtr) };
        private MethodInfo ObjectTranslator_Assignable = typeof(ObjectTranslator).GetMethod("Assignable", new Type[] { typeof(RealStatePtr),
               typeof(int), typeof(Type)});

        private MethodInfo Utils_BeginObjectRegister = typeof(Utils).GetMethod("BeginObjectRegister");
        private MethodInfo Utils_EndObjectRegister = typeof(Utils).GetMethod("EndObjectRegister");
        private MethodInfo Utils_BeginClassRegister = typeof(Utils).GetMethod("BeginClassRegister");
        private MethodInfo Utils_EndClassRegister = typeof(Utils).GetMethod("EndClassRegister");
        private MethodInfo Utils_RegisterFunc = typeof(Utils).GetMethod("RegisterFunc");
        private MethodInfo Utils_RegisterObject = typeof(Utils).GetMethod("RegisterObject");

        private ConstructorInfo LuaCSFunction_Constructor = typeof(LuaCSFunction).GetConstructor(new Type[] { typeof(object), typeof(IntPtr) });

        private MethodInfo String_Concat = typeof(string).GetMethod("Concat", new Type[] { typeof(object), typeof(object) });

        void checkType(ILGenerator il, Type type, LocalBuilder translator, int argPos, Label endOfBlock, bool isVParam, bool isDefault)
        {
            Label endOfCheckType = il.DefineLabel();

            if (isVParam || isDefault)
            {
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldc_I4, argPos);
                il.Emit(OpCodes.Call, LuaAPI_lua_type);
                il.Emit(OpCodes.Ldc_I4_M1);
                il.Emit(OpCodes.Beq, endOfCheckType);
            }

            il.Emit(OpCodes.Ldloc, translator);
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldc_I4, argPos);
            il.Emit(OpCodes.Ldtoken, isVParam ? type.GetElementType() : type);
            il.Emit(OpCodes.Call, Type_GetTypeFromHandle); // typeof(DeclaringType)
            il.Emit(OpCodes.Callvirt, ObjectTranslator_Assignable);
            il.Emit(OpCodes.Brfalse, endOfBlock);

            il.MarkLabel(endOfCheckType);
        }

        void emitRegisterFunc(ILGenerator il, MethodBuilder method, int index, string name)
        {
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldc_I4, index);
            il.Emit(OpCodes.Ldstr, name);
            il.Emit(OpCodes.Ldnull);
            il.Emit(OpCodes.Ldftn, method);
            il.Emit(OpCodes.Newobj, LuaCSFunction_Constructor);
            il.Emit(OpCodes.Call, Utils_RegisterFunc);
        }

        void emitCatchBlock(ILGenerator il, LocalBuilder ex, LocalBuilder wrapRet, Label retPoint, Label exceptionBlock)
        {
            il.BeginCatchBlock(typeof(Exception));
            il.Emit(OpCodes.Stloc, ex);
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldstr, "c# exception:");
            il.Emit(OpCodes.Ldloc, ex);
            il.Emit(OpCodes.Call, String_Concat);
            il.Emit(OpCodes.Call, LuaAPI_luaL_error);
            il.Emit(OpCodes.Stloc, wrapRet);
            il.Emit(OpCodes.Leave, retPoint);
            il.Emit(OpCodes.Leave, exceptionBlock);

            il.EndExceptionBlock();
        }

        public MethodBuilder emitFieldWrap(TypeBuilder typeBuilder, FieldInfo field, bool genGetter)
        {
            MethodBuilder methodBuilder = typeBuilder.DefineMethod(field.Name + (genID++), MethodAttributes.Static, typeof(int), parameterTypeOfWrap);
            methodBuilder.DefineParameter(1, ParameterAttributes.None, "L");

            ILGenerator il = methodBuilder.GetILGenerator();

            LocalBuilder L = il.DeclareLocal(typeof(RealStatePtr));
            LocalBuilder translator = il.DeclareLocal(typeof(ObjectTranslator));
            LocalBuilder fieldStore = il.DeclareLocal(field.FieldType);
            LocalBuilder wrapRet = il.DeclareLocal(typeof(int));
            LocalBuilder ex = il.DeclareLocal(typeof(Exception));

            Label exceptionBlock = il.BeginExceptionBlock();
            Label retPoint = il.DefineLabel();

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Stloc, L);

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Call, ObjectTranslatorPool_FindTranslator);
            il.Emit(OpCodes.Stloc, translator);

            if (genGetter)
            {
                if (!field.IsStatic)
                {
                    EmitGetObject(il, 1, field.DeclaringType, L, translator, null);
                    il.Emit(OpCodes.Ldfld, field);
                }
                else
                {
                    il.Emit(OpCodes.Ldsfld, field);
                }
                il.Emit(OpCodes.Stloc, fieldStore);
                emitPush(il, field.FieldType, 2, false, L, translator, false);
            }
            else
            {
                if (!field.IsStatic)
                {
                    EmitGetObject(il, 1, field.DeclaringType, L, translator, null);
                    LocalBuilder self = null;
                    if (field.DeclaringType.IsValueType)
                    {
                        self = il.DeclareLocal(field.DeclaringType);
                        il.Emit(OpCodes.Stloc, self);
                        il.Emit(OpCodes.Ldloca, self);
                    }
                    EmitGetObject(il, 2, field.FieldType, L, translator, null);
                    il.Emit(OpCodes.Stfld, field);
                    if (self != null)
                    {
                        emitUpdateIfNeeded(il, L, translator, field.DeclaringType, 1, self.LocalIndex);
                    }
                }
                else
                {
                    EmitGetObject(il, 1, field.FieldType, L, translator, null);
                    il.Emit(OpCodes.Stsfld, field);
                }
            }

            il.Emit(OpCodes.Leave, exceptionBlock);

            emitCatchBlock(il, ex, wrapRet, retPoint, exceptionBlock);

            il.Emit(genGetter ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
            il.Emit(OpCodes.Ret);

            il.MarkLabel(retPoint);
            il.Emit(OpCodes.Ldloc, wrapRet);
            il.Emit(OpCodes.Ret);

            return methodBuilder;
        }

        public MethodBuilder emitPropertyWrap(TypeBuilder typeBuilder, PropertyInfo prop, MethodInfo op, bool genGetter)
        {
            MethodBuilder methodBuilder = typeBuilder.DefineMethod(prop.Name + (genID++), MethodAttributes.Static, typeof(int), parameterTypeOfWrap);
            methodBuilder.DefineParameter(1, ParameterAttributes.None, "L");

            ILGenerator il = methodBuilder.GetILGenerator();

            LocalBuilder L = il.DeclareLocal(typeof(RealStatePtr));
            LocalBuilder translator = il.DeclareLocal(typeof(ObjectTranslator));
            LocalBuilder propStore = il.DeclareLocal(prop.PropertyType);
            LocalBuilder wrapRet = il.DeclareLocal(typeof(int));
            LocalBuilder ex = il.DeclareLocal(typeof(Exception));

            Label exceptionBlock = il.BeginExceptionBlock();
            Label retPoint = il.DefineLabel();

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Stloc, L);

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Call, ObjectTranslatorPool_FindTranslator);
            il.Emit(OpCodes.Stloc, translator);

            if (genGetter)
            {
                if (!op.IsStatic)
                {
                    EmitGetObject(il, 1, prop.DeclaringType, L, translator, null);
                    if (prop.DeclaringType.IsValueType)
                    {
                        var self = il.DeclareLocal(prop.DeclaringType);
                        il.Emit(OpCodes.Stloc, self);
                        il.Emit(OpCodes.Ldloca, self);
                        il.Emit(OpCodes.Call, op);
                        emitUpdateIfNeeded(il, L, translator, prop.DeclaringType, 1, self.LocalIndex);
                    }
                    else
                    {
                        il.Emit(OpCodes.Callvirt, op);
                    }
                }
                else
                {
                    il.Emit(OpCodes.Call, op);
                }
                il.Emit(OpCodes.Stloc, propStore);
                emitPush(il, prop.PropertyType, (short)propStore.LocalIndex, false, L, translator, false);
            }
            else
            {
                if (!op.IsStatic)
                {
                    EmitGetObject(il, 1, prop.DeclaringType, L, translator, null);
                    LocalBuilder self = null;
                    if (prop.DeclaringType.IsValueType)
                    {
                        self = il.DeclareLocal(prop.DeclaringType);
                        il.Emit(OpCodes.Stloc, self);
                        il.Emit(OpCodes.Ldloca, self);
                    }
                    EmitGetObject(il, 2, prop.PropertyType, L, translator, null);
                    il.Emit(prop.DeclaringType.IsValueType ? OpCodes.Call : OpCodes.Callvirt, op);
                    if (self != null)
                    {
                        emitUpdateIfNeeded(il, L, translator, prop.DeclaringType, 1, self.LocalIndex);
                    }
                }
                else
                {
                    EmitGetObject(il, 1, prop.PropertyType, L, translator, null);
                    il.Emit(OpCodes.Call, op);
                }
            }

            il.Emit(OpCodes.Leave, exceptionBlock);

            emitCatchBlock(il, ex, wrapRet, retPoint, exceptionBlock);

            il.Emit(genGetter ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
            il.Emit(OpCodes.Ret);

            il.MarkLabel(retPoint);
            il.Emit(OpCodes.Ldloc, wrapRet);
            il.Emit(OpCodes.Ret);

            return methodBuilder;
        }

        static HashSet<MemberInfo> BlackList = new HashSet<MemberInfo>();

        static void addToBlackList(List<string> info)
        {
            try
            {
                var type = Type.GetType(info[0], true);
                var members = type.GetMember(info[1], BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly);
                foreach(var member in members)
                {
                    if (member.MemberType == MemberTypes.Method)
                    {
                        var mb = member as MethodBase;
                        var parameters = mb.GetParameters();
                        if (parameters.Length != info.Count - 2)
                        {
                            continue;
                        }

                        bool paramsMatch = true;

                        for (int i = 0; i < parameters.Length; i++)
                        {
                            if (parameters[i].ParameterType.FullName != info[i + 2])
                            {
                                paramsMatch = false;
                                break;
                            }
                        }
                        if (paramsMatch)
                        {
                            BlackList.Add(member);
                        }
                    }
                    else if (info.Count == 2)
                    {
                        BlackList.Add(member);
                    }
                }
            } catch { }
        }

        static void initBlackList()
        {
            foreach (var t in Utils.GetAllTypes(true))
            {
                if (!t.IsAbstract || !t.IsSealed) continue;

                var fields = t.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
                for (int i = 0; i < fields.Length; i++)
                {
                    var field = fields[i];
                    if (field.IsDefined(typeof(BlackListAttribute), false)
                        && (typeof(List<List<string>>)).IsAssignableFrom(field.FieldType))
                    {
                        foreach (var info in (field.GetValue(null) as List<List<string>>))
                        {
                            addToBlackList(info);
                        }
                    }
                }

                var props = t.GetProperties(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
                for (int i = 0; i < props.Length; i++)
                {
                    var prop = props[i];
                    if (prop.IsDefined(typeof(BlackListAttribute), false)
                        && (typeof(List<List<string>>)).IsAssignableFrom(prop.PropertyType))
                    {
                        foreach (var info in (prop.GetValue(null, null) as List<List<string>>))
                        {
                            addToBlackList(info);
                        }
                    }
                }
            }
        }

        static bool isMemberInBlackList(MemberInfo mb)
        {
            if (mb is FieldInfo && (mb as FieldInfo).FieldType.IsPointer) return true;
            if (mb is PropertyInfo && (mb as PropertyInfo).PropertyType.IsPointer) return true;

            if (mb.IsDefined(typeof(BlackListAttribute), false) || mb.IsDefined(typeof(ObsoleteAttribute), false)) return true;

            return BlackList.Contains(mb);
        }

        static bool isMethodInBlackList(MethodBase mb)
        {
            if (mb.GetParameters().Any(pInfo => pInfo.ParameterType.IsPointer)) return true;
            if (mb is MethodInfo && (mb as MethodInfo).ReturnType.IsPointer) return false;

            if (mb.IsDefined(typeof(BlackListAttribute), false) || mb.IsDefined(typeof(ObsoleteAttribute), false)) return true;

            return BlackList.Contains(mb);
        }

        public Type EmitTypeWrap(Type toBeWrap)
        {
            TypeBuilder wrapTypeBuilder = CodeEmitModule.DefineType(toBeWrap.Name + "Wrap" + (genID++), TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Abstract | TypeAttributes.Sealed);

            var methodBuilder = wrapTypeBuilder.DefineMethod("__Register", MethodAttributes.Static | MethodAttributes.Public, null, parameterTypeOfWrap);
            methodBuilder.DefineParameter(1, ParameterAttributes.None, "L");

            ILGenerator il = methodBuilder.GetILGenerator();

            LocalBuilder translator = il.DeclareLocal(typeof(ObjectTranslator));

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Call, ObjectTranslatorPool_FindTranslator);
            il.Emit(OpCodes.Stloc, translator);

            var instanceFlag = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly;
            var staticFlag = BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly;

            var instanceFields = toBeWrap.GetFields(instanceFlag).Where(m => !isMemberInBlackList(m));
            var instanceProperties = toBeWrap.GetProperties(instanceFlag).Where(m => !isMemberInBlackList(m));
            var extensionMethods = Utils.GetExtensionMethodsOf(toBeWrap);
            extensionMethods = (extensionMethods == null) ? Enumerable.Empty<MethodInfo>() : extensionMethods.Where(m => !isMemberInBlackList(m));
            var instanceMethods = toBeWrap.GetMethods(instanceFlag)
                .Where(m => !isMethodInBlackList(m))
                .Concat(extensionMethods)
                .Where(m => Utils.IsSupportedMethod(m))
                .Where(m => !m.IsSpecialName
                    || (
                         ((m.Name == "get_Item" && m.GetParameters().Length == 1) || (m.Name == "set_Item" && m.GetParameters().Length == 2))
                         && m.GetParameters()[0].ParameterType.IsAssignableFrom(typeof(string))
                       )
                ).GroupBy(m => m.Name).ToList();
            var supportOperators = toBeWrap.GetMethods(staticFlag)
                .Where(m => !isMethodInBlackList(m))
                .Where(m => m.IsSpecialName && InternalGlobals.supportOp.ContainsKey(m.Name))
                .GroupBy(m => m.Name);

            //begin obj
            il.Emit(OpCodes.Ldtoken, toBeWrap);
            il.Emit(OpCodes.Call, Type_GetTypeFromHandle); // typeof(type)
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldloc, translator);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Ldc_I4_M1);
            il.Emit(OpCodes.Call, Utils_BeginObjectRegister);

            foreach(var field in instanceFields)
            {
                emitRegisterFunc(il, emitFieldWrap(wrapTypeBuilder, field, true), Utils.GETTER_IDX, field.Name);
                emitRegisterFunc(il, emitFieldWrap(wrapTypeBuilder, field, false), Utils.SETTER_IDX, field.Name);
            }

            List<MethodBase> itemGetter = new List<MethodBase>();
            List<MethodBase> itemSetter = new List<MethodBase>();

            foreach(var prop in instanceProperties)
            {
                var getter = prop.GetGetMethod();
                if (getter != null && getter.IsPublic)
                {
                    if (prop.GetIndexParameters().Length > 0)
                    {
                        if (!prop.GetIndexParameters()[0].ParameterType.IsAssignableFrom(typeof(string)))
                        {
                            itemGetter.Add(getter);
                        }
                    }
                    else
                    {
                        emitRegisterFunc(il, emitPropertyWrap(wrapTypeBuilder, prop, getter, true), Utils.GETTER_IDX, prop.Name);
                    }
                }

                var setter = prop.GetSetMethod();
                if (setter != null && setter.IsPublic)
                {
                    if (prop.GetIndexParameters().Length > 0)
                    {
                        if (!prop.GetIndexParameters()[0].ParameterType.IsAssignableFrom(typeof(string)))
                        {
                            itemSetter.Add(setter);
                        }
                    }
                    else
                    {
                        emitRegisterFunc(il, emitPropertyWrap(wrapTypeBuilder, prop, setter, false), Utils.SETTER_IDX, prop.Name);
                    }
                }
            }

            foreach (var group in instanceMethods)
            {
                emitRegisterFunc(il, emitMethodWrap(wrapTypeBuilder, group.Cast<MethodBase>().ToList(), false, toBeWrap), Utils.METHOD_IDX, group.Key);
            }

            foreach (var group in supportOperators)
            {
                emitRegisterFunc(il, emitMethodWrap(wrapTypeBuilder, group.Cast<MethodBase>().ToList(), false, toBeWrap), Utils.OBJ_META_IDX, InternalGlobals.supportOp[group.Key]);
            }

            foreach (var ev in toBeWrap.GetEvents(instanceFlag).Where(m => !isMemberInBlackList(m)))
            {
                emitRegisterFunc(il, emitEventWrap(wrapTypeBuilder, ev), Utils.METHOD_IDX, ev.Name);
            }

            //end obj
            il.Emit(OpCodes.Ldtoken, toBeWrap);
            il.Emit(OpCodes.Call, Type_GetTypeFromHandle); // typeof(type)
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldloc, translator);
            il.Emit(OpCodes.Ldnull);
            if (itemGetter.Count > 0)
            {
                il.Emit(OpCodes.Ldftn, emitMethodWrap(wrapTypeBuilder, itemGetter, true, toBeWrap));
                il.Emit(OpCodes.Newobj, LuaCSFunction_Constructor);
            }
            il.Emit(OpCodes.Ldnull);
            if (itemSetter.Count > 0)
            {
                il.Emit(OpCodes.Ldftn, emitMethodWrap(wrapTypeBuilder, itemSetter, true, toBeWrap));
                il.Emit(OpCodes.Newobj, LuaCSFunction_Constructor);
            }
            il.Emit(OpCodes.Ldnull);
            il.Emit(OpCodes.Ldnull);
            il.Emit(OpCodes.Ldnull);
            il.Emit(OpCodes.Call, Utils_EndObjectRegister);

            // begin class
            il.Emit(OpCodes.Ldtoken, toBeWrap);
            il.Emit(OpCodes.Call, Type_GetTypeFromHandle); // typeof(type)
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldnull);
            il.Emit(OpCodes.Ldftn, emitMethodWrap(wrapTypeBuilder,
                toBeWrap.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase)
                .Where(m => !isMethodInBlackList(m))
                .Cast<MethodBase>().ToList(), false, toBeWrap, toBeWrap.ToString() + " constructor"));
            il.Emit(OpCodes.Newobj, LuaCSFunction_Constructor);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Ldc_I4_1);
            il.Emit(OpCodes.Call, Utils_BeginClassRegister);

            var staticMethods = toBeWrap.GetMethods(staticFlag)
                .Where(m => !isMethodInBlackList(m))
                .Where(m => Utils.IsSupportedMethod(m))
                .Where(m => !m.IsSpecialName).GroupBy(m => m.Name);

            var staticFields = toBeWrap.GetFields(staticFlag).Where(m => !isMemberInBlackList(m));

            var staticProperties = toBeWrap.GetProperties(staticFlag).Where(m => !isMemberInBlackList(m));

            foreach (var group in staticMethods)
            {
                emitRegisterFunc(il, emitMethodWrap(wrapTypeBuilder, group.Cast<MethodBase>().ToList(), false, toBeWrap), Utils.CLS_IDX, group.Key);
            }

            foreach (var ev in toBeWrap.GetEvents(staticFlag).Where(m => !isMemberInBlackList(m)))
            {
                emitRegisterFunc(il, emitEventWrap(wrapTypeBuilder, ev), Utils.CLS_IDX, ev.Name);
            }

            foreach (var prop in staticProperties)
            {
                var getter = prop.GetGetMethod();
                if (getter != null && getter.IsPublic)
                {
                    emitRegisterFunc(il, emitPropertyWrap(wrapTypeBuilder, prop, getter, true), Utils.GETTER_IDX, prop.Name);
                }

                var setter = prop.GetSetMethod();
                if (setter != null && setter.IsPublic)
                {
                    emitRegisterFunc(il, emitPropertyWrap(wrapTypeBuilder, prop, setter, false), Utils.SETTER_IDX, prop.Name);
                }
            }

            foreach (var field in staticFields)
            {
                if (field.IsInitOnly || field.IsLiteral)
                {
                    il.Emit(OpCodes.Ldarg_0);
                    il.Emit(OpCodes.Ldloc, translator);
                    il.Emit(OpCodes.Ldc_I4, Utils.CLS_IDX);
                    il.Emit(OpCodes.Ldstr, field.Name);
                    if (field.IsLiteral)
                    {
                        LocalBuilder literalStore = il.DeclareLocal(field.FieldType);
                        emitLiteralLoad(il, field.FieldType, field.GetValue(null), literalStore.LocalIndex);
                        il.Emit(OpCodes.Stloc, literalStore);
                        il.Emit(OpCodes.Ldloc, literalStore);
                    }
                    else
                    {
                        il.Emit(OpCodes.Ldsfld, field);
                    }
                    if (field.FieldType.IsValueType)
                    {
                        il.Emit(OpCodes.Box, field.FieldType);
                    }
                    il.Emit(OpCodes.Call, Utils_RegisterObject);
                }
                else
                {
                    emitRegisterFunc(il, emitFieldWrap(wrapTypeBuilder, field, true), Utils.CLS_GETTER_IDX, field.Name);
                    emitRegisterFunc(il, emitFieldWrap(wrapTypeBuilder, field, false), Utils.CLS_SETTER_IDX, field.Name);
                }
            }

            //end class
            il.Emit(OpCodes.Ldtoken, toBeWrap);
            il.Emit(OpCodes.Call, Type_GetTypeFromHandle); // typeof(type)
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldloc, translator);
            il.Emit(OpCodes.Call, Utils_EndClassRegister);

            il.Emit(OpCodes.Ret);

            return wrapTypeBuilder.CreateType();
        }

        MethodBuilder emitEventWrap(TypeBuilder typeBuilder, EventInfo ev)
        {
            var addEvent = ev.GetAddMethod();
            var removeEvent = ev.GetRemoveMethod();

            if (addEvent == null && removeEvent == null)
            {
                return null;
            }

            bool isStatic = addEvent != null ? addEvent.IsStatic : removeEvent.IsStatic;

            var methodBuilder = typeBuilder.DefineMethod(ev.Name + (genID++), MethodAttributes.Static, typeof(int), parameterTypeOfWrap);
            methodBuilder.DefineParameter(1, ParameterAttributes.None, "L");

            ILGenerator il = methodBuilder.GetILGenerator();

            LocalBuilder wrapRet = il.DeclareLocal(typeof(int));
            LocalBuilder ex = il.DeclareLocal(typeof(Exception));
            LocalBuilder L = il.DeclareLocal(typeof(RealStatePtr));
            LocalBuilder translator = il.DeclareLocal(typeof(ObjectTranslator));
            LocalBuilder callback = il.DeclareLocal(ev.EventHandlerType);

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Stloc, L);

            Label exceptionBlock = il.BeginExceptionBlock();
            Label retPoint = il.DefineLabel();

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Call, ObjectTranslatorPool_FindTranslator);
            il.Emit(OpCodes.Stloc, translator);

            EmitGetObject(il, isStatic ? 2 : 3, ev.EventHandlerType, L, translator, null);
            il.Emit(OpCodes.Stloc, callback);
            il.Emit(OpCodes.Ldloc, callback);
            Label ifBlock = il.DefineLabel();
            il.Emit(OpCodes.Brtrue, ifBlock);

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldstr, string.Format("#{0}, need {1}", isStatic ? 2 : 3, ev.EventHandlerType));
            il.Emit(OpCodes.Call, LuaAPI_luaL_error);
            il.Emit(OpCodes.Stloc, wrapRet);
            il.Emit(OpCodes.Leave, retPoint);
            il.MarkLabel(ifBlock);

            if (addEvent != null)
            {
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(isStatic ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_2);
                il.Emit(OpCodes.Ldstr, "+");
                il.Emit(OpCodes.Call, LuaAPI_xlua_is_eq_str);
                ifBlock = il.DefineLabel();
                il.Emit(OpCodes.Brfalse, ifBlock);

                if (!isStatic)
                {
                    EmitGetObject(il, 1, ev.DeclaringType, L, translator, null);
                    if (ev.DeclaringType.IsValueType)
                    {
                        var self = il.DeclareLocal(ev.DeclaringType);
                        il.Emit(OpCodes.Stloc, self);
                        il.Emit(OpCodes.Ldloca, self);
                    }
                }
                il.Emit(OpCodes.Ldloc, callback);
                il.Emit(OpCodes.Call, addEvent);
                il.Emit(OpCodes.Ldc_I4_0);
                il.Emit(OpCodes.Leave, retPoint);
                il.MarkLabel(ifBlock);
            }

            if (removeEvent != null)
            {
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(isStatic ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_2);
                il.Emit(OpCodes.Ldstr, "-");
                il.Emit(OpCodes.Call, LuaAPI_xlua_is_eq_str);
                ifBlock = il.DefineLabel();
                il.Emit(OpCodes.Brfalse, ifBlock);

                if (!isStatic)
                {
                    EmitGetObject(il, 1, ev.DeclaringType, L, translator, null);
                    if (ev.DeclaringType.IsValueType)
                    {
                        var self = il.DeclareLocal(ev.DeclaringType);
                        il.Emit(OpCodes.Stloc, self);
                        il.Emit(OpCodes.Ldloca, self);
                    }
                }
                il.Emit(OpCodes.Ldloc, callback);
                il.Emit(OpCodes.Call, removeEvent);
                il.Emit(OpCodes.Ldc_I4_0);
                il.Emit(OpCodes.Leave, retPoint);
                il.MarkLabel(ifBlock);
            }

            il.Emit(OpCodes.Leave, exceptionBlock);

            emitCatchBlock(il, ex, wrapRet, retPoint, exceptionBlock);

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldstr, "invalid arguments to " + ev.DeclaringType + "." + ev.Name + "!");
            il.Emit(OpCodes.Call, LuaAPI_luaL_error);
            il.Emit(OpCodes.Ret);

            il.MarkLabel(retPoint);
            il.Emit(OpCodes.Ldloc, wrapRet);
            il.Emit(OpCodes.Ret);

            return methodBuilder;
        }

        void emitUpdateIfNeeded(ILGenerator il, LocalBuilder L, LocalBuilder translator, Type type, int luaIndex, int localIndex)
        {
            if (type.IsValueType && !type.IsPrimitive && !type.IsEnum() && type != typeof(decimal))
            {
                //UnityEngine.Debug.LogWarning("-----------------emit update:" + type);
                il.Emit(OpCodes.Ldloc, translator);
                il.Emit(OpCodes.Ldloc, L);
                il.Emit(OpCodes.Ldc_I4, luaIndex);
                il.Emit(OpCodes.Ldloc, localIndex);
                il.Emit(OpCodes.Box, type);
                il.Emit(OpCodes.Callvirt, ObjectTranslator_Update);
            }
        }

        //private MethodInfo UnityEngine_Debug_Log = typeof(UnityEngine.Debug).GetMethod("Log", new Type[] { typeof(object)});
        int firstDefaultValue(MethodBase method)
        {
            var parameters = method.GetParameters();
            for(int i = 0; i < parameters.Length; i++)
            {
                if (parameters[i].IsOptional) return i;
            }
            return -1;
        }

        MethodBuilder emitMethodWrap(TypeBuilder typeBuilder, List<MethodBase> methodsToCall, bool isIndexer, Type declaringType, string methodDesciption = null)
        {
            string wrapName = (methodsToCall.Count > 0 ? methodsToCall[0].Name : "Constructor");
            var methodBuilder = typeBuilder.DefineMethod(wrapName + (genID++), MethodAttributes.Static, typeof(int), parameterTypeOfWrap);
            methodBuilder.DefineParameter(1,  ParameterAttributes.None, "L");

            bool needCheckParameterType = (methodsToCall.Count > 1)  || isIndexer;

            if (methodsToCall.Count == 0 || methodsToCall[0].IsConstructor)
            {
                needCheckParameterType = true;
            }

            if (methodsToCall.Count == 1 && firstDefaultValue(methodsToCall[0]) != -1)
            {
                needCheckParameterType = true;
            }

            ILGenerator il = methodBuilder.GetILGenerator();

            LocalBuilder wrapRet = il.DeclareLocal(typeof(int));
            LocalBuilder ex = il.DeclareLocal(typeof(Exception));
            LocalBuilder L = il.DeclareLocal(typeof(RealStatePtr));
            LocalBuilder translator = il.DeclareLocal(typeof(ObjectTranslator));
            LocalBuilder top = il.DeclareLocal(typeof(int));

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Stloc, L);

            Label exceptionBlock = il.BeginExceptionBlock();
            Label retPoint = il.DefineLabel();
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Call, ObjectTranslatorPool_FindTranslator);
            il.Emit(OpCodes.Stloc, translator);

            if (needCheckParameterType)
            {
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Call, LuaAPI_lua_gettop);
                il.Emit(OpCodes.Stloc, top);
            }

            for (int i = 0; i < methodsToCall.Count; i++)
            {
                var method = methodsToCall[i];
                if ((method is MethodInfo) && method.ContainsGenericParameters)
                {
                    method = Utils.MakeGenericMethodWithConstraints(method as MethodInfo);
                }
                bool isStatic = method.IsStatic;
                var paramInfos = method.GetParameters();
                int minInParamCount = 0;
                int maxInParamCount = 0;
                int outParamCount = 0;
                bool hasParams = paramInfos.Length > 0 && paramInfos[paramInfos.Length - 1].IsDefined(typeof(ParamArrayAttribute), false);
                bool hasOptional = false;

                LocalBuilder methodReturn = null;

                for (int j = 0; j < paramInfos.Length; j++)
                {
                    if (!paramInfos[j].IsOut)
                    {
                        if (!paramInfos[j].IsOptional && (!hasParams || j != paramInfos.Length - 1))
                        {
                            minInParamCount++;
                        }
                        maxInParamCount++;
                    }
                    if (paramInfos[j].IsOptional)
                    {
                        hasOptional = true;
                    }
                    if (paramInfos[j].ParameterType.IsByRef)
                    {
                        outParamCount++;
                    }
                }

                Label endOfBlock = il.DefineLabel();

                if (needCheckParameterType)
                {
                    il.Emit(OpCodes.Ldloc, top);
                    il.Emit(OpCodes.Ldc_I4, minInParamCount + (isStatic ? 0 : 1));
                    il.Emit((hasParams || hasOptional) ? OpCodes.Blt : OpCodes.Bne_Un, endOfBlock);

                    if (hasOptional && !hasParams)
                    {
                        il.Emit(OpCodes.Ldloc, top);
                        il.Emit(OpCodes.Ldc_I4, maxInParamCount + (isStatic ? 0 : 1));
                        il.Emit(OpCodes.Bgt, endOfBlock);
                    }
                    
                    if (!isStatic && !method.IsConstructor)
                    {
                        checkType(il, method.DeclaringType, translator, 1, endOfBlock, false, false);
                    }

                    int argPos = isStatic ? 1 : 2;

                    for (int j = 0; j < paramInfos.Length; j++)
                    {
                        var paramInfo = paramInfos[j];
                        if (!paramInfo.IsOut)
                        {
                            var rawParamType = paramInfo.ParameterType;
                            if (rawParamType.IsByRef)
                            {
                                rawParamType = rawParamType.GetElementType();
                            }
                            checkType(il, rawParamType, translator, argPos++, endOfBlock, 
                                hasParams && (j == paramInfos.Length - 1), paramInfo.IsOptional);
                        }
                    }
                }

                int luaPos = isStatic ? 1 : 2;

                int argStoreStart = -1;

                for (int j = 0; j < paramInfos.Length; j++)
                {
                    var paramInfo = paramInfos[j];
                    var paramRawType = paramInfo.ParameterType.IsByRef ? paramInfo.ParameterType.GetElementType() :
                        paramInfo.ParameterType;
                    var argStore = il.DeclareLocal(paramRawType);
                    if (paramInfo.IsOptional)
                    {
                        //UnityEngine.Debug.Log(paramInfo.Name + "," + paramRawType + "," + paramInfo.DefaultValue);
                        emitLiteralLoad(il, paramRawType, paramInfo.DefaultValue, argStore.LocalIndex);
                        il.Emit(OpCodes.Stloc, argStore);
                    }
                    //UnityEngine.Debug.LogWarning(declaringType.Name + "." + method.Name + "." + paramInfos[j].Name + " pos(d):" + argStore.LocalIndex + ", pt:" + paramRawType + ", j:" + j);
                    if (argStoreStart == -1)
                    {
                        argStoreStart = argStore.LocalIndex;
                    }
                    
                }
                for (int j = 0; j < paramInfos.Length; j++)
                {
                    var paramInfo = paramInfos[j];
                    var paramRawType = paramInfo.ParameterType.IsByRef ? paramInfo.ParameterType.GetElementType() :
                        paramInfo.ParameterType;
                    if (!paramInfo.IsOut)
                    {
                        Label endOfGetValue = il.DefineLabel();
                        if (paramInfo.IsOptional)
                        {
                            il.Emit(OpCodes.Ldarg_0);
                            il.Emit(OpCodes.Ldc_I4, luaPos);
                            il.Emit(OpCodes.Call, LuaAPI_lua_type);
                            il.Emit(OpCodes.Ldc_I4_M1);
                            il.Emit(OpCodes.Beq, endOfGetValue);
                        }
                        EmitGetObject(il, luaPos++, paramRawType, L, translator, null, hasParams && (j == paramInfos.Length - 1));
                        il.Emit(OpCodes.Stloc, argStoreStart + j);
                        il.MarkLabel(endOfGetValue);
                    }
                }

                LocalBuilder valueTypeTmp = null;

                if (!isStatic && (!method.IsConstructor || method.DeclaringType.IsValueType))
                {
                    if (!method.IsConstructor)
                    {
                        EmitGetObject(il, 1, method.DeclaringType, L, translator, null);
                    }
                    if (method.DeclaringType.IsValueType)
                    {
                        if (method.IsConstructor)
                        {
                            methodReturn = il.DeclareLocal(method.DeclaringType);
                            il.Emit(OpCodes.Ldloca, methodReturn);
                        }
                        else
                        {
                            valueTypeTmp = il.DeclareLocal(method.DeclaringType);
                            il.Emit(OpCodes.Stloc, valueTypeTmp);
                            il.Emit(OpCodes.Ldloca, valueTypeTmp);
                        }
                    }
                }

                for (int j = 0; j < paramInfos.Length; j++)
                {
                    //UnityEngine.Debug.LogWarning(declaringType.Name + "." + method.Name + "." + paramInfos[j].Name +" pos:" + (argStoreStart + j) + ", op:" + (paramInfos[j].ParameterType.IsByRef ? OpCodes.Ldloca : OpCodes.Ldloc) + ", j:" + j );
                    il.Emit(paramInfos[j].ParameterType.IsByRef ? OpCodes.Ldloca : OpCodes.Ldloc, argStoreStart + j);
                }

                if (method.IsConstructor)
                {
                    if (method.DeclaringType.IsValueType)
                    {
                        il.Emit(OpCodes.Call, method as ConstructorInfo);
                    }
                    else
                    {
                        il.Emit(OpCodes.Newobj, method as ConstructorInfo);
                    }
                }
                else
                {
                    il.Emit(isStatic ? OpCodes.Call : OpCodes.Callvirt, method as MethodInfo);
                }

                if (valueTypeTmp != null)
                {
                    emitUpdateIfNeeded(il, L, translator, method.DeclaringType, 1, valueTypeTmp.LocalIndex);
                }

                if (isIndexer)
                {
                    il.Emit(OpCodes.Ldarg_0);
                    il.Emit(OpCodes.Ldc_I4_1);
                    il.Emit(OpCodes.Call, LuaAPI_lua_pushboolean);
                }

                bool hasReturn = false;

                MethodInfo methodInfo = method as MethodInfo;
                if (methodInfo == null || methodInfo.ReturnType != typeof(void))
                {
                    hasReturn = true;
                    Type returnType = methodInfo == null ? method.DeclaringType : methodInfo.ReturnType;
                    if (methodReturn == null)
                    {
                        methodReturn = il.DeclareLocal(returnType);
                        il.Emit(OpCodes.Stloc, methodReturn);
                    }
                    emitPush(il, returnType, (short)methodReturn.LocalIndex, false, L, translator, false);
                }

                int luaIndex = isStatic ? 1 : 2;
                for (int j = 0; j < paramInfos.Length; j++)
                {
                    if (paramInfos[j].ParameterType.IsByRef)
                    {
                        var rawParamType = paramInfos[j].ParameterType.GetElementType();
                        emitPush(il, rawParamType,
                            (short)(argStoreStart + j), false, L, translator, false);
                        if (!paramInfos[j].IsOut)
                        {
                            emitUpdateIfNeeded(il, L, translator, rawParamType, luaIndex, argStoreStart + j);
                        }
                    }
                    if (!paramInfos[j].IsOut)
                    {
                        luaIndex++;
                    }
                }

                il.Emit(OpCodes.Ldc_I4, outParamCount + (hasReturn ? 1 : 0) + (isIndexer ? 1 : 0));
                il.Emit(OpCodes.Stloc, wrapRet);
                il.Emit(OpCodes.Leave, retPoint);
                //il.Emit(OpCodes.Ret);

                if (needCheckParameterType)
                {
                    il.MarkLabel(endOfBlock);
                }
            }

            if (declaringType.IsValueType && (methodsToCall.Count == 0 || methodsToCall[0].IsConstructor))
            {
                Label endOfBlock = il.DefineLabel();
                il.Emit(OpCodes.Ldloc, top);
                il.Emit(OpCodes.Ldc_I4_1);
                il.Emit(OpCodes.Bne_Un, endOfBlock);

                var methodReturn = il.DeclareLocal(declaringType);

                il.Emit(OpCodes.Ldloca, methodReturn);
                il.Emit(OpCodes.Initobj, declaringType);
                emitPush(il, declaringType, (short)methodReturn.LocalIndex, false, L, translator, false);
                il.Emit(OpCodes.Ldc_I4_1);
                il.Emit(OpCodes.Stloc, wrapRet);
                il.Emit(OpCodes.Leave_S, retPoint);
                il.MarkLabel(endOfBlock);
            }

            il.Emit(OpCodes.Leave, exceptionBlock);
            emitCatchBlock(il, ex, wrapRet, retPoint, exceptionBlock);

            if (needCheckParameterType)
            {
                if (isIndexer)
                {
                    il.Emit(OpCodes.Ldarg_0);
                    il.Emit(OpCodes.Ldc_I4_0);
                    il.Emit(OpCodes.Call, LuaAPI_lua_pushboolean);
                    il.Emit(OpCodes.Ldc_I4_1);
                    il.Emit(OpCodes.Ret);
                }
                else
                {
                    il.Emit(OpCodes.Ldarg_0);
                    if (methodDesciption == null)
                    {
                        if (methodsToCall.Count > 0)
                        {
                            methodDesciption = declaringType + "." + methodsToCall[0].Name;
                        }
                        else
                        {
                            methodDesciption = "unknow method in " + declaringType;
                        }
                    }
                    il.Emit(OpCodes.Ldstr, "invalid arguments to " + methodDesciption + "!");
                    il.Emit(OpCodes.Call, LuaAPI_luaL_error);
                    il.Emit(OpCodes.Ret);
                }
            }

            il.MarkLabel(retPoint);
            il.Emit(OpCodes.Ldloc, wrapRet);
            il.Emit(OpCodes.Ret);

            return methodBuilder;
        }
    }
}

#endif

Mono.Cecil.Cil.OpCodes : Object

Fields :

public static OpCode Nop
public static OpCode Break
public static OpCode Ldarg_0
public static OpCode Ldarg_1
public static OpCode Ldarg_2
public static OpCode Ldarg_3
public static OpCode Ldloc_0
public static OpCode Ldloc_1
public static OpCode Ldloc_2
public static OpCode Ldloc_3
public static OpCode Stloc_0
public static OpCode Stloc_1
public static OpCode Stloc_2
public static OpCode Stloc_3
public static OpCode Ldarg_S
public static OpCode Ldarga_S
public static OpCode Starg_S
public static OpCode Ldloc_S
public static OpCode Ldloca_S
public static OpCode Stloc_S
public static OpCode Ldnull
public static OpCode Ldc_I4_M1
public static OpCode Ldc_I4_0
public static OpCode Ldc_I4_1
public static OpCode Ldc_I4_2
public static OpCode Ldc_I4_3
public static OpCode Ldc_I4_4
public static OpCode Ldc_I4_5
public static OpCode Ldc_I4_6
public static OpCode Ldc_I4_7
public static OpCode Ldc_I4_8
public static OpCode Ldc_I4_S
public static OpCode Ldc_I4
public static OpCode Ldc_I8
public static OpCode Ldc_R4
public static OpCode Ldc_R8
public static OpCode Dup
public static OpCode Pop
public static OpCode Jmp
public static OpCode Call
public static OpCode Calli
public static OpCode Ret
public static OpCode Br_S
public static OpCode Brfalse_S
public static OpCode Brtrue_S
public static OpCode Beq_S
public static OpCode Bge_S
public static OpCode Bgt_S
public static OpCode Ble_S
public static OpCode Blt_S
public static OpCode Bne_Un_S
public static OpCode Bge_Un_S
public static OpCode Bgt_Un_S
public static OpCode Ble_Un_S
public static OpCode Blt_Un_S
public static OpCode Br
public static OpCode Brfalse
public static OpCode Brtrue
public static OpCode Beq
public static OpCode Bge
public static OpCode Bgt
public static OpCode Ble
public static OpCode Blt
public static OpCode Bne_Un
public static OpCode Bge_Un
public static OpCode Bgt_Un
public static OpCode Ble_Un
public static OpCode Blt_Un
public static OpCode Switch
public static OpCode Ldind_I1
public static OpCode Ldind_U1
public static OpCode Ldind_I2
public static OpCode Ldind_U2
public static OpCode Ldind_I4
public static OpCode Ldind_U4
public static OpCode Ldind_I8
public static OpCode Ldind_I
public static OpCode Ldind_R4
public static OpCode Ldind_R8
public static OpCode Ldind_Ref
public static OpCode Stind_Ref
public static OpCode Stind_I1
public static OpCode Stind_I2
public static OpCode Stind_I4
public static OpCode Stind_I8
public static OpCode Stind_R4
public static OpCode Stind_R8
public static OpCode Add
public static OpCode Sub
public static OpCode Mul
public static OpCode Div
public static OpCode Div_Un
public static OpCode Rem
public static OpCode Rem_Un
public static OpCode And
public static OpCode Or
public static OpCode Xor
public static OpCode Shl
public static OpCode Shr
public static OpCode Shr_Un
public static OpCode Neg
public static OpCode Not
public static OpCode Conv_I1
public static OpCode Conv_I2
public static OpCode Conv_I4
public static OpCode Conv_I8
public static OpCode Conv_R4
public static OpCode Conv_R8
public static OpCode Conv_U4
public static OpCode Conv_U8
public static OpCode Callvirt
public static OpCode Cpobj
public static OpCode Ldobj
public static OpCode Ldstr
public static OpCode Newobj
public static OpCode Castclass
public static OpCode Isinst
public static OpCode Conv_R_Un
public static OpCode Unbox
public static OpCode Throw
public static OpCode Ldfld
public static OpCode Ldflda
public static OpCode Stfld
public static OpCode Ldsfld
public static OpCode Ldsflda
public static OpCode Stsfld
public static OpCode Stobj
public static OpCode Conv_Ovf_I1_Un
public static OpCode Conv_Ovf_I2_Un
public static OpCode Conv_Ovf_I4_Un
public static OpCode Conv_Ovf_I8_Un
public static OpCode Conv_Ovf_U1_Un
public static OpCode Conv_Ovf_U2_Un
public static OpCode Conv_Ovf_U4_Un
public static OpCode Conv_Ovf_U8_Un
public static OpCode Conv_Ovf_I_Un
public static OpCode Conv_Ovf_U_Un
public static OpCode Box
public static OpCode Newarr
public static OpCode Ldlen
public static OpCode Ldelema
public static OpCode Ldelem_I1
public static OpCode Ldelem_U1
public static OpCode Ldelem_I2
public static OpCode Ldelem_U2
public static OpCode Ldelem_I4
public static OpCode Ldelem_U4
public static OpCode Ldelem_I8
public static OpCode Ldelem_I
public static OpCode Ldelem_R4
public static OpCode Ldelem_R8
public static OpCode Ldelem_Ref
public static OpCode Stelem_I
public static OpCode Stelem_I1
public static OpCode Stelem_I2
public static OpCode Stelem_I4
public static OpCode Stelem_I8
public static OpCode Stelem_R4
public static OpCode Stelem_R8
public static OpCode Stelem_Ref
public static OpCode Ldelem_Any
public static OpCode Stelem_Any
public static OpCode Unbox_Any
public static OpCode Conv_Ovf_I1
public static OpCode Conv_Ovf_U1
public static OpCode Conv_Ovf_I2
public static OpCode Conv_Ovf_U2
public static OpCode Conv_Ovf_I4
public static OpCode Conv_Ovf_U4
public static OpCode Conv_Ovf_I8
public static OpCode Conv_Ovf_U8
public static OpCode Refanyval
public static OpCode Ckfinite
public static OpCode Mkrefany
public static OpCode Ldtoken
public static OpCode Conv_U2
public static OpCode Conv_U1
public static OpCode Conv_I
public static OpCode Conv_Ovf_I
public static OpCode Conv_Ovf_U
public static OpCode Add_Ovf
public static OpCode Add_Ovf_Un
public static OpCode Mul_Ovf
public static OpCode Mul_Ovf_Un
public static OpCode Sub_Ovf
public static OpCode Sub_Ovf_Un
public static OpCode Endfinally
public static OpCode Leave
public static OpCode Leave_S
public static OpCode Stind_I
public static OpCode Conv_U
public static OpCode Arglist
public static OpCode Ceq
public static OpCode Cgt
public static OpCode Cgt_Un
public static OpCode Clt
public static OpCode Clt_Un
public static OpCode Ldftn
public static OpCode Ldvirtftn
public static OpCode Ldarg
public static OpCode Ldarga
public static OpCode Starg
public static OpCode Ldloc
public static OpCode Ldloca
public static OpCode Stloc
public static OpCode Localloc
public static OpCode Endfilter
public static OpCode Unaligned
public static OpCode Volatile
public static OpCode Tail
public static OpCode Initobj
public static OpCode Constrained
public static OpCode Cpblk
public static OpCode Initblk
public static OpCode No
public static OpCode Rethrow
public static OpCode Sizeof
public static OpCode Refanytype
public static OpCode Readonly

Methods :

public Type GetType()
public String ToString()
public Boolean Equals(Object obj = )
public Int32 GetHashCode()

Other methods

Other methods