LuaJit分析(八)LuaJit预编译库函数加载过程

2024-08-30 08:28

本文主要是介绍LuaJit分析(八)LuaJit预编译库函数加载过程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在luajit的pmain函数中,在执行命令行输入的参数之前,会执行如下函数:

luaL_openlibs(L);

该函数位于lib_init.c中,实现如下:

LUALIB_API void luaL_openlibs(lua_State *L)
{const luaL_Reg *lib;for (lib = lj_lib_load; lib->func; lib++) {lua_pushcfunction(L, lib->func);lua_pushstring(L, lib->name);lua_call(L, 1, 0);}luaL_findtable(L, LUA_REGISTRYINDEX, "_PRELOAD",sizeof(lj_lib_preload)/sizeof(lj_lib_preload[0])-1);for (lib = lj_lib_preload; lib->func; lib++) {lua_pushcfunction(L, lib->func);lua_setfield(L, -2, lib->name);}lua_pop(L, 1);
}

它通过编遍历lj_lib_load,加载所有的库函数,lj_lib_load定义如下:

static const luaL_Reg lj_lib_load[] = {{ "",     luaopen_base },{ LUA_LOADLIBNAME,  luaopen_package },{ LUA_TABLIBNAME, luaopen_table },{ LUA_IOLIBNAME,  luaopen_io },{ LUA_OSLIBNAME,  luaopen_os },{ LUA_STRLIBNAME, luaopen_string },{ LUA_MATHLIBNAME,  luaopen_math },{ LUA_DBLIBNAME,  luaopen_debug },{ LUA_BITLIBNAME, luaopen_bit },{ LUA_JITLIBNAME, luaopen_jit },{ LUA_FFILIBNAME, luaopen_ffi },{ NULL,   NULL }
};

这里定义了luajit中的库函数类型,第二个参数是定义的C函数,以luaopen_base为例,定义如下,位于lib_base.c中:

LUALIB_API int luaopen_base(lua_State *L)
{/* NOBARRIER: Table and value are the same. */GCtab *env = tabref(L->env);settabV(L, lj_tab_setstr(L, env, lj_str_newlit(L, "_G")), env);lua_pushliteral(L, LUA_VERSION);  /* top-3. */newproxy_weaktable(L);  /* top-2. */LJ_LIB_REG(L, "_G", base);LJ_LIB_REG(L, LUA_COLIBNAME, coroutine);return 2;
}

其中有一个宏定义 LJ_LIB_REG 用于注册库函数,宏定义如下:

#define LJ_LIB_REG(L, regname, name) \lj_lib_register(L, regname, lj_lib_init_##name, lj_lib_cf_##name)

从函数名即可看出是注册函数用,lj_lib_register位于lj_lib.c中,实现如下:

void lj_lib_register(lua_State *L, const char *libname,const uint8_t *p, const lua_CFunction *cf)
{GCtab *env = tabref(L->env);GCfunc *ofn = NULL;int ffid = *p++;BCIns *bcff = &L2GG(L)->bcff[*p++];GCtab *tab = lib_create_table(L, libname, *p++);ptrdiff_t tpos = L->top - L->base;/* Avoid barriers further down. */lj_gc_anybarriert(L, tab);tab->nomm = 0;for (;;) {uint32_t tag = *p++;MSize len = tag & LIBINIT_LENMASK;tag &= LIBINIT_TAGMASK;if (tag != LIBINIT_STRING) {const char *name;MSize nuv = (MSize)(L->top - L->base - tpos);GCfunc *fn = lj_func_newC(L, nuv, env);if (nuv) {L->top = L->base + tpos;memcpy(fn->c.upvalue, L->top, sizeof(TValue)*nuv);}fn->c.ffid = (uint8_t)(ffid++);name = (const char *)p;p += len;if (tag == LIBINIT_CF)setmref(fn->c.pc, &G(L)->bc_cfunc_int);elsesetmref(fn->c.pc, bcff++);if (tag == LIBINIT_ASM_)fn->c.f = ofn->c.f;  /* Copy handler from previous function. */elsefn->c.f = *cf++;  /* Get cf or handler from C function table. */if (len) {/* NOBARRIER: See above for common barrier. */setfuncV(L, lj_tab_setstr(L, tab, lj_str_new(L, name, len)), fn);}ofn = fn;} else {switch (tag | len) {case LIBINIT_LUA:p = lib_read_lfunc(L, p, tab);break;case LIBINIT_SET:L->top -= 2;if (tvisstr(L->top+1) && strV(L->top+1)->len == 0)env = tabV(L->top);else  /* NOBARRIER: See above for common barrier. */copyTV(L, lj_tab_set(L, tab, L->top+1), L->top);break;case LIBINIT_NUMBER:memcpy(&L->top->n, p, sizeof(double));L->top++;p += sizeof(double);break;case LIBINIT_COPY:copyTV(L, L->top, L->top - *p++);L->top++;break;case LIBINIT_LASTCL:setfuncV(L, L->top++, ofn);break;case LIBINIT_FFID:ffid++;break;case LIBINIT_END:return;default:setstrV(L, L->top++, lj_str_new(L, (const char *)p, len));p += len;break;}}}
}

