Bootstrap

【学习笔记】从零开始学ToLua(四)tolua原理解析

lua调用C#

  • tolua中lua调用C#是基于去反射。
  • 把所有的c#类的public成员变量、成员函数,都导出到一个相对应的Wrap类中,而这些成员函数通过特殊的标记,映射到lua的虚拟机中,当在lua中调用相对应的函数时候,直接调用映射进去的c# wrap函数,然后再调用到实际的c#类,完成调用过程。
  • 当lua虚拟机启动的时候,会将此wrap文件加载进lua虚拟机,然后lua就可以识别此调用了。
  • 最后就形成了Lua 调用 Wrap , Wrap调用C#的模式,实现了Lua调用C# 

生成wrap文件

  • 生成Wrap文件需要使用者自己手动的去CustomSetting,填写需要Wrap的文件
  • BindLua.cs 文件,里面有个叫Binding的函数,我们手动填写要绑定的类型会被添加到里面的list的里。
  • 那里面会通过GenLuaBinders绑定wrap并注册到虚拟机

lua中对C#对象的交互

ObjectTranslator.cs

这个类代码不多,它存在的主要意义就是给lua中对C#对象的交互提供了基础,简单来说就是C#中的对象在传给lua时并不是直接把对象暴露给了lua,而是在这个OjbectTranslator里面注册并返回一个索引(可以理解为windows编程中的句柄)并把这个索引包装成一个userdata传递给lua,并且设置元表。具体可以查看tolua_pushnewudata代码。

而在lua需要通过上面传到lua里面的对象调用C#的方法时,它会调用ToLua.CheckObject或者ToLua.ToObject从ObjectTranslator获取真正的C#对象。

C#与Lua数据交互(lua虚拟栈)

  • C#与lua的数据交互是基于一个Lua先进后出的虚拟栈
  • 可以压入数字,字符串,表table,闭包func
  •  

C#与Lua通信(P/Invoke)

  • 所有的通信都是基于P/Invoke模式(性能低)类似JNI
  • P/Invoke:公共语言运行库(CLR)的interop功能(称为平台调用(P/Invoke))
  • 命名空间:System.Runtime.InteropServices

 tolua的优化方式汇总

  • BinderLua太多wrap很慢(反射与去反射共存)
  • Lua代码打入AssetBundle为了绕过苹果检测
  • 动态注册Wrap文件到Lua虚拟机(tolua延伸)
  • ToLuaExport. memberFilter的函数过滤
  • 尽量减少c#调用lua的次数来做主题优化思想
  • 尽量使用lua中的容器table取代c#中的所有容器
  • 例子CallLuaFunction_02里附带了no gc alloc调用方式
  • Lua的bytecode模式性能要低于Lua源码执行
  • 取消动态参数:打开LuaFunction.cs文件,找到函数声明:
public object[] Call(params object[] args){
    return call(args, null);
}

取消动态参数args,可用较笨方法,就是定义6-7个默认参数,不够再加。

  • 安卓平台如果使用luajit的话,记得在lua最开始执行的地方请开启 jit.off(),性能会提升N倍。
  • 记得安卓平台上在加上jit.opt.start(3),相当于c++程序-O3,可选范围0-3,性能还会提升。Luajit作者建议-O2

tolua部分代码说明

tolua#的核心运行时

tolua#的运行代码包含SourceGenerate下面的绑定代码以及ToLuaàBaseType代码以及Core下面的核心代码。接下来我们着重讲一下Core下面的几个主要类。

LuaAttribute.cs

它在tolua#生成绑定代码时做一些标示使用。Attribute 是一种可由用户自由定义的修饰符(Modifier),可以用来修饰各种需要被修饰的目标。特性Attribute 的作用是添加元数据。元数据可以被工具支持,比如:编译器用元数据来辅助编译,调试器用元数据来调试程序。Unity以及tolua#中就会用Attribute来辅助做一些事情。

LuaBaseRef.cs

Lua中对象对应C#中对象的一个基类(子类有LuaTable,LuaFunction,LuaThread),主要作用是有一个reference指向lua里面的对象,引用计数判断两个对象是否相等等。

LuaDll.cs

这个类的主要作用就是实现了C#调用原生代码的功能.

LuaState.cs

这里面是对真正的lua_State的封装,包括初始化lua路径,加载相应的lua文件,注册我们前面生成的绑定代码以及各种辅助函数。

ObjectTranslator.cs

接下来,我们着重说一下这个ObjectTranslator这个类,这个类代码不多,它存在的主要意义就是给lua中对C#对象的交互提供了基础,简单来说就是C#中的对象在传给lua时并不是直接把对象暴露给了lua,而是在这个OjbectTranslator里面注册并返回一个索引(可以理解为windows编程中的句柄)并把这个索引包装成一个userdata传递给lua,并且设置元表。具体可以查看tolua_pushnewudata代码。

而在lua需要通过上面传到lua里面的对象调用C#的方法时,它会调用ToLua.CheckObject或者ToLua.ToObject从ObjectTranslator获取真正的C#对象。

userdata

userdata实际上是一个指针地址,通过对这个userdata设置不同的metatable来区分userdata对应的c#类型

要更详细地了解userdata内容可以阅读   tolua#中的userdata @xsxjin

 


参考资料 http://richbabe.top/2018/07/20/ulua-tolua%E5%8E%9F%E7%90%86%E8%A7%A3%E6%9E%90/ @RichBaby

https://www.cnblogs.com/yptianma/p/11797925.html @天马yp

;