`
chinamming
  • 浏览: 151296 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

Lua5.1代码阅读(六):ltm.h/ltm.c

 
阅读更多

一、概览

ltm.h/ltm.c的作用是提供查询元方法(元方法的值可能是函数,也可能是非函数的值)的API。

源码中把元方法称为标签方法(tag method)。

Lua的元方法有点像C++的运算符重载,用于覆盖一些Lua内部定义的默认行为。

参考链接:

1. LUA源码分析五:元表

http://lin-style.iteye.com/blog/1012138

2. Lua GC 的源码剖析 (2)

http://blog.codingnow.com/2011/03/lua_gc_2.html

查询元表的方式有两种:

* 方式一、查询某个元表(Table结构体)的元方法(见fasttm, gfasttm)

首先,把事件(类型是枚举值)转换为元方法名称(类型是TString *字符串)。

然后,通过查询Table结构体(相当于关联数组),获取元方法的值,

如果结果为空(nil值),则把这个信息缓存到Table结构体中(flags域),

下次查询时就可以直接返回空指针。

* 方式二、查询某个对象的元方法(见luaT_gettmbyobj)

首先,判断对象是表、用户数据还是其它基本类型

(TValue实际是个联合体,所以需要判断类型,

然后用hvalue和uvalue宏转换为正确的类型,

见lobject.h的TValue、Value结构体,lstate.h的GCObject联合体)

这里,根据类型用相应的宏取出作为元表的Table *指针:

* 表:hvalue(o)对应GCObject的struct Table h字段。元表是->metatable。

* 用户数据:uvalue(o)对应GCObject的union Udata u字段。元表是->metatable。

* 其它基本类型:G(L)对应lua_State的global_State *l_G字段,元表是->mt[ttype(o)],

ttype(o)是o的基本类型索引(定义在lua.h的LUA_TNIL到LUA_TTHREAD常量)。

然后,用类似情况一的方式查元表,但不缓存nil结果,也不读取Table的flags缓存标志。

二、相关结构体(均定义在ltm模块外)

* 元表内部实现是结构体Table:

lobject.h:

typedef struct Table {

CommonHeader;

lu_byte flags; /* 1<<p means tagmethod(p) is not present */

lu_byte lsizenode; /* log2 of size of `node' array */

struct Table *metatable;

...

其中flags用于缓存nil结果(位数组)。

* Table的flags域用于缓存元表的查询(加速判断元方法是否存在)

详细见gfasttm的宏定义以及luaT_gettm的实现

* global_State结构体携带元方法名称数组信息,用于快速把枚举值转换为TString *字符串。

lstate.h

...

struct Table *mt[NUM_TAGS]; /* metatables for basic types */

TString *tmname[TM_N]; /* array with tag-method names */

} global_State;

其中mt是把LUA_TNIL到LUA_TTHREAD的常量(定义在lua.h中)映射为基本类型的元表。

(基本类型的元表由lapi.c的lua_setmetatable修改)

tmname用于所有元方法枚举映射为TString *数组,

以便于查询元表时获取luaH_getstr()需要传入的作为键名的字符串指针参数。

三、头文件

#include <string.h>

#include "lua.h"

#include "lobject.h"

#include "lstate.h"

#include "lstring.h"

#include "ltable.h"

#include "ltm.h"

四、宏定义

1. #define ltm_c

表示源于ltm.c。

2. #define LUA_CORE

表示ltm作为Lua的底层实现。

五、全局的枚举值

1. TMS(元标签类型)

typedef enum {

TM_INDEX,

TM_NEWINDEX,

TM_GC,

TM_MODE,

TM_EQ, /* last tag method with `fast' access */

TM_ADD,

TM_SUB,

TM_MUL,

TM_DIV,

TM_MOD,

TM_POW,

TM_UNM,

TM_LEN,

TM_LT,

TM_LE,

TM_CONCAT,

TM_CALL,

TM_N /* number of elements in the enum */

} TMS;

注意它的值分别对应luaT_init内的luaT_eventname数组

static const char *const luaT_eventname[] = { /* ORDER TM */

"__index", "__newindex",

"__gc", "__mode", "__eq",

"__add", "__sub", "__mul", "__div", "__mod",

"__pow", "__unm", "__len", "__lt", "__le",

"__concat", "__call"

};

另外,fasttm和gfasttm宏只支持查询TM_INDEX和TM_MODE之间元方法的值。

而luaT_gettmbyobj可以查所有TMS类型。

六、全局变量

