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

相关文章

MySQL数据目录迁移的完整过程

《MySQL数据目录迁移的完整过程》文章详细介绍了将MySQL数据目录迁移到新硬盘的整个过程,包括新硬盘挂载、创建新的数据目录、迁移数据(推荐使用两遍rsync方案)、修改MySQL配置文件和重启验证... 目录1,新硬盘挂载(如果有的话)2,创建新的 mysql 数据目录3,迁移 MySQL 数据(推荐两

MyBatis-Plus逻辑删除实现过程

《MyBatis-Plus逻辑删除实现过程》本文介绍了MyBatis-Plus如何实现逻辑删除功能,包括自动填充字段、配置与实现步骤、常见应用场景,并展示了如何使用remove方法进行逻辑删除,逻辑删... 目录1. 逻辑删除的必要性编程1.1 逻辑删除的定义1.2 逻辑删php除的优点1.3 适用场景2.

Spring Boot Interceptor的原理、配置、顺序控制及与Filter的关键区别对比分析

《SpringBootInterceptor的原理、配置、顺序控制及与Filter的关键区别对比分析》本文主要介绍了SpringBoot中的拦截器(Interceptor)及其与过滤器(Filt... 目录前言一、核心功能二、拦截器的实现2.1 定义自定义拦截器2.2 注册拦截器三、多拦截器的执行顺序四、过

C++ scoped_ptr 和 unique_ptr对比分析

《C++scoped_ptr和unique_ptr对比分析》本文介绍了C++中的`scoped_ptr`和`unique_ptr`,详细比较了它们的特性、使用场景以及现代C++推荐的使用`uni... 目录1. scoped_ptr基本特性主要特点2. unique_ptr基本用法3. 主要区别对比4. u

JAVA SpringBoot集成Jasypt进行加密、解密的详细过程

《JAVASpringBoot集成Jasypt进行加密、解密的详细过程》文章详细介绍了如何在SpringBoot项目中集成Jasypt进行加密和解密,包括Jasypt简介、如何添加依赖、配置加密密钥... 目录Java (SpringBoot) 集成 Jasypt 进行加密、解密 - 详细教程一、Jasyp

Nginx内置变量应用场景分析

《Nginx内置变量应用场景分析》Nginx内置变量速查表,涵盖请求URI、客户端信息、服务器信息、文件路径、响应与性能等类别,这篇文章给大家介绍Nginx内置变量应用场景分析,感兴趣的朋友跟随小编一... 目录1. Nginx 内置变量速查表2. 核心变量详解与应用场景3. 实际应用举例4. 注意事项Ng

Java多种文件复制方式以及效率对比分析

《Java多种文件复制方式以及效率对比分析》本文总结了Java复制文件的多种方式,包括传统的字节流、字符流、NIO系列、第三方包中的FileUtils等,并提供了不同方式的效率比较,同时,还介绍了遍历... 目录1 背景2 概述3 遍历3.1listFiles()3.2list()3.3org.codeha

Java通过ServerSocket与Socket实现通信过程

《Java通过ServerSocket与Socket实现通信过程》本文介绍了Java中的ServerSocket和Socket类,详细讲解了它们的构造方法和使用场景,并通过一个简单的通信示例展示了如何... 目录1 ServerSocket2 Socket3 服务器端4 客户端5 运行结果6 设置超时总结1

springboot+mybatis一对多查询+懒加载实例

《springboot+mybatis一对多查询+懒加载实例》文章介绍了如何在SpringBoot和MyBatis中实现一对多查询的懒加载,通过配置MyBatis的`fetchType`属性,可以全局... 目录springboot+myBATis一对多查询+懒加载parent相关代码child 相关代码懒

Java编译错误java.lang.NoSuchFieldError的解决方案详析

《Java编译错误java.lang.NoSuchFieldError的解决方案详析》java.lang.NoSuchFieldError是Java中的一种运行时错误,:本文主要介绍Java编译错... 目录前言解决方案1. 统一JDK版本环境2. 优化maven-compiler-plugin配置3. 清