Browse Source

add: 内存优化第二阶段-luf, 新的luac存储格式. 尚未调通,仍需努力

已经完成的调整
1. Proto结构体的内存是需要动态的,因为部分属性是动态修改的
2. 字符串统统转为长字符串类型,已落地存储,不占内存
3. 调试信息已落地
4. 常量信息已落地
5. upvalues描述符已落地
6. 操作码code已落地
7. 对90%以上的数据进行校对,均与原函数等价

当前存在的问题:
访问任何全局方法或变量,必挂

猜测的原因: 某个数据结构不可以落地存储?
Wendal Chen 4 years ago
parent
commit
9e233dff50

+ 25 - 0
bsp/win32/luf_test/abc.lua

@@ -0,0 +1,25 @@
+
+local abc = {}
+abc.version = 1
+abc[1] = 123
+abc["hi"] = function (name)
+    -- log.info("*abc*", name)
+    -- return "Hi, ".. name, function ()
+    --     os.exit(123)
+    -- end
+    return "hi, ".. name
+end
+-- _G.print(1)
+-- log.info("abc", "Great")
+-- return abc
+wendal = 1
+
+function abc.h2(name) 
+    local function hi12345678901234567890123456789012345678902()
+        
+    end
+    hi12345678901234567890123456789012345678902()
+    return "hi, " .. name, function() end
+end
+
+return abc

BIN
bsp/win32/luf_test/abc.luf


+ 39 - 0
bsp/win32/luf_test/main.lua

