当前位置: 首页 > article >正文

LuaJit分析(七)LuaJit -b 命令分析

Luajit -b 命令用于生成字节码文件,通过之前对 -bl命令的分析:

luajit -bl 命令分析

可知,-b系统的命令都通过执行 bcsave.lua脚本来完成, luajit -b命令最终是执行bcsave.lua脚本中的 bcsave函数,bcsave函数代码如下:

local function bcsave(ctx, input, output)
  local f = readfile(input)
  local s = string.dump(f, ctx.strip)
  local t = ctx.type
  if not t then
    t = detecttype(output)
    ctx.type = t
  end
  if t == "raw" then
    bcsave_raw(output, s)
  else
    if not ctx.modname then ctx.modname = detectmodname(input) end
    if t == "obj" then
      bcsave_obj(ctx, output, s)
    else
      bcsave_c(ctx, output, s)
    end
  end
end

这通过关键的两个函数,来完成代码的转换:

local f = readfile(input)
local s = string.dump(f, ctx.strip)

由之前对luajit -b 命令的分析可知,readfile函数最终返回原型数据,如果是字节码文件,返回读取后的原型数据,否则进行源码分析再返回原型数据。接着通过string.dump返回完整的字节码文件,通过ctx.strip决定是否有调试信息,string.dump为库函数,位于lib_string.c中,实现如下:

LJLIB_CF(string_dump)
{
  GCfunc *fn = lj_lib_checkfunc(L, 1);
  int strip = L->base+1 < L->top && tvistruecond(L->base+1);
  SBuf *sb = lj_buf_tmp_(L);  /* Assumes lj_bcwrite() doesn't use tmpbuf. */
  L->top = L->base+1;
  if (!isluafunc(fn) || lj_bcwrite(L, funcproto(fn), writer_buf, sb, strip))
    lj_err_caller(L, LJ_ERR_STRDUMP);
  setstrV(L, L->top-1, lj_buf_str(L, sb));
  lj_gc_check(L);
  return 1;
}

最终是通过lj_bcwrite函数来完成字节码的生成,与lj_bcread对应。Lj_bcwriter位于lj_bcwriter.c文件中,代码如下:

int lj_bcwrite(lua_State *L, GCproto *pt, lua_Writer writer, void *data,
        int strip)
{
  BCWriteCtx ctx;
  int status;
  ctx.pt = pt;
  ctx.wfunc = writer;
  ctx.wdata = data;
  ctx.strip = strip;
  ctx.status = 0;
  lj_buf_init(L, &ctx.sb);
  status = lj_vm_cpcall(L, NULL, &ctx, cpwriter);
  if (status == 0) status = ctx.status;
  lj_buf_free(G(sbufL(&ctx.sb)), &ctx.sb);
  return status;
}

实质是调用 cpwriter函数,实现如下:

/* Protected callback for bytecode writer. */
static TValue *cpwriter(lua_State *L, lua_CFunction dummy, void *ud)
{
  BCWriteCtx *ctx = (BCWriteCtx *)ud;
  UNUSED(L); UNUSED(dummy);
  lj_buf_need(&ctx->sb, 1024);  /* Avoids resize for most prototypes. */
  bcwrite_header(ctx);
  bcwrite_proto(ctx, ctx->pt);
  bcwrite_footer(ctx);
  return NULL;
}

从这里就可以明显的看出,它通过分别生成头部、原型等数据来完成字节码的生成。

Bcsave函数中通过detecttype确定要保存的文件类型,代码如下:

local function detecttype(str)
  local ext = string.match(string.lower(str), "%.(%a+)$")
  return map_type[ext] or "raw"
end
local map_type = {
  raw = "raw", c = "c", h = "h", o = "obj", obj = "obj",
}

这里通过正则表达式匹配了输出文件后缀名,map_type中定义了几种后缀,除非特别指定了如obj等后缀名,否则都是返回raw.即执行bcsave_raw函数,实现如下:

local function bcsave_raw(output, s)
  local fp = savefile(output, "wb")
  bcsave_tail(fp, output, s)
end

这里最终将整个字节码文件写入到指定的文件名中。

总结:luajit -b生成字节码,实际上是调用 bcsave.lua脚本中的bcsave函数,该函数通过readfile函数(最终调用loadfile库函数)来完成lua脚本和字节码统一返回原型数据,并通过string.dump库函数生成完整的字节码文件。


http://www.kler.cn/news/283180.html

相关文章:

  • Linux基础 -- 网络工具之curl使用
  • 【JAVA】后端开发中的数据结构:基础知识与应用场景
  • 从 7000 余项目脱颖而出,飞轮科技《新一代实时分析数据仓库解决方案》荣获 HICOOL 2024 全球创业大赛二等奖
  • Oracle字符串聚合函数LISTAGG
  • AI创新,DataOps聚能 | 白鲸开源DTCC共话DataOps新篇章
  • 封装信号灯集相关API
  • 【JavaEE】深入浅出 Spring AOP:概念、实现与原理解析
  • HarmonyOS(AIP12 Beta5版)鸿蒙开发:选择条件渲染和显隐控制
  • 全志/RK安卓屏一体机:智能家居中控屏,支持鸿蒙国产化
  • Android studio设置国内镜像代理(HTTP Proxy)教程详解
  • PTA L1-027 出租
  • leedCode - - - 动态规划
  • 常见的深度学习模型总结
  • Elasticsearch7.15版本后新版本的接入
  • 三级_网络技术_54_应用题
  • FFmpeg 实现从设备端获取音视频流并通过RTMP推流
  • Prometheus+Grafana的安装和入门
  • 云上Oracle 数据库本地备份部署测试
  • Redis/ElaticSearch/kafka入门
  • 《经典图论算法》卡恩(Kahn)算法
  • 【电控笔记z27】相对位置控制(无前馈)
  • 【算法】递归、回溯、剪枝、dfs 算法题练习(N皇后、单词搜索、数独问题;C++)
  • Nginx: 反向代理和动静分离概述
  • 02. 开发前准备,Docker安装MySQL,Redis
  • SpringBoot优雅的封装不同研发环境下(环境隔离)RocketMq自动ack和手动ack
  • python实战二-筛选多个Excel中数据
  • 深度学习论文被评“创新性不足、工作量不够”怎么办?
  • Java毕业设计 基于SSM校园心理咨询服务平台
  • 应对Nginx负载均衡中的请求超时:策略与配置
  • HTTPS 通信时是对称加密还是非对称加密?