/* * ============================================================================== * Filename: LuaHookSetup * Created: 2018/7/2 11:36:16 * Author: エル・プサイ・コングリィ * Purpose: * ============================================================================== */ //#define XLUA #define TOLUA //#define SLUA #if UNITY_EDITOR using System; using System.Collections.Generic; using System.Reflection; using System.Text; using UnityEditor; using UnityEngine; #if XLUA using XLua; using LuaDLL = XLua.LuaDLL.Lua; using LuaCSFunction = XLua.LuaDLL.lua_CSFunction; using StrLen = System.IntPtr; #elif TOLUA using LuaInterface; using LuaDLL = LuaInterface.LuaDLL; using LuaCSFunction = LuaInterface.LuaCSFunction; using StrLen = System.Int32; #elif SLUA using SLua; using LuaDLL = SLua.LuaDLL; using LuaCSFunction = SLua.LuaCSFunction; using StrLen = System.Int32; #endif namespace MikuLuaProfiler { [InitializeOnLoad] public static class HookLuaUtil { private static MethodHooker hookNewLuaEnv; static HookLuaUtil() { if (hookNewLuaEnv == null) { Type envReplace = typeof(LuaEnvReplace); Type typeDll = typeof(LuaDLL); var newstateFun = typeDll.GetMethod("luaL_newstate"); var clickReplace = envReplace.GetMethod("luaL_newstate"); var clickProxy = envReplace.GetMethod("ProxyNewstate", BindingFlags.Public | BindingFlags.Static); hookNewLuaEnv = new MethodHooker(newstateFun, clickReplace, clickProxy); hookNewLuaEnv.Install(); newstateFun = typeDll.GetMethod("lua_close"); clickReplace = envReplace.GetMethod("lua_close"); clickProxy = envReplace.GetMethod("ProxyClose", BindingFlags.Public | BindingFlags.Static); hookNewLuaEnv = new MethodHooker(newstateFun, clickReplace, clickProxy); hookNewLuaEnv.Install(); } } public static class LuaEnvReplace { public static void lua_close(IntPtr luaState) { if (LuaProfiler.mainL == luaState) { LuaProfiler.mainL = IntPtr.Zero; UnInstall(); } ProxyClose(luaState); } public static void ProxyClose(IntPtr luaState) { } public static IntPtr luaL_newstate() { IntPtr l = ProxyNewstate(); if (LuaDeepProfilerSetting.Instance.isDeepProfiler) { MikuLuaProfilerLuaProfilerWrap.__Register(l); Install(); LuaProfiler.mainL = l; } return l; } public static IntPtr ProxyNewstate() { return IntPtr.Zero; } } #region hook when run private static MethodHooker tostringHook; private static MethodHooker loaderHook; private static bool m_hooked = false; private static void Install() { if (m_hooked) return; if (tostringHook == null) { Type typeLogReplace = typeof(LuaDLLReplace); Type typeLog = typeof(LuaDLL); #if XLUA MethodInfo tostringFun = typeLog.GetMethod("xluaL_loadbuffer"); #else MethodInfo tostringFun = typeLog.GetMethod("luaL_loadbuffer", new Type[] { typeof(IntPtr), typeof(byte[]), typeof(int), typeof(string) }); #endif MethodInfo tostringReplace = typeLogReplace.GetMethod("luaL_loadbuffer"); MethodInfo tostringProxy = typeLogReplace.GetMethod("ProxyLoadbuffer"); tostringHook = new MethodHooker(tostringFun, tostringReplace, tostringProxy); tostringHook.Install(); tostringFun = typeLog.GetMethod("lua_tostring"); tostringReplace = typeLogReplace.GetMethod("lua_tostring"); tostringProxy = typeLogReplace.GetMethod("PoxyToString"); tostringHook = new MethodHooker(tostringFun, tostringReplace, tostringProxy); tostringHook.Install(); } m_hooked = true; } public static void UnInstall() { if (tostringHook != null) { tostringHook.Uninstall(); tostringHook = null; } if (loaderHook != null) { loaderHook.Uninstall(); loaderHook = null; } m_hooked = false; } public class LuaDLLReplace { #region luastring public static readonly Dictionary stringDict = new Dictionary(); public static bool TryGetLuaString(IntPtr p, out string result) { return stringDict.TryGetValue((long)p, out result); } public static void RefString(IntPtr strPoint, int index, string s, IntPtr L) { int oldTop = LuaDLL.lua_gettop(L); LuaDLL.lua_pushvalue(L, index); //把字符串ref了之后就不GC了 LuaDLL.luaL_ref(L, LuaIndexes.LUA_REGISTRYINDEX); LuaDLL.lua_settop(L, oldTop); stringDict[(long)strPoint] = s; } #endregion #region hook fun public static int luaL_loadbuffer(IntPtr L, byte[] buff, int size, string name) { if (LuaDeepProfilerSetting.Instance.isDeepProfiler)//&& name != "chunk" { string value = ""; string hookedValue = ""; try { string fileName = name.Replace("@", "").Replace("/", ".") + ".lua"; if (buff[0] == 239 && buff[1] == 187 && buff[2] == 191) {// utf-8 value = Encoding.UTF8.GetString(buff, 3, buff.Length - 3); } else { value = Encoding.UTF8.GetString(buff); } hookedValue = Parse.InsertSample(value, fileName); //System.IO.File.WriteAllText(fileName, value); buff = Encoding.UTF8.GetBytes(hookedValue); size = buff.Length; } catch (Exception e) { Debug.LogError(name + "\n解析出错:\n" + value); throw e; } } return ProxyLoadbuffer(L, buff, size, name); } public static int ProxyLoadbuffer(IntPtr L, byte[] buff, int size, string name) { return 0; } public static string lua_tostring(IntPtr L, int index) { StrLen strlen; #if SLUA IntPtr str = LuaDLL.luaS_tolstring32(L, index, out strlen); #else IntPtr str = LuaDLL.lua_tolstring(L, index, out strlen); #endif string ret; if (!TryGetLuaString(str, out ret)) { ret = PoxyToString(L, index); RefString(str, index, ret, L); } return ret; } public static string PoxyToString(IntPtr L, int index) { Debug.Log("ffffffffff"); return null; } #endregion } #endregion } public class LuaLib { #region memory public static void RunGC() { var env = LuaProfiler.mainL; if (env != IntPtr.Zero) { LuaDLL.lua_gc(env, LuaGCOptions.LUA_GCCOLLECT, 0); } } public static void StopGC() { var env = LuaProfiler.mainL; if (env != IntPtr.Zero) { LuaDLL.lua_gc(env, LuaGCOptions.LUA_GCSTOP, 0); } } public static void ResumeGC() { var env = LuaProfiler.mainL; if (env != IntPtr.Zero) { LuaDLL.lua_gc(env, LuaGCOptions.LUA_GCRESTART, 0); } } public static long GetLuaMemory(IntPtr luaState) { long result = 0; result = LuaDLL.lua_gc(luaState, LuaGCOptions.LUA_GCCOUNT, 0); result = result * 1024 + LuaDLL.lua_gc(luaState, LuaGCOptions.LUA_GCCOUNTB, 0); return result; } #endregion public static void lua_pushstdcallcfunction(IntPtr L, LuaCSFunction fun) { #if XLUA LuaDLL.lua_pushstdcallcfunction(L, fun); #elif TOLUA LuaDLL.tolua_pushcfunction(L, fun); #elif SLUA LuaDLL.lua_pushcfunction(L, fun); #endif } public static void lua_setglobal(IntPtr L, string name) { #if XLUA LuaDLL.xlua_setglobal(L, name); #elif TOLUA LuaDLL.lua_setglobal(L, name); #elif SLUA LuaDLL.lua_setglobal(L, name); #endif } public static void lua_getglobal(IntPtr L, string name) { #if XLUA LuaDLL.xlua_getglobal(L, name); #elif TOLUA LuaDLL.lua_getglobal(L, name); #elif SLUA LuaDLL.lua_getglobal(L, name); #endif } } #region bind public class MikuLuaProfilerLuaProfilerWrap { public static void __Register(IntPtr L) { LuaDLL.lua_newtable(L); LuaDLL.lua_pushstring(L, "LuaProfiler"); LuaDLL.lua_newtable(L); LuaDLL.lua_pushstring(L, "BeginSample"); LuaLib.lua_pushstdcallcfunction(L, BeginSample); LuaDLL.lua_rawset(L, -3); LuaDLL.lua_pushstring(L, "EndSample"); LuaLib.lua_pushstdcallcfunction(L, EndSample); LuaDLL.lua_rawset(L, -3); LuaDLL.lua_rawset(L, -3); LuaLib.lua_setglobal(L, "MikuLuaProfiler"); LuaLib.lua_pushstdcallcfunction(L, BeginSample); LuaLib.lua_setglobal(L, "BeginMikuSample"); LuaLib.lua_pushstdcallcfunction(L, EndSample); LuaLib.lua_setglobal(L, "EndMikuSample"); LuaLib.lua_pushstdcallcfunction(L, UnpackReturnValue); LuaLib.lua_setglobal(L, "miku_unpack_return_value"); } [MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))] static int BeginSample(IntPtr L) { string _name = LuaDLL.lua_tostring(L, 1); MikuLuaProfiler.LuaProfiler.BeginSample(L, _name); return 0; } [MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))] static int UnpackReturnValue(IntPtr L) { MikuLuaProfiler.LuaProfiler.EndSample(L); return LuaDLL.lua_gettop(L); } [MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))] static int EndSample(IntPtr L) { MikuLuaProfiler.LuaProfiler.EndSample(L); return 0; } } #endregion } #endif