1. const char *const luaT_typenames[] = {

"nil", "boolean", "userdata", "number",

"string", "table", "function", "userdata", "thread",

"proto", "upval"

};

这个数组是用来把LUA_TNIL到LUA_TTHREAD常量(定义在lua.h中)转换为字符串。

跟元方法的关系不大(配合ttype宏获取TValue结构体的类型信息)

七、全局宏

1. #define gfasttm(g,et,e) ((et) == NULL ? NULL : \

((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e]))

这个宏的作用是快速获取指定元方法对应的TValue *值。

给定——

* 全局状态g(类型为global_State结构体的L栈全局状态G(L),见lua_State的l_G域)、

* 表et(类型为Table结构体的元表,事件表?)、

* 事件e(类型为TMS的元方法枚举值),

返回获取的标签方法(元方法)的对应值(类型为TValue *)。

作用类似下面的伪代码(et可以看成是一个以字符串为下标的关联数组)。

tm gfasttm(g, et, event)

{

return et[g.metaname[event]]

}

由于lgc的traversetable方法要取__mode元方法的值,

但traversetable方法是直接以global_State类型作为参数,

所以需要定义这个gfasttm()宏(实际上它和fasttm是同等作用的)

2. #define fasttm(l,et,e) gfasttm(G(l), et, e)

相当于gfasttm(G(L), et, event)。

和gfasttm作用相同,都是快速获取指定元方法对应的TValue *值。

除了lgc的traversetable函数外,Lua其它代码(分布在lgc, ltm, lvm三个模块)

都使用它从元表中取出元方法的值。

八、全局导出函数

