miduo_client/Assets/Scripts/LuaProfiler/HookSetup/LuaHookSetup.cs

368 lines
11 KiB
C#

/*
* ==============================================================================
* 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<long, string> stringDict = new Dictionary<long, string>();
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