因为是在 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/
在 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));
- }
- }
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
- 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
- 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
- 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
- t = {1, 2, nil, 4}
- print(#t) -- UB
- 4
- traverse(ipairs, t)
- -- 1=1, 2=2
- 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