其中下面这句:

switch (tag | len) {case LIBINIT_LUA:p = lib_read_lfunc(L, p, tab);break;

当是一个LUA的库函数时,使用lib_read_lfunc函数读取,即预编译的那么几个库函数,lib_read_lfunc函数实现如下:

static const uint8_t *lib_read_lfunc(lua_State *L, const uint8_t *p, GCtab *tab)
{int len = *p++;GCstr *name = lj_str_new(L, (const char *)p, len);LexState ls;GCproto *pt;GCfunc *fn;memset(&ls, 0, sizeof(ls));ls.L = L;ls.p = (const char *)(p+len);ls.pe = (const char *)~(uintptr_t)0;ls.c = -1;ls.level = (BCDUMP_F_STRIP|(LJ_BE*BCDUMP_F_BE));ls.chunkname = name;pt = lj_bcread_proto(&ls);pt->firstline = ~(BCLine)0;fn = lj_func_newL_empty(L, pt, tabref(L->env));/* NOBARRIER: See below for common barrier. */setfuncV(L, lj_tab_setstr(L, tab, name), fn);return (const uint8_t *)ls.p;
}

可以看到,该函数通过调用lj_bcread_proto读取luajit字节码的原型数据,接着使用原型创建一个新函数,然后保存该函数变量

这篇关于LuaJit分析(八)LuaJit预编译库函数加载过程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1120296

相关文章

IDEA编译报错“java: 常量字符串过长”的原因及解决方法

《IDEA编译报错“java:常量字符串过长”的原因及解决方法》今天在开发过程中,由于尝试将一个文件的Base64字符串设置为常量,结果导致IDEA编译的时候出现了如下报错java:常量字符串过长,... 目录一、问题描述二、问题原因2.1 理论角度2.2 源码角度三、解决方案解决方案①:StringBui

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

Springboot中分析SQL性能的两种方式详解

《Springboot中分析SQL性能的两种方式详解》文章介绍了SQL性能分析的两种方式:MyBatis-Plus性能分析插件和p6spy框架,MyBatis-Plus插件配置简单,适用于开发和测试环... 目录SQL性能分析的两种方式:功能介绍实现方式:实现步骤:SQL性能分析的两种方式:功能介绍记录

redis群集简单部署过程

《redis群集简单部署过程》文章介绍了Redis,一个高性能的键值存储系统,其支持多种数据结构和命令,它还讨论了Redis的服务器端架构、数据存储和获取、协议和命令、高可用性方案、缓存机制以及监控和... 目录Redis介绍1. 基本概念2. 服务器端3. 存储和获取数据4. 协议和命令5. 高可用性6.

最长公共子序列问题的深度分析与Java实现方式

《最长公共子序列问题的深度分析与Java实现方式》本文详细介绍了最长公共子序列(LCS)问题,包括其概念、暴力解法、动态规划解法,并提供了Java代码实现,暴力解法虽然简单,但在大数据处理中效率较低,... 目录最长公共子序列问题概述问题理解与示例分析暴力解法思路与示例代码动态规划解法DP 表的构建与意义动

关于Spring @Bean 相同加载顺序不同结果不同的问题记录

《关于Spring@Bean相同加载顺序不同结果不同的问题记录》本文主要探讨了在Spring5.1.3.RELEASE版本下,当有两个全注解类定义相同类型的Bean时,由于加载顺序不同,最终生成的... 目录问题说明测试输出1测试输出2@Bean注解的BeanDefiChina编程nition加入时机总结问题说明

PLsql Oracle 下载安装图文过程详解

《PLsqlOracle下载安装图文过程详解》PL/SQLDeveloper是一款用于开发Oracle数据库的集成开发环境,可以通过官网下载安装配置,并通过配置tnsnames.ora文件及环境变... 目录一、PL/SQL Developer 简介二、PL/SQL Developer 安装及配置详解1.下

在Java中使用ModelMapper简化Shapefile属性转JavaBean实战过程

《在Java中使用ModelMapper简化Shapefile属性转JavaBean实战过程》本文介绍了在Java中使用ModelMapper库简化Shapefile属性转JavaBean的过程,对比... 目录前言一、原始的处理办法1、使用Set方法来转换2、使用构造方法转换二、基于ModelMapper

springboot启动流程过程

《springboot启动流程过程》SpringBoot简化了Spring框架的使用,通过创建`SpringApplication`对象,判断应用类型并设置初始化器和监听器,在`run`方法中,读取配... 目录springboot启动流程springboot程序启动入口1.创建SpringApplicat

本地搭建DeepSeek-R1、WebUI的完整过程及访问

《本地搭建DeepSeek-R1、WebUI的完整过程及访问》:本文主要介绍本地搭建DeepSeek-R1、WebUI的完整过程及访问的相关资料,DeepSeek-R1是一个开源的人工智能平台,主... 目录背景       搭建准备基础概念搭建过程访问对话测试总结背景       最近几年,人工智能技术