1. void luaT_init (lua_State *L) {

由于需要查Table的值(使用luaH_getstr),要用到TString *的键,需要缓存元方法常数。

同时确保每个常数都不会被回收。

2. const TValue *luaT_gettm (Table *events, TMS event, TString *ename) {

作为gfasttm和fasttm的内部实现(判断nil缓存的工作交给宏处理)

当发现结果为nil,该函数会对events的flags做标记(把某个位从0变成1)以达到缓存效果。

返回的TM值可能是闭包、值或者是空指针。

3. const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) {

查询o的event元方法,如果o既不是表也不是用户数据,则查询L的event元方法。

九、关键代码

1. luaT_gettm / luaT_gettmbyobj

实际上它们都使用luaH_getstr进行索引查询,

不同的是,前者使用元表的位数组缓存查询到的nil结果,

但是只支持__index, __newindex, __gc和__mode,

而后者没有做结果的缓存处理,所以没有限制元方法的类型范围。

分享到:
评论

相关推荐

    lua-utf8.zip

    a utf-8 support module for Lua and LuaJIT 源码地址:https://github.com/starwing/luautf8 编译后可用的库: Linux版:lua-utf8.so Windows版:lua-utf8.dll(若是用在openresty中,openresty版本需使用32位版本...

    luadec解密工具 包含了5.1、5.2、5.3版本的 luareplace.exe/ luaopswap.exe/ luadec.exe/ lua.exe

    ├─5.1 │ └─bin │ liblua51.lib │ lua.exe │ lua51.dll │ lua51.lib │ luac.exe │ luadec.exe │ luaopswap.exe │ luareplace.exe │ ├─5.2 │ └─bin │ liblua52.lib │ lua.exe │ lua52.dll │ ...

    lua5.1 cjson.dll模块

    cjson.dll 需要lua5.1.dll 调用require “cjson” cjson.dll 需要lua5.1.dll 调用require “cjson”

    Lua5.1.5-lib库

    1. **lua.h**: 这是Lua C API的头文件,定义了所有与C语言交互的函数和数据结构。 2. **lua.c/lua.o**: Lua的主解析器和虚拟机实现,编译后的对象文件或静态库。 3. **lapi.c/lapi.o**: 实现了Lua与C之间的接口,...

    Lua5.1全三套:Lua Programming(中英文版)+中文手册

    本文将详细解析"Lua5.1全三套:Lua Programming(中英文版)+中文手册"中包含的知识点。 首先,我们有《Lua Programming》第二版的中文版和英文版。这本书由Mario J. Silva、Luiz Henrique de Figueiredo和Roberto ...

    lua5.1基础环境包(LuaForWindows_v5.1.5-52及mingw).zip

    总结来说,这个压缩包为Windows用户提供了完整的Lua 5.1开发环境,包括解释器、调试工具以及用于编译C扩展的MinGW。通过这个环境,开发者能够快速入门并深入掌握Lua编程,利用其强大的功能来解决各种问题。

    FairyGUI生成lua代码插件.rar

    FairyGUI生成lua代码插件 导入到FairyGUI编辑器,可以为UI生成lua代码。 Git路径: https://github.com/qufangliu/Plugin_FairyGUI_Lua

    lua-5.1.5-Win64-bin (exe)程序

    2. **luac5.1.exe**:这是Lua的编译器,它可以将Lua源代码转换为预编译的字节码,这种字节码可以直接由Lua虚拟机执行,提高了加载速度。这对于大型应用或者需要快速启动的环境尤其有用。 3. **bin2c5.1.exe**:这是...

    在线编码环境Praxis.zip

    Praxis 是基于 Lua,Lisp 和 Forth 的在线编码环境。 特性 OpenGL 实时音频生成 Midi 立体引擎 可编程的文本编辑器 等等 Introduction: https://www.youtube.com/watch?v=1VRtRazMYSA Running the ...

    ZeroBraneStudio1.9和lua脚本测试代码

    ZeroBrane Studio是一个免费、开源、跨平台(Windows、MacOSX和Linux)的Lua集成开发环境(IDE),它提供了代码提示、远程调试、代码分析、语法高亮等功能,支持Lua 5.1、Lua 5.2、Lua 5.3、LuaJIT和其他Lua引擎1。

    Lua-5.1.5-部分源码注释.rar

    1. **API接口(lapi.c)**:这部分代码定义了Lua与C语言交互的接口,包括创建和销毁lua_State,调用lua_pcall,注册C函数到全局环境等操作。 2. **编译器(lcode.c, llex.c, lparser.c)**:Lua的编译器将源代码转换为...

    lua5.1.lib

    lua5.1.lib文件缺失,LNK1181

    lua5.1 +luarocks for windows64安装版

    Lua 5.1是Lua语言的一个版本,发布于2006年,它提供了强大的数据结构,如表(tables),支持动态类型的面向对象编程,以及灵活的接口机制,使它能够方便地与各种C/C++程序进行交互。这个版本相对于更早期或更晚期的...

    lua-nginx-module-0.10.9rc7

    例如,使用`lua_code_cache on|off`来控制Lua代码缓存策略,用`set_by_lua_file`或`access_by_lua_file`等指令执行Lua脚本。 4. **测试与启动**:在修改配置后,务必先运行`nginx -t`测试配置文件的正确性,无误后...

    lua5.1静态库

    源代码通常包含`.c`和`.h`文件,`.c`文件是实现函数和数据结构的C语言代码,`.h`文件则定义了头文件,包含对外接口声明。这对于理解Lua的内部工作原理以及根据特定需求定制功能非常有用。 "编译 lua5.1"标签指示了...

    lua5.1压缩包源文件

    其中,`lua.c` 和 `luac.c` 分别是 Lua 解释器和编译器的主要实现。通过阅读这些源码,你可以了解到 Lua 如何解析和执行代码。 2. `lualib/`:这个目录包含了 Lua 标准库的源代码,如数学运算、字符串处理、文件I/O...

    Cocos2d-x之C++和Lua通信5个入门Demo

    木头Cocos2d-x教程 Lua篇 Demo源代码。 教程地址: 第1章:http://blog.csdn.net/musicvs/article/details/8440707 第2章:http://blog.csdn.net/musicvs/article/details/8440919 第3章:...

    c#调用脚本语言Lua——简单Demo

    c#调用脚本语言Lua——简单Demo 配置: 1. 下载c#下的Lua支持类库。下载地址:http://files.luaforge.net/releases/luainterface/luainterface/2.0.3 将(lua51.dll\LuaInterface.dll)引用自己的项目中。 2. 修改...

    lua源码下载 Lua-5.3.4 源码 最新 截止2017-3-7

    3. **lualib.h** 和 **luac.h**: 分别包含了标准库和编译器的接口。 4. **lstate.h**: 描述了lua_State结构,它是Lua执行环境的核心,保存了所有运行时信息。 5. **lparser.h** 和 **llex.h**: 用于解析Lua源代码...

    windows下使用的luac 基于5.1版本

    《Windows环境下基于5.1版本的LuaC使用详解》 LuaC是一款用于编译Lua脚本的工具,它将源代码转换成预编译的字节码,以便于提高程序的加载速度和安全性。在Windows操作系统中,Luac 5.1版本是广泛使用的版本,与lua...

Global site tag (gtag.js) - Google Analytics