2025年4月15日 星期二 乙巳(蛇)年 正月十六 设为首页 加入收藏
rss
您当前的位置:首页 > 计算机 > 编程开发 > Lua

剖析一下LuaJIT的Table

时间:12-14来源:作者:点击数:3
城东书院 www.cdsy.xyz

安装 LuaJIT

因为是在 openresty 里面使用 LuaJIT 的,那么就直接从 openresty/luajit2 下载一份源代码吧,看到有 Makefile 文件,直接 make 报错,

  • ~/Downloads/luajit2-2.1-agentzh
  • [ 21:19:27 ] ❯ make
  • ==== Building LuaJIT 2.1.0-beta3 ====
  • /Library/Developer/CommandLineTools/usr/bin/make -C src
  • Makefile:323: *** missing: export MACOSX_DEPLOYMENT_TARGET=XX.YY. Stop.
  • make: *** [default] Error 2

查看文章 MacOS源码安装 LuaJIT

  • $ export MACOSX_DEPLOYMENT_TARGET=10.14
  • $ make install PREFIX=~/luajit

然后设置一下 PATH 环境变量,就可以看到 luajit 装好了

  • [ 22:41:36 ]which luajit
  • /Users/bingoobjca/luajit/bin/luajit
  • [ 22:41:59 ]luajit -v
  • LuaJIT 2.1.0-beta3 -- Copyright (C) 2005-2020 Mike Pall. https://luajit.org/

hack 源代码,增加打印 table 信息

在 src/lj_strfmt.c 中,修正函数 lj_strfmt_obj,增加对 tostring 的处置

  • /* Raw conversion of object to string. */
  • GCstr * LJ_FASTCALL lj_strfmt_obj(lua_State *L, cTValue *o)
  • {
  • if (tvisstr(o)) {
  • return strV(o);
  • } else if (tvisnumber(o)) {
  • return lj_strfmt_number(L, o);
  • } else if (tvisnil(o)) {
  • return lj_str_newlit(L, "nil");
  • } else if (tvisfalse(o)) {
  • return lj_str_newlit(L, "false");
  • } else if (tvistrue(o)) {
  • return lj_str_newlit(L, "true");
  • } else {
  • char buf[8+2+2+16], *p = buf;
  • p = lj_buf_wmem(p, lj_typename(o), (MSize)strlen(lj_typename(o)));
  • *p++ = ':'; *p++ = ' ';
  • if (tvisfunc(o) && isffunc(funcV(o))) {
  • p = lj_buf_wmem(p, "builtin#", 8);
  • p = lj_strfmt_wint(p, funcV(o)->c.ffid);
  • } else if (tvistab(o)) { // 从这里开始是新增的代码
  • p = lj_strfmt_wptr(p, lj_obj_ptr(G(L), o));
  • *p++ = '\0';
  • printf("-- %s\n", buf);
  • GCtab *t = tabV(o);
  • /* print array part */ {
  • uint32_t i, asize = t->asize;
  • printf("-- a[%d]: ", asize);
  • TValue *array = tvref(t->array);
  • for (i = 0; i < asize; i++) {
  • if (i>0) printf(", ");
  • cTValue *o = &array[i];
  • if (tvisstr(o)) printf("%s", strdata(strV(o)));
  • else if (tvisnum(o)) printf("%g", numV(o));
  • else if (tvisnil(o)) printf("nil");
  • else printf("?");
  • }
  • printf("\n");
  • }
  • /* print hashmap part */ {
  • uint32_t i, hmask = t->hmask;
  • printf("-- h[%d]: ", hmask+1);
  • Node *node = noderef(t->node);
  • for (i = 0; i <= hmask; i++) {
  • if (i>0) printf(", ");
  • Node *n = &node[i];
  • cTValue *k = &n->key;
  • cTValue *v = &n->val;
  • if (tvisstr(k)) printf("%s", strdata(strV(k)));
  • else if (tvisnum(k)) printf("%g", numV(k));
  • else if (tvisnil(k)) printf("nil");
  • else printf("?");
  • printf("=");
  • if (tvisstr(v)) printf("%s", strdata(strV(v)));
  • else if (tvisnum(v)) printf("%g", numV(v));
  • else if (tvisnil(v)) printf("nil");
  • else printf("?");
  • }
  • printf("\n");
  • }
  • // 从这里新增的代码结束
  • } else {
  • p = lj_strfmt_wptr(p, lj_obj_ptr(G(L), o));
  • }
  • return lj_str_new(L, buf, (size_t)(p - buf));
  • }
  • }

