XLua原理(一)

项目中活动都是用xlua开发的,项目周更热修也是用xlua的hotfix特性来做的。现研究底层原理,对于项目性能有个更好的把控。

本文认为看到该文章的人已具备使用xlua开发的能力,只研究介绍下xlua的底层实现原理。

一.luac#交互原理

概括:

通过栈来实现。lua调用c#就是将lua层的参数和c#导出函数入栈,然后执行函数。c#调用lua就是将c#层的参数和lua函数入栈,然后执行函数

1.1 C#访问lua

直接上代码:

 private void Demo1(){IntPtr L = LuaAPI.luaL_newstate();if (LuaAPI.luaL_loadbuffer(L, @"function addandsub(x,y) return x+y , x-y end", "selfTagChunk") != 0){Debug.LogError(LuaAPI.lua_tostring(L,-1));}//LuaAPI.lua_pushnumber(L,20);//LuaAPI.lua_pushnumber(L,21);LuaAPI.lua_pcall(L, 0, 0, 0);LuaAPI.xlua_getglobal(L, "addandsub");LuaAPI.lua_pushnumber(L,10);LuaAPI.lua_pushnumber(L,7);int valueB = LuaAPI.xlua_tointeger(L, -1);//7int valueB2 = LuaAPI.xlua_tointeger(L, -2);//10LuaTypes luaTypeB3 = LuaAPI.lua_type(L, -3);//functionint valueC4 = LuaAPI.xlua_tointeger(L, 3);//7int valueC3 = LuaAPI.xlua_tointeger(L, 2);//10LuaTypes luaTypeC2 = LuaAPI.lua_type(L, 1);//functionif (LuaAPI.lua_pcall(L, 2, 2, 0) != 0){Debug.LogError(LuaAPI.lua_tostring(L,-1));}int value = LuaAPI.xlua_tointeger(L, -1); //3int value2 = LuaAPI.xlua_tointeger(L, -2); //17LuaAPI.lua_close(L);}

Api备注:

LuaAPI.luaL_newstate:开辟lua虚拟机,执行lua程序
LuaAPI.lua_close:关闭lua虚拟机,释放资源
LuaAPI.luaL_loadbuffer:编译一段lua代码,但没执行
LuaAPI.lua_pcall:执行lua代码,这时候可以用

这里:先把addandsub方法压栈,然后把10和7分别压栈。所以看到的内存里的数据如批注所示。

在执行第2个lua_pcall。会把之前的堆栈信息清空,把函数执行返回的结果进行压栈操作

1.2 lua访问C#

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]public delegate void TestCSFunction(IntPtr L);[MonoPInvokeCallback(typeof(TestCSFunction))]public static void TestLuaCallCSharp(IntPtr L){Debug.Log("TestLuaCallCSharp");}private void Demo2(){IntPtr L = LuaAPI.luaL_newstate();//Marshal 提供对非托管类型的操作IntPtr function = Marshal.GetFunctionPointerForDelegate(new TestCSFunction(TestLuaCallCSharp));//函数入栈LuaAPI.lua_pushcclosure(L,function,0);LuaAPI.lua_pcall(L, 0, 0, 0);LuaAPI.lua_close(L);}

UnmanagedFunctionPointer:定义为了让其不受C#托管管理
MonoPInvokeCallback:标记可以使其用C或C++调用

上述可以看到是把C#函数包装成指针,然后进行压栈操作供lua调用

二.xlua中的LuaEnv

  private void Demo3(){LuaEnv luaenv = new LuaEnv();luaenv.DoString("CS.UnityEngine.Debug.Log('hello world')");luaenv.Dispose();}

LuaEnv:是xlua封装好的lua环境,类似上面的luaL_newstate。

具体的事情:

XLua框架中最重要的一个类,那就是LuaEnv。它包含了lua中的状态机RealStatePrt。lua的G表,还有注册表LuaIndexes.LUA_REGISTRYINDEX等等,下面从LuaEnv的构造函数开始,看看这个类做了些什么事情

//节选LuaEnv构造函数部分代码//拿到Lua中的注册表
LuaIndexes.LUA_REGISTRYINDEX = LuaAPI.xlua_get_registry_index//创建Lua状态机
rawL = LuaAPI.luaL_newstate()//十分重要的一个对象,用于c#和lua的交互
translator = new ObjectTranslator(this, rawL); 
translator.createFunctionMetatable(rawL);	//添加_gc元方法到注册表
translator.OpenLib(rawL);	//将init_xlua中会用到的方法,全部定义出来//添加搜索路径
AddSearcher(StaticLuaCallbacks.LoadBuiltinLib, 2); 
//添加自定义解析Lua文件的方法,对应的是LuaEnv.CustomLoader
AddSearcher(StaticLuaCallbacks.LoadFromCustomLoaders, 3);
#if !XLUA_GENERAL
AddSearcher(StaticLuaCallbacks.LoadFromResource, 4);
AddSearcher(StaticLuaCallbacks.LoadFromStreamingAssetsPath, -1);
#endif//十分重要!! 初始化xLua
DoString(init_xlua, "Init");#if !UNITY_SWITCH || UNITY_EDITOR
AddBuildin("socket.core", StaticLuaCallbacks.LoadSocketCore);
AddBuildin("socket", StaticLuaCallbacks.LoadSocketCore);
#endif
AddBuildin("CS", StaticLuaCallbacks.LoadCS);

调用Init方法:

private string init_xlua = @" local metatable = {}local rawget = rawgetlocal setmetatable = setmetatablelocal import_type = xlua.import_typelocal import_generic_type = xlua.import_generic_typelocal load_assembly = xlua.load_assembly--fqn就是类型和命名空间名,通过import_type去获取对应的udata并且入栈function metatable:__index(key) --查询key不调用元方法,更简单的表达只在自己的表内查询local fqn = rawget(self,'.fqn')fqn = ((fqn and fqn .. '.') or '') .. key--查询C#类型local obj = import_type(fqn)--如果不是 再次查询C#命名空间if obj == nil then-- It might be an assembly, so we load it too.obj = { ['.fqn'] = fqn }setmetatable(obj, metatable)elseif obj == true thenreturn rawget(self, key)end-- Cache this lookuprawset(self, key, obj)return objend--既然是C#对象 就不要再newindex了,避免产生未知的错误function metatable:__newindex()error('No such type: ' .. rawget(self,'.fqn'), 2)end-- A non-type has been called; e.g. foo = System.Foo()function metatable:__call(...)local n = select('#', ...)local fqn = rawget(self,'.fqn')if n > 0 thenlocal gt = import_generic_type(fqn, ...)if gt thenreturn rawget(CS, gt)endenderror('No such type: ' .. fqn, 2)endCS = CS or {}setmetatable(CS, metatable)--定义typeof 这下知道了 typeof是xlua自己搞的,不是lua本身语言特性typeof = function(t) return t.UnderlyingSystemType endcast = xlua.castif not setfenv or not getfenv thenlocal function getfunction(level)local info = debug.getinfo(level + 1, 'f')return info and info.funcendfunction setfenv(fn, env)if type(fn) == 'number' then fn = getfunction(fn + 1) endlocal i = 1while true dolocal name = debug.getupvalue(fn, i)if name == '_ENV' thendebug.upvaluejoin(fn, i, (function()return envend), 1)breakelseif not name thenbreakendi = i + 1endreturn fnendfunction getfenv(fn)if type(fn) == 'number' then fn = getfunction(fn + 1) endlocal i = 1while true dolocal name, val = debug.getupvalue(fn, i)if name == '_ENV' thenreturn valelseif not name thenbreakendi = i + 1endendendxlua.hotfix = function(cs, field, func)if func == nil then func = false endlocal tbl = (type(field) == 'table') and field or {[field] = func}for k, v in pairs(tbl) dolocal cflag = ''if k == '.ctor' thencflag = '_c'k = 'ctor'endlocal f = type(v) == 'function' and v or nilxlua.access(cs, cflag .. '__Hotfix0_'..k, f) -- at least onepcall(function()for i = 1, 99 doxlua.access(cs, cflag .. '__Hotfix'..i..'_'..k, f)endend)endxlua.private_accessible(cs)endxlua.getmetatable = function(cs)return xlua.metatable_operation(cs)endxlua.setmetatable = function(cs, mt)return xlua.metatable_operation(cs, mt)endxlua.setclass = function(parent, name, impl)impl.UnderlyingSystemType = parent[name].UnderlyingSystemTyperawset(parent, name, impl)endlocal base_mt = {__index = function(t, k)local csobj = t['__csobj']local func = csobj['<>xLuaBaseProxy_'..k]return function(_, ...)return func(csobj, ...)endend}base = function(csobj)return setmetatable({__csobj = csobj}, base_mt)end";

设置了metatble扩充原方法,并且设置CS的元表示metatable:

__index:会把C#没有缓存的命名空间下的元数据导入进来。

__call:与index同理,这里能看出来了为什么在lua里调C#方法是CS.UnityEngine.Vector3(x,x,x)。

这步是让lua可以去访问C#对象。

因为在Lua中定义了全局的CS表,并且在lua中调用CS的时候,会先调用StaticLuaCallbacks.LoadCS获取到注册表中的CS表,然后在调用XXX的时候,如果访问到了CS表中不存在的元素,则会调用其元表,在元表中通过映射到c#的StaticLuaCallbacks.ImportType方法完成查找。

lua在查找时调用了import_type进行查找调用,提前在OpenLib里把方法进行注册:

而importType会从中转器查询,查询的过程就是从一个维护的字典里看能不能取到,取不到就加载命名空间并注入到lua虚拟机中。

后面介绍lua与C#之间通信会详解介绍

参考:

Lua与C#交互原理(转)_lua与c#的交互原理-CSDN博客

https://zhuanlan.zhihu.com/p/441169478

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/48410.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用程序画出三角形图案

创建各类三角形图案 直角三角形&#xff08;左下角&#xff09; #include <iostream> using namespace std;int main() {int rows;cout << "输入行数: ";cin >> rows;for(int i 1; i < rows; i){for(int j 1; j < i; j){cout << &…

003uboot目录分析和两个阶段

我们都知道s3c2440是一个soc&#xff0c;内含cpu和各种控制器、片内的RAM&#xff0c;他的CPU是arm920t。 我们先来分析一下uboot原码的各个目录 1.uboot目录分析 board&#xff1a;board里存放的是支持各个开发板的文件&#xff0c;包括链接脚本 common: common目录中存放的…

graham 算法计算平面投影点集的凸包

文章目录 向量的内积&#xff08;点乘&#xff09;、外积&#xff08;叉乘&#xff09;确定旋转方向numpy 的 cross 和 outernp.inner 向量与矩阵计算示例np.outer 向量与矩阵计算示例 python 示例生成样例散点数据图显示按极角排序的结果根据排序点计算向量转向并连成凸包 基本…

set、map、multiset、multimap容器介绍和常用接口使用

文章目录 前言一、set容器二、multiset三、map四、multimap 前言 1、set、map、 multiset、 multimap都是基于红黑树实现的容器。 2、set、multiset都使用头文件#include<set>,map、multimap都是使用头文件#include<map> 一、set容器 1、set容器的介绍 C标准库中的…

pytest常用命令行参数解析

简介&#xff1a;pytest作为一个成熟的测试框架&#xff0c;它提供了许多命令行参数来控制测试的运行方式&#xff0c;以配合适用于不同的测试场景。例如 -x 可以用于希望出现错误就停止&#xff0c;以便定位和分析问题。–rerunsnum适用于希望进行失败重跑等个性化测试策略。 …

【BUG】已解决:AttributeError: ‘str‘ object has no attribute ‘get‘

已解决&#xff1a;AttributeError: ‘str‘ object has no attribute ‘get‘ 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&#xff0c;就职于医疗科技公司&#xff0c;热衷分享知识&#xff0c…

C++初学者指南-5.标准库(第一部分)--标准库查找算法

C初学者指南-5.标准库(第一部分)–标准库查找算法 文章目录 C初学者指南-5.标准库(第一部分)--标准库查找算法查找/定位一个元素findfind_iffind_if_notfind_last / find_last_if / find_last_if_notfind_first_of 查找范围内的子范围 search find_endstarts_withends_with 找到…

SpringBoot3 + Vue3 学习 Day 2

登入接口 和 获取用户详细信息的开发 学习视频登入接口的开发1、登入主逻辑2、登入认证jwt 介绍生成 JWT① 导入依赖② 编写代码③ 验证JWT 登入认证接口的实现① 导入 工具类② controller 类实现③ 存在的问题及优化① 编写拦截器② 注册拦截器③ 其他接口直接提供服务 获取用…

Web3D:WebGL为什么在渲染性能上输给了WebGPU。

WebGL已经成为了web3D的标配&#xff0c;市面上有N多基于webGL的3D引擎&#xff0c;WebGPU作为挑战者&#xff0c;在渲染性能上确实改过webGL一头&#xff0c;由于起步较晚&#xff0c;想通过这个优势加持&#xff0c;赶上并超越webGL仍需时日。 贝格前端工场为大家分享一下这…

Webstorm-恢复默认UI布局

背景 在使用Webstorm的时候,有时候进行个性化设置,如字体、界面布局等. 但是设置后的效果不理想,想要重新设置回原来的模样,却找不到设置项. 这里提供一种解决方案,恢复默认设置,即恢复到最初刚下载好后的设置. 操作步骤 步骤一:打开setting 步骤二:搜索Restore Default,找到…

数学建模-----SPSS参数检验和非参数检验

目录 1.参数检验 1.1独立样本t检验案例分析 1.1.1查看数据编号 1.1.2确定变量所属类型 1.1.3选项里面的置信区间 1.1.4对于结果进行分析 1.2配对样本t检验案例分析 1.2.1相关设置 1.2.2分析结果 2.非参数检验 2.1对比分析 2.2非参数检验的方法 2.3案例分析 2.3.1相…

10道JVM经典面试题

1、 JVM中&#xff0c;new出来的对象是在哪个区&#xff1f; 2、 说说类加载有哪些步骤&#xff1f; 3、 JMM是什么&#xff1f; 4、 说说JVM内存结构&#xff1f; 5、 MinorGC和FullGC有什么区别&#xff1f; 6、 什么是STW? 7、 什么情况下会发生堆/栈溢出&#xff1f…

当“广撒网”遇上“精准定点”的鱼叉式网络钓鱼

批量网络钓鱼电子邮件活动倾向于针对大量受众&#xff0c;它们通常使用笼统的措辞和简单的格式&#xff0c;其中不乏各种拼写错误。而有针对性的攻击往往需要付出更大的努力&#xff0c;攻击者会伪装成雇主或客户向目标发送包含个人详细信息的个性化消息。在更大范围内采用这种…

大语言模型-文本检索任务基准 BEIR

BEIR (A Heterogeneous Benchmark for Zero-shot Evaluation of Information Retrieval Models) 文本检索任务的基准&#xff0c;使用18 个数据集为检索系统的零样本评估提出了一个标准化基准&#xff0c; BEIR 基准上在9个不同领域的检索任务评估 10 种不同的检索方法。 九个…

义务外贸wordpress独立站主题

健身器材wordpress网站模板 跑步机、椭圆机、划船机、动感单车、健身车、深蹲架、龙门架、健身器材wordpress网站模板。 https://www.jianzhanpress.com/?p4251 农业机械wordpress网站模板 植保机械、畜牧养殖机械、农机配件、土壤耕整机械、农业机械wordpress网站模板。 …

2.1.卷积层

卷积 ​ 用MLP处理图片的问题&#xff1a;假设一张图片有12M像素&#xff0c;那么RGB图片就有36M元素&#xff0c;使用大小为100的单隐藏层&#xff0c;模型有3.6B元素&#xff0c;这个数量非常大。 识别模式的两个原则&#xff1a; 平移不变性&#xff08;translation inva…

K8S 部署jaeger-operator,与其演示项目hotrod

最近在研究observabilty在K8S环境的onboard&#xff0c;查阅了一些资料&#xff0c;发现现在网上Prometheus/Metrics相关的资源&#xff0c;是比较全面的&#xff0c;而Trace相关的部分不是很全面&#xff0c;所以写下这篇博文&#xff0c;以做备忘和分享。 组件介绍 我这里选…

Excel的操作

Excel的操作 一、Excel的作用 Excel是一款功能强大的电子表格软件&#xff0c;主要用于数据处理和分析。 二、Excel的基础操作 新建文档 一般情况下&#xff0c;就在桌面空白处&#xff0c;点击鼠标右键&#xff0c;即可新建 三、页面布局 1、快速访问工具栏 主要包含&am…

为 android编译 luajit库、 交叉编译

时间&#xff1a;20200719 本机环境&#xff1a;iMac2017 macOS11.4 参考: 官方的文档&#xff1a;Use the NDK with other build systems 写在前边&#xff1a;交叉编译跟普通编译类似&#xff0c;无非是利用特殊的编译器、链接器生成动态或静态库; make 本质上是按照 Make…

ssm 学习 ---(spring)

一、spring框架 1、基本框架 2、Beanfactory快速入门 配置清单&#xff1a;xml文件 (1) 导入jar包或者maven坐标 (2) 定义UserService接口以及UserService实现类 (3) 创建bean.xml配置文件&#xff0c;将UserService信息配置到该xml文件中; (4)编写测试代码&#xff0c;创…