@@ -0,0 +1,39 @@
+
+log.info("main", "hi")
+
+local func = loadfile("abc.lua")
+log.info("func", func)
+buff = zbuff.create(16*1024)
+data = luf.dump(func, false, buff)
+
+buff:write(data)
+
+log.info("data", #data)
+print(data:toHex())
+
+io.writeFile("abc.luf", data)
+
+func2 = luf.undump(data)
+
+if func2 then
+    log.info("func??", func2)
+    luf.cmp(func, func2)
+    local abc = func2()
+    log.info("table?", type(abc))
+    log.info("table?", json.encode(abc))
+    if abc.version then
+        log.info("abc", abc["version"])
+    else
+        log.info("abc", "no version")
+    end
+    if abc.h2 then
+        log.info("abc", abc.h2("wendal"))
+    else
+        log.info("abc", "no hi function")
+    end
+    log.info("func??", "end", abc[1])
+else
+    log.info("func", "nil!!!")
+end
+
+os.exit(0)

+ 118 - 0
components/luf/luat_lib_luf.c

@@ -0,0 +1,118 @@
+#include "luat_base.h"
+#include "luat_malloc.h"
+
+#include "lprefix.h"
+
+
+#include <stddef.h>
+
+#include "lua.h"
+#include "lapi.h"
+
+#include "lobject.h"
+#include "lstate.h"
+#include "lundump.h"
+#include "luat_zbuff.h"
+
+int luf_dump(lua_State *L, const Proto *f, lua_Writer w, void *data, int strip, int ptroffset);
+
+LClosure *luat_luf_undump(lua_State *L, ZIO *Z, const char *name);
+
+void luat_luf_cmp(lua_State *L, const Proto* p1, const Proto *p2);
+
+static int writer (lua_State *L, const void *b, size_t size, void *B) {
+  (void)L;
+  luaL_addlstring((luaL_Buffer *) B, (const char *)b, size);
+  return 0;
+}
+
+static int l_luf_dump(lua_State* L) {
+  luaL_Buffer b;
+  TValue *o;
+  int strip = lua_toboolean(L, 2);
+  uint32_t ptroffset = 0;
+  luaL_checktype(L, 1, LUA_TFUNCTION);
+
+  luat_zbuff_t *zbuff = NULL;
+
+  if (lua_isuserdata(L, 3)) {
+    zbuff = luaL_checkudata(L, 3, LUAT_ZBUFF_TYPE);
+    ptroffset = (uint32_t)zbuff->addr;
+  }
+  else if (lua_isinteger(L, 3)) {
+    ptroffset = luaL_checkinteger(L, 3);
+  }
+
+  lua_settop(L, 1);
+  luaL_buffinit(L,&b);
+
+  lua_lock(L);
+  api_checknelems(L, 1);
+  o = L->top - 1;
+  if (luf_dump(L, getproto(o), writer, &b, strip, ptroffset) != 0)
+    return luaL_error(L, "unable to dump given function");
+  luaL_pushresult(&b);
+  lua_unlock(L);
+  return 1;
+}
+
+typedef struct LoadS {
+  const char *s;
+  size_t size;
+} LoadS;
+
+
+static const char *getS (lua_State *L, void *ud, size_t *size) {
+  LoadS *ls = (LoadS *)ud;
+  (void)L;  /* not used */
+  if (ls->size == 0) return NULL;
+  *size = ls->size;
+  ls->size = 0;
+  return ls->s;
+}
+
+static int l_luf_undump(lua_State* L) {
+  ZIO z;
+  LoadS ls;
+  ls.s = luaL_checklstring(L, 1, &ls.size);
+  luaZ_init(L, &z, getS, &ls);
+
+  zgetc(&z);
+
+  luat_luf_undump(L, &z, NULL);
+  return 1;
+}
+
+static int l_luf_cmp(lua_State* L) {
+  luaL_checktype(L, 1, LUA_TFUNCTION);
+  luaL_checktype(L, 2, LUA_TFUNCTION);
+
+  lua_settop(L, 2);
+
+  TValue *o;
+  Proto* p1;
+  Proto* p2;
+
+  o = L->top - 2;
+  p1 = getproto(o);
+  o = L->top - 1;
+  p2 = getproto(o);
+
+  luat_luf_cmp(L, p1, p2);
+
+  return 0;
+}
+
+#include "rotable.h"
+static const rotable_Reg reg_luf[] =
+{
+    { "dump" ,        l_luf_dump , 0},
+    { "undump" ,      l_luf_undump , 0},
+    { "cmp",          l_luf_cmp,   0},
+	{ NULL,          NULL ,       0}
+};
+
+LUAMOD_API int luaopen_luf( lua_State *L ) {
+    luat_newlib(L, reg_luf);
+    return 1;
+}

+ 129 - 0
components/luf/luat_luf_cmp.c

@@ -0,0 +1,129 @@
+#include "luat_base.h"
+#include "luat_malloc.h"
+
+#define ldump_c
+#define LUA_CORE
+
+#include "lprefix.h"
+
+
+#include <stddef.h>
+
+#include "lua.h"
+
+#include "lobject.h"
+#include "lstate.h"
+#include "lundump.h"
+#include "lstring.h"
+
+#define LUAT_LOG_TAG "cmp"
+#include "luat_log.h"
+
+static void cmpProto(const Proto* p1, const Proto *p2);
+
+static void cmpCode(const Proto* p1, const Proto *p2) {
+    LLOGD("code %d", memcmp(p1->code, p2->code, sizeof(Instruction)*p1->sizecode));
+}
+
+
+static void cmpConstants(const Proto* p1, const Proto *p2) {
+    for (size_t i = 0; i < p1->sizek; i++)
+    {
+        TValue* o1 = &p1->k[i];
+        TValue* o2 = &p2->k[i];
+        if (ttype(o1) != ttype(o2)) {
+            LLOGD("Constants Not Match %d %d %d", i, ttype(o1), ttype(o2));
+            continue;
+        }
+        switch (p1->k[i].tt_)
+        {
+        case LUA_TSHRSTR:
+        case LUA_TLNGSTR:
+            if (tsslen(tsvalue(o1)) != tsslen(tsvalue(o2))) {
+                LLOGE("strlen NOT match %d %d", tsslen(tsvalue(o1)), tsslen(tsvalue(o2)));
+            }
+            if (!strcmp(getstr(tsvalue(o1)), getstr(tsvalue(o2)))) {
+                LLOGE("str value NOT match %s %s", getstr(tsvalue(o1)), getstr(tsvalue(o2)));
+            }
+            break;
+        
+        default:
+            break;
+        }
+    }
+    
+}
+static void cmpUpvalues(const Proto* p1, const Proto *p2) {
+    for (size_t i = 0; i < p1->sizeupvalues; i++)
+    {
+        Upvaldesc* u1 = &p1->upvalues[i];
+        Upvaldesc* u2 = &p2->upvalues[i];
+
+        if (u1->idx != u2->idx) {
+            LLOGE("upvalues idx NOT match %d %d", u1->idx, u2->idx);
+        }
+        if (u1->instack != u2->instack) {
+            LLOGE("upvalues instack NOT match %d %d", u1->instack, u2->instack);
+        }
+        if (u1->name == NULL || u2->name == NULL) {
+            LLOGE("upvalues NULL name %d", i);
+        }
+        if (strcmp(getstr(u1->name), getstr(u2->name))) {
+            LLOGE("upvalues name NOT match %s %s", getstr(u1->name), getstr(u2->name));
+        }
+    }
+    
+}
+static void cmpProtos(const Proto* p1, const Proto *p2) {
+    LLOGD("protos %d", p1->sizep == p2->sizep);
+    if (p1->sizep == p2->sizep) {
+        for (size_t i = 0; i < p1->sizep; i++)
+        {
+            cmpProto(p1->p[i], p2->p[i]);
+        }
+    }
+}
+static void cmpDebug(const Proto* p1, const Proto *p2) {
+    LLOGD("linenumbers %d", memcmp(p1->lineinfo, p2->lineinfo, sizeof(int) * p1->sizelineinfo));
+    for (size_t i = 0; i < p1->sizelineinfo; i++)
+    {
+        /* code */
+    }
+    
+}
+
+static void cmpProto(const Proto* p1, const Proto *p2) {
+    if (p1 == NULL || p2 == NULL) {
+        LLOGD("p1/p2 is null");
+        return;
+    }
+    if (p1 == p2) {
+        LLOGD("p1 == p2, in pointer form");
+        return;
+    }
+
+    LLOGD("source %s %s %d", getstr(p1->source), getstr(p2->source), strcmp(getstr(p1->source), getstr(p2->source)));
+
+    // 对比几个属性
+    LLOGD("linedefined %d %d %d", p1->linedefined, p2->linedefined, p1->linedefined == p2->linedefined);
+    LLOGD("lastlinedefined %d %d %d", p1->lastlinedefined, p2->lastlinedefined, p1->lastlinedefined == p2->lastlinedefined);
+    LLOGD("is_vararg %d %d %d", p1->is_vararg, p2->is_vararg, p1->is_vararg == p2->is_vararg);
+    LLOGD("numparams %d %d %d", p1->numparams, p2->numparams, p1->numparams == p2->numparams);
+    LLOGD("sizecode %d %d %d", p1->sizecode, p2->sizecode, p1->sizecode == p2->sizecode);
+    LLOGD("sizek %d %d %d", p1->sizek, p2->sizek, p1->sizek == p2->sizek);
+    LLOGD("sizelineinfo %d %d %d", p1->sizelineinfo, p2->sizelineinfo, p1->sizelineinfo == p2->sizelineinfo);
+    LLOGD("sizelocvars %d %d %d", p1->sizelocvars, p2->sizelocvars, p1->sizelocvars == p2->sizelocvars);
+    LLOGD("sizeupvalues %d %d %d", p1->sizeupvalues, p2->sizeupvalues, p1->sizeupvalues == p2->sizeupvalues);
+
+    cmpCode(p1, p2);
+    cmpConstants(p1, p2);
+    cmpUpvalues(p1, p2);
+    cmpProtos(p1, p2);
+    cmpDebug(p1, p2);
+}
+
+void luat_luf_cmp(lua_State *L, const Proto* p1, const Proto *p2) {
+    if (p1 == NULL || p2 == NULL)
+        return;
+    cmpProto(p1, p2);
+}

+ 293 - 0
components/luf/luat_luf_dump.c

@@ -0,0 +1,293 @@
+/*
+** $Id: ldump.c,v 2.37.1.1 2017/04/19 17:20:42 roberto Exp $
+** save precompiled Lua chunks
+** See Copyright Notice in lua.h
+*/
+
+#include "luat_base.h"
+#include "luat_malloc.h"
+
+#define ldump_c
+#define LUA_CORE
+
+#include "lprefix.h"
+
+
+#include <stddef.h>
+
+#include "lua.h"
+
+#include "lobject.h"
+#include "lstate.h"
+#include "lundump.h"
+#include "lstring.h"
+
+#define LUAT_LOG_TAG "dump"
+#include "luat_log.h"
+
+static size_t fd_offset;
+
+typedef struct {
+  lua_State *L;
+  lua_Writer writer;
+  void *data;
+  int strip;
+  int status;
+} DumpState;
+
+
+/*
+** All high-level dumps go through DumpVector; you can change it to
+** change the endianness of the result
+*/
+#define DumpVector(v,n,D)	DumpBlock(v,(n)*sizeof((v)[0]),D)
+
+#define DumpLiteral(s,D)	DumpBlock(s, sizeof(s) - sizeof(char), D)
+
+#define fslen(s) (sizeof(TString) + tsslen(s) + 1)
+
+
+static void DumpBlock (const void *b, size_t size, DumpState *D) {
+  if (D->status == 0 && size > 0) {
+    lua_unlock(D->L);
+    D->status = (*D->writer)(D->L, b, size, D->data);
+    lua_lock(D->L);
+  }
+
+  fd_offset +=  size;
+}
+
+
+#define DumpVar(x,D)		DumpVector(&x,1,D);
+
+
+static void DumpByte (int y, DumpState *D) {
+  lu_byte x = (lu_byte)y;
+  DumpVar(x, D);
+}
+
+
+static void DumpInt (int x, DumpState *D) {
+  DumpVar(x, D);
+}
+
+
+static void DumpNumber (lua_Number x, DumpState *D) {
+  DumpVar(x, D);
+}
+
+
+static void DumpInteger (lua_Integer x, DumpState *D) {
+  DumpVar(x, D);
+}
+
+
+static void DumpString (const TString *s, DumpState *D) {
+  size_t size = 0;
+  if (s == NULL) {
+    DumpByte(0, D);
+    return;
+  }
+  DumpByte(1, D);
+  TString ts;
+  memcpy(&ts, s, sizeof(TString));
+  ts.next = NULL;
+  if (ts.tt == LUA_TSHRSTR) {
+    ts.u.hnext = NULL;
+    ts.u.lnglen = ts.shrlen;
+    ts.hash = (getstr(s), ts.shrlen, 0);
+    ts.extra = 1;
+    ts.tt = LUA_TLNGSTR;
+  }
+  //LLOGD("B>DumpString %d %d", fslen(s), fd_offset);
+  DumpBlock(&ts, sizeof(TString), D);
+  DumpBlock(getstr(s), tsslen(s)+1, D);
+  //LLOGD("A>DumpString %d %d", fslen(s), fd_offset);
+}
+
+static void DumpCode (const Proto *f, DumpState *D) {
+  DumpInt(f->sizecode, D);
+  DumpVector(f->code, f->sizecode, D);
+}
+
+
+static void DumpFunction(const Proto *f, TString *psource, DumpState *D);
+
+static void DumpConstants (const Proto *f, DumpState *D) {
+  int i;
+  int n = f->sizek;
+
+  //LLOGD("DumpConstants %d %d", n, n * sizeof(TValue));
+  DumpInt(n, D);
+
+  size_t init_offset = fd_offset + sizeof(TValue) * n + sizeof(int);
+  size_t i_offset = init_offset;
+  TValue tmp;
+  for (i = 0; i < n; i++) {
+    const TValue *o = &f->k[i];
+    switch (ttype(o)) {
+      case LUA_TSHRSTR:
+      case LUA_TLNGSTR:
+      // {
+        memcpy(&tmp, o, sizeof(TValue));
+        tmp.value_.gc = (void*)(init_offset);
+      //   o = &tmp;
+        init_offset += fslen(tsvalue(o)) + 1;
+      //   //break;
+      // }
+      default:
+        DumpBlock(o, sizeof(TValue), D);
+        break;
+    }
+  }
+  //LLOGD("DumpConstants1 Strings len %d %d %d %d", init_offset, i_offset, fd_offset, init_offset - i_offset);
+  DumpInt(init_offset - i_offset, D);
+  for (i = 0; i < n; i++) {
+    const TValue *o = &f->k[i];
+    switch (ttype(o)) {
+      case LUA_TSHRSTR:
+      case LUA_TLNGSTR:
+      {
+        DumpString(tsvalue(o), D);
+        break;
+      }
+    }
+  }
+  //LLOGD("DumpConstants2 Strings len %d %d %d %d", init_offset, i_offset, fd_offset, init_offset - i_offset);
+}
+
+
+static void DumpProtos (const Proto *f, DumpState *D) {
+  int i;
+  int n = f->sizep;
+  DumpInt(n, D);
+  for (i = 0; i < n; i++)
+    DumpFunction(f->p[i], f->source, D);
+}
+
+
+static void DumpUpvalues (const Proto *f, DumpState *D) {
+  int i, n = f->sizeupvalues;
+  DumpInt(n, D);
+  //LLOGD("LoadUpvalues %d %d", n, sizeof(Upvaldesc) * n);
+  size_t init_offset = fd_offset + sizeof(Upvaldesc) * f->sizeupvalues + sizeof(int);
+  size_t i_offset = init_offset;
+  Upvaldesc desc;
+  for (i = 0; i < n; i++) {
+    if (f->upvalues[i].name == NULL)
+      desc.name = NULL;
+    else
+      desc.name = (TString*)(init_offset);
+    desc.idx = f->upvalues[i].idx;
+    desc.instack = f->upvalues[i].instack;
+
+    DumpBlock(&desc, sizeof(Upvaldesc), D);
+
+    if (f->upvalues[i].name) {
+      init_offset += fslen(f->upvalues[i].name) + 1;
+      //LLOGD("DumpUpvalues name %s %d %d", getstr(f->upvalues[i].name), i_offset, init_offset);
+    }
+    else {
+      init_offset += 1;
+    }
+  }
+  
+  //LLOGD("DumpUpvalues Strings len %d %d %d %d", init_offset, i_offset, fd_offset, init_offset - i_offset);
+  DumpInt(init_offset - i_offset, D);
+  for (i = 0; i < n; i++) {
+    DumpString(f->upvalues[i].name, D);
+  }
+}
+
+
+static void DumpDebug (const Proto *f, DumpState *D) {
+  int i, n;
+  n = (D->strip) ? 0 : f->sizelineinfo;
+  DumpInt(n, D);
+  DumpVector(f->lineinfo, n, D);
+  n = (D->strip) ? 0 : f->sizelocvars;
+  DumpInt(n, D);
+  size_t init_offset = fd_offset + sizeof(LocVar) * f->sizelocvars + sizeof(int);
+  size_t i_offset = init_offset;
+  for (i = 0; i < n; i++) {
+    DumpInt(f->locvars[i].varname == NULL ? 0 : init_offset, D);
+    DumpInt(f->locvars[i].startpc, D);
+    DumpInt(f->locvars[i].endpc, D);
+
+    if (f->locvars[i].varname) {
+      init_offset += fslen(f->locvars[i].varname) + 1;
+    }
+    else {
+      init_offset += 1;
+    }
+  }
+  //LLOGD("DumpDebug Strings len %d %d %d %d", init_offset, i_offset, fd_offset, init_offset - i_offset);
+  DumpInt(init_offset - i_offset, D);
+  for (i = 0; i < n; i++) {
+    DumpString(f->locvars[i].varname, D);
+  }
+}
+
+
+static void DumpFunction (const Proto *f, TString *psource, DumpState *D) {
+  DumpString(f->source, D);
+
+  DumpInt(f->linedefined, D);
+  DumpInt(f->lastlinedefined, D);
+  DumpByte(f->numparams, D);
+  DumpByte(f->is_vararg, D);
+  DumpByte(f->maxstacksize, D);
+
+  // LLOGD("linedefined %d", f->linedefined);
+  // LLOGD("lastlinedefined %d", f->lastlinedefined);
+  // LLOGD("numparams %d", f->numparams);
+  // LLOGD("is_vararg %d", f->is_vararg);
+  // LLOGD("maxstacksize %d", f->maxstacksize);
+
+  DumpCode(f, D);
+  DumpConstants(f, D);
+  DumpUpvalues(f, D);
+  DumpProtos(f, D);
+  DumpDebug(f, D);
+}
+
+
+static void DumpHeader (DumpState *D) {
+  DumpLiteral(LUA_SIGNATURE, D);
+  DumpByte(LUAC_VERSION, D);
+  DumpByte(LUAC_FORMAT + 1, D);
+  DumpLiteral(LUAC_DATA, D);
+  DumpByte(sizeof(int), D);
+  DumpByte(sizeof(size_t), D);
+  DumpByte(sizeof(Instruction), D);
+  DumpByte(sizeof(lua_Integer), D);
+  DumpByte(sizeof(lua_Number), D);
+  DumpInteger(LUAC_INT, D);
+  DumpNumber(LUAC_NUM, D);
+}
+
+
+/*
+** dump Lua function as precompiled chunk
+*/
+int luf_dump(lua_State *L, const Proto *f, lua_Writer w, void *data,
+              int strip, int ptroffset) {
+  DumpState D;
+  D.L = L;
+  D.writer = w;
+  D.data = data;
+  D.strip = strip;
+  D.status = 0;
+
+  fd_offset = ptroffset + 1;
+
+  LLOGD("sizeof(Upvaldesc) %d", sizeof(Upvaldesc));
+  LLOGD("sizeof(LocVar) %d", sizeof(LocVar));
+
+  DumpHeader(&D);
+  DumpByte(f->sizeupvalues, &D);
+  // LLOGD("sizeupvalues %d", f->sizeupvalues);
+  DumpFunction(f, NULL, &D);
+  return D.status;
+}
+

+ 290 - 0
components/luf/luat_luf_undump.c

@@ -0,0 +1,290 @@
+/*
+** $Id: lundump.c,v 2.44.1.1 2017/04/19 17:20:42 roberto Exp $
+** load precompiled Lua chunks
+** See Copyright Notice in lua.h
+*/
+
+#define lundump_c
+#define LUA_CORE
+
+#include "lprefix.h"
+
+
+#include <string.h>
+
+#include "lua.h"
+
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lstring.h"
+#include "lundump.h"
+#include "lzio.h"
+
+#include "luat_base.h"
+#include "luat_fs.h"
+
+#define LUAT_LOG_TAG "undump"
+#include "luat_log.h"
+
+#define LUAT_UNDUMP_DEBUG 0
+
+// 未开启VFS就不能使用mmap
+#ifndef LUAT_USE_FS_VFS
+#ifdef LUAT_USE_MEMORY_OPTIMIZATION_CODE_MMAP
+#undef LUAT_USE_MEMORY_OPTIMIZATION_CODE_MMAP
+#endif
+#endif
+
+
+#if !defined(luai_verifycode)
+#define luai_verifycode(L,b,f)  /* empty */
+#endif
+
+typedef struct {
+  lua_State *L;
+  ZIO *Z;
+  const char *name;
+} LoadState;
+
+
+static l_noret error(LoadState *S, const char *why) {
+  luaO_pushfstring(S->L, "%s: %s precompiled chunk", S->name, why);
+  luaD_throw(S->L, LUA_ERRSYNTAX);
+}
+
+
+/*
+** All high-level loads go through LoadVector; you can change it to
+** adapt to the endianness of the input
+*/
+#define LoadVector(S,b,n)	LoadBlock(S,b,(n)*sizeof((b)[0]))
+
+static void LoadBlock (LoadState *S, void *b, size_t size) {
+  if (luaZ_read(S->Z, b, size) != 0)
+    error(S, "truncated");
+}
+
+static void* DistBlock (LoadState *S, size_t size) {
+  char b = 0;
+  void* p = S->Z->p;
+  for (size_t i = 0; i < size; i++)
+  {
+    if (luaZ_read(S->Z, &b, 1) != 0)
+      error(S, "truncated");
+  }
+  return p;
+}
+
+
+#define LoadVar(S,x)		LoadVector(S,&x,1)
+
+
+static lu_byte LoadByte (LoadState *S) {
+  lu_byte x;
+  LoadVar(S, x);
+  return x;
+}
+
+
+static int LoadInt (LoadState *S) {
+  int x;
+  LoadVar(S, x);
+  return x;
+}
+
+
+static lua_Number LoadNumber (LoadState *S) {
+  lua_Number x;
+  LoadVar(S, x);
+  return x;
+}
+
+
+static lua_Integer LoadInteger (LoadState *S) {
+  lua_Integer x;
+  LoadVar(S, x);
+  return x;
+}
+
+
+static TString *LoadString (LoadState *S, Proto *p) {
+  lu_byte t = LoadByte(S);
+  if (t == 0)
+    return NULL;
+  TString * ts = S->Z->p;
+  // LLOGD("LoadString >> %d %p", tsslen(ts), ts);
+  DistBlock(S, sizeof(TString) + tsslen(ts) + 1);
+  // LLOGD("LoadString >> %s", getstr(ts));
+  return ts;
+}
+
+static void LoadCode (LoadState *S, Proto *f) {
+  int n = LoadInt(S);
+  // LLOGD("LoadCode %d %d", n, sizeof(Instruction) * n);
+  f->sizecode = n;
+  f->code = DistBlock(S, sizeof(Instruction) * n);
+}
+
+
+static void LoadFunction(LoadState *S, Proto *f, TString *psource);
+
+
+static void LoadConstants (LoadState *S, Proto *f) {
+  int i;
+  int n = LoadInt(S);
+  // LLOGD("LoadConstants %d %d", n, sizeof(TValue) * n);
+  f->sizek = n;
+  // 指向常数数组
+  f->k = DistBlock(S, sizeof(TValue) * n);
+  // 跳过字符串段
+  
+  // LLOGD("1>>LoadConstants %02X %02X %02X %02X", *(S->Z->p), *(S->Z->p + 1), *(S->Z->p + 2), *(S->Z->p + 3));
+  n = LoadInt(S);
+  // LLOGD("LoadConstants skip Strings %d", n);
+  DistBlock(S, sizeof(char) * n);
+
+  // LLOGD("2>>LoadConstants %02X %02X %02X %02X", *(S->Z->p), *(S->Z->p + 1), *(S->Z->p + 2), *(S->Z->p + 3));
+}
+
+
+static void LoadProtos (LoadState *S, Proto *f) {
+  int i;
+  int n = LoadInt(S);
+  f->p = luaM_newvector(S->L, n, Proto *);
+  f->sizep = n;
+  for (i = 0; i < n; i++)
+    f->p[i] = NULL;
+  for (i = 0; i < n; i++) {
+    f->p[i] = luaF_newproto(S->L);
+    luaC_objbarrier(S->L, f, f->p[i]);
+    LoadFunction(S, f->p[i], f->source);
+  }
+  // LLOGD("LoadProtos %d %d", n, sizeof(Proto *) * n);
+}
+
+
+static void LoadUpvalues (LoadState *S, Proto *f) {
+  int i, n;
+  n = LoadInt(S);
+  f->sizeupvalues = n;
+  // LLOGD("LoadUpvalues %d %d", n, sizeof(Upvaldesc) * n);
+  f->upvalues = DistBlock(S, sizeof(Upvaldesc) * n);
+  // 跳过字符串段
+  n = LoadInt(S);
+  // LLOGD("LoadUpvalues skip Strings %d", n);
+  DistBlock(S, sizeof(char) * n);
+}
+
+
+static void LoadDebug (LoadState *S, Proto *f) {
+  int i, n;
+  
+  n = LoadInt(S);
+  f->sizelineinfo = n;
+  // LLOGD("LoadDebug sizelineinfo %d %d", n, sizeof(int) * n);
+  f->lineinfo = DistBlock(S, sizeof(int) * n);
+  
+  n = LoadInt(S);
+  f->sizelocvars = n;
+  // LLOGD("LoadDebug sizelocvars %d %d", n, sizeof(LocVar) * n);
+  f->locvars = DistBlock(S, sizeof(LocVar) * n);
+
+  n = LoadInt(S);
+  DistBlock(S, sizeof(char) * n);
+}
+
+
+static void LoadFunction (LoadState *S, Proto *f, TString *psource) {
+  //LLOGD(">> %02X %02X %02X %02X", *(S->Z->p), *(S->Z->p + 1), *(S->Z->p + 2), *(S->Z->p + 3));
+  f->source = LoadString(S, f);
+  if (f->source == NULL)  /* no source in dump? */
+    f->source = psource;  /* reuse parent's source */
+
+  // if (f->source)
+  //   LLOGI("%s %d source %s", __FILE__, __LINE__, getstr(f->source));
+  // else
+  //   LLOGD("no source ?");
+
+  f->linedefined = LoadInt(S);
+  f->lastlinedefined = LoadInt(S);
+  f->numparams = LoadByte(S);
+  f->is_vararg = LoadByte(S);
+  f->maxstacksize = LoadByte(S);
+
+  // LLOGD("linedefined %d", f->linedefined);
+  // LLOGD("lastlinedefined %d", f->lastlinedefined);
+  // LLOGD("numparams %d", f->numparams);
+  // LLOGD("is_vararg %d", f->is_vararg);
+  // LLOGD("maxstacksize %d", f->maxstacksize);
+
+  LoadCode(S, f);
+  LoadConstants(S, f);
+  LoadUpvalues(S, f);
+  LoadProtos(S, f);
+  LoadDebug(S, f);
+}
+
+
+static void checkliteral (LoadState *S, const char *s, const char *msg) {
+  char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */
+  size_t len = strlen(s);
+  LoadVector(S, buff, len);
+  if (memcmp(s, buff, len) != 0)
+    error(S, msg);
+}
+
+
+static void fchecksize (LoadState *S, size_t size, const char *tname) {
+  if (LoadByte(S) != size)
+    error(S, luaO_pushfstring(S->L, "%s size mismatch in", tname));
+}
+
+
+#define checksize(S,t)	fchecksize(S,sizeof(t),#t)
+
+static void checkHeader (LoadState *S) {
+  checkliteral(S, LUA_SIGNATURE + 1, "not a");  /* 1st char already checked */
+  if (LoadByte(S) != LUAC_VERSION)
+    error(S, "version mismatch in");
+  if (LoadByte(S) != 1)
+    error(S, "format mismatch in");
+  checkliteral(S, LUAC_DATA, "corrupted");
+  checksize(S, int);
+  checksize(S, size_t);
+  checksize(S, Instruction);
+  checksize(S, lua_Integer);
+  checksize(S, lua_Number);
+  if (LoadInteger(S) != LUAC_INT)
+    error(S, "endianness mismatch in");
+  if (LoadNumber(S) != LUAC_NUM)
+    error(S, "float format mismatch in");
+}
+
+extern void luat_os_print_heapinfo(const char* tag);
+
+/*
+** load precompiled chunk
+*/
+LClosure *luat_luf_undump(lua_State *L, ZIO *Z, const char *name) {
+  LoadState S;
+  LClosure *cl;
+
+  S.name = name;
+  S.L = L;
+  S.Z = Z;
+  checkHeader(&S);
+  cl = luaF_newLclosure(L, LoadByte(&S));
+  setclLvalue(L, L->top, cl);
+  luaD_inctop(L);
+  cl->p = luaF_newproto(L);
+  // LLOGD("sizeupvalues %d", cl->nupvalues);
+  luaC_objbarrier(L, cl, cl->p); // add by wendal, refer: https://github.com/lua/lua/commit/f5eb809d3f1da13683cd02184042e67228206205
+  LoadFunction(&S, cl->p, NULL);
+  lua_assert(cl->nupvalues == cl->p->sizeupvalues);
+  luai_verifycode(L, buff, cl->p);
+  return cl;
+}
+

+ 2 - 0
luat/include/luat_libs.h

@@ -103,4 +103,6 @@ LUAMOD_API int luaopen_pin( lua_State *L );
 LUAMOD_API int luaopen_dac( lua_State *L );
 LUAMOD_API int luaopen_otp( lua_State *L );
 
+LUAMOD_API int luaopen_luf( lua_State *L );
+
 #endif