剖析 table

habr.lua

  • jit.off()
  • ffi = require('ffi')
  • require('table.new')
  • require('table.clear')
  • local function caption(h, c)
  • print(h)
  • print(string.rep(c or '-', #h))
  • print()
  • end
  • function traverse(fn, t)
  • local str = '-- '
  • for k, v, n in (fn or pairs)(t) do
  • if str ~= '-- ' then
  • str = str .. ', '
  • end
  • str = string.format('%s%s=%s%s',
  • str, k, v, n and ', ' or ''
  • )
  • end
  • print(str)
  • end
  • local function codeblock(str)
  • print('```lua')
  • for l in string.gmatch(str, "([^\n]*)\n") do
  • print(l)
  • assert(loadstring(l))()
  • end
  • print('```\n')
  • end
  • caption('Welcome to the LuaJIT internals', '=')
  • --------------------------
  • caption('Анатомия таблиц')
  • codeblock([[
  • t = {}
  • tostring(t)
  • ]])
  • codeblock([[
  • t["a"] = "A"
  • t["b"] = "B"
  • t["c"] = "C"
  • tostring(t)
  • ]])
  • codeblock([[
  • t1 = {a = 1, b = 2, c = 3}
  • tostring(t1)
  • t2 = {c = 3, b = 2, a = 1}
  • tostring(t2)
  • traverse(pairs, t1)
  • traverse(pairs, t2)
  • ]])
  • codeblock([[
  • t2["c"] = nil
  • traverse(pairs, t2)
  • tostring(t2)
  • print('-- ', next(t2, "c"))
  • ]])
  • ------------------
  • caption('Массивы')
  • codeblock([[
  • t = {1, 2}
  • tostring(t)
  • ]])
  • codeblock([[
  • t = {[2] = 2, 1}
  • tostring(t)
  • ]])
  • ---------------------------
  • caption('Итератор pairs()')
  • codeblock([[
  • t = table.new(4, 4)
  • for i = 1, 8 do t[i] = i end
  • tostring(t)
  • traverse(pairs, t)
  • ]])
  • codeblock([[
  • t[9] = 9
  • tostring(t)
  • ]])
  • -------------------------------------
  • caption('Длина таблицы table.getn()')
  • codeblock([[
  • print(#{nil, 2})
  • print(#{[2] = 2})
  • ]])
  • codeblock([[
  • tostring({nil, 2})
  • tostring({[2] = 2})
  • ]])
  • ----------------------------------
  • caption('Сортировка table.sort()')
  • ----------------------------------
  • caption('Pack / unpack')
  • codeblock([[
  • t = {nil, 2}
  • tostring(t)
  • traverse(pairs, t)
  • print(unpack(t, 1, t.n))
  • ]])
  • ----------------------------
  • caption('Итератор ipairs()')
  • codeblock([[
  • t = {1, 2, nil, 4}
  • print(#t) -- UB
  • traverse(ipairs, t)
  • ]])
  • ------------------------------
  • caption('Подводные камни FFI')
  • codeblock([[
  • NULL = ffi.new('void*', nil)
  • print(type(NULL))
  • print(type(nil))
  • print(NULL == nil)
  • if NULL then print('NULL is not nil') end
  • ]])
  • os.exit(1)

运行

  • [ 22:46:35 ] ❯ luajit habr.lua
  • Welcome to the LuaJIT internals
  • ===============================

Анатомия таблиц

  • t = {}
  • tostring(t)
  • -- table: 0x07cd7c80
  • -- a[0]:
  • -- h[1]: nil=nil
  • t["a"] = "A"
  • t["b"] = "B"
  • t["c"] = "C"
  • tostring(t)
  • -- table: 0x07cd7c80
  • -- a[0]:
  • -- h[4]: nil=nil, b=B, a=A, c=C
  • t1 = {a = 1, b = 2, c = 3}
  • tostring(t1)
  • -- table: 0x07cd8890
  • -- a[0]:
  • -- h[4]: nil=nil, b=2, a=1, c=3
  • t2 = {c = 3, b = 2, a = 1}
  • tostring(t2)
  • -- table: 0x07cd8f08
  • -- a[0]:
  • -- h[4]: nil=nil, b=2, c=3, a=1
  • traverse(pairs, t1)
  • -- b=2, a=1, c=3
  • traverse(pairs, t2)
  • -- b=2, c=3, a=1
  • t2["c"] = nil
  • traverse(pairs, t2)
  • -- b=2, a=1
  • tostring(t2)
  • -- table: 0x07cd8f08
  • -- a[0]:
  • -- h[4]: nil=nil, b=2, c=nil, a=1
  • print('-- ', next(t2, "c"))
  • -- a 1

Массивы

  • t = {1, 2}
  • tostring(t)
  • -- table: 0x07cda5d8
  • -- a[3]: nil, 1, 2
  • -- h[1]: nil=nil
  • t = {[2] = 2, 1}
  • tostring(t)
  • -- table: 0x07cdaa28
  • -- a[2]: nil, 1
  • -- h[2]: nil=nil, 2=2

Итератор pairs()

  • t = table.new(4, 4)
  • for i = 1, 8 do t[i] = i end
  • tostring(t)
  • -- table: 0x07cdaec0
  • -- a[5]: nil, 1, 2, 3, 4
  • -- h[4]: 7=7, 8=8, 5=5, 6=6
  • traverse(pairs, t)
  • -- 1=1, 2=2, 3=3, 4=4, 7=7, 8=8, 5=5, 6=6
  • t[9] = 9
  • tostring(t)
  • -- table: 0x07cdaec0
  • -- a[17]: nil, 1, 2, 3, 4, 5, 6, 7, 8, 9, nil, nil, nil, nil, nil, nil, nil
  • -- h[1]: nil=nil

Длина таблицы table.getn()

  • print(#{nil, 2})
  • 2
  • print(#{[2] = 2})
  • 0
  • tostring({nil, 2})
  • -- table: 0x07cdc660
  • -- a[3]: nil, nil, 2
  • -- h[1]: nil=nil
  • tostring({[2] = 2})
  • -- table: 0x07cdc848
  • -- a[0]:
  • -- h[2]: nil=nil, 2=2

Сортировка table.sort()

Pack / unpack

  • t = {nil, 2}
  • tostring(t)
  • -- table: 0x07cdcdd0
  • -- a[3]: nil, nil, 2
  • -- h[1]: nil=nil
  • traverse(pairs, t)
  • -- 2=2
  • print(unpack(t, 1, t.n))
  • nil 2

Итератор ipairs()

  • t = {1, 2, nil, 4}
  • print(#t) -- UB
  • 4
  • traverse(ipairs, t)
  • -- 1=1, 2=2

Подводные камни FFI

  • NULL = ffi.new('void*', nil)
  • print(type(NULL))
  • cdata
  • print(type(nil))
  • nil
  • print(NULL == nil)
  • true
  • if NULL then print('NULL is not nil') end
  • NULL is not nil
城东书院 www.cdsy.xyz
方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
    无相关信息
栏目更新
栏目热门
本栏推荐