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

相关文章

kotlin中const 和val的区别及使用场景分析

《kotlin中const和val的区别及使用场景分析》在Kotlin中,const和val都是用来声明常量的,但它们的使用场景和功能有所不同,下面给大家介绍kotlin中const和val的区别,... 目录kotlin中const 和val的区别1. val:2. const:二 代码示例1 Java

将Mybatis升级为Mybatis-Plus的详细过程

《将Mybatis升级为Mybatis-Plus的详细过程》本文详细介绍了在若依管理系统(v3.8.8)中将MyBatis升级为MyBatis-Plus的过程,旨在提升开发效率,通过本文,开发者可实现... 目录说明流程增加依赖修改配置文件注释掉MyBATisConfig里面的Bean代码生成使用IDEA生

Java编译生成多个.class文件的原理和作用

《Java编译生成多个.class文件的原理和作用》作为一名经验丰富的开发者,在Java项目中执行编译后,可能会发现一个.java源文件有时会产生多个.class文件,从技术实现层面详细剖析这一现象... 目录一、内部类机制与.class文件生成成员内部类(常规内部类)局部内部类(方法内部类)匿名内部类二、

Go标准库常见错误分析和解决办法

《Go标准库常见错误分析和解决办法》Go语言的标准库为开发者提供了丰富且高效的工具,涵盖了从网络编程到文件操作等各个方面,然而,标准库虽好,使用不当却可能适得其反,正所谓工欲善其事,必先利其器,本文将... 目录1. 使用了错误的time.Duration2. time.After导致的内存泄漏3. jsO

Spring Boot 配置文件之类型、加载顺序与最佳实践记录

《SpringBoot配置文件之类型、加载顺序与最佳实践记录》SpringBoot的配置文件是灵活且强大的工具,通过合理的配置管理,可以让应用开发和部署更加高效,无论是简单的属性配置,还是复杂... 目录Spring Boot 配置文件详解一、Spring Boot 配置文件类型1.1 applicatio

C# WinForms存储过程操作数据库的实例讲解

《C#WinForms存储过程操作数据库的实例讲解》:本文主要介绍C#WinForms存储过程操作数据库的实例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、存储过程基础二、C# 调用流程1. 数据库连接配置2. 执行存储过程(增删改)3. 查询数据三、事务处

JSON Web Token在登陆中的使用过程

《JSONWebToken在登陆中的使用过程》:本文主要介绍JSONWebToken在登陆中的使用过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录JWT 介绍微服务架构中的 JWT 使用结合微服务网关的 JWT 验证1. 用户登录,生成 JWT2. 自定义过滤

java中使用POI生成Excel并导出过程

《java中使用POI生成Excel并导出过程》:本文主要介绍java中使用POI生成Excel并导出过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录需求说明及实现方式需求完成通用代码版本1版本2结果展示type参数为atype参数为b总结注:本文章中代码均为

Spring事务中@Transactional注解不生效的原因分析与解决

《Spring事务中@Transactional注解不生效的原因分析与解决》在Spring框架中,@Transactional注解是管理数据库事务的核心方式,本文将深入分析事务自调用的底层原理,解释为... 目录1. 引言2. 事务自调用问题重现2.1 示例代码2.2 问题现象3. 为什么事务自调用会失效3

找不到Anaconda prompt终端的原因分析及解决方案

《找不到Anacondaprompt终端的原因分析及解决方案》因为anaconda还没有初始化,在安装anaconda的过程中,有一行是否要添加anaconda到菜单目录中,由于没有勾选,导致没有菜... 目录问题原因问http://www.chinasem.cn题解决安装了 Anaconda 却找不到 An