lua的类型,lua_State,函数调用

类型

lua中的数据可以这样分为两位:值类型和引用类型。引用类型创建时需要从堆上分配内存,复制时只需要复制指针,分配的内存由GC负责维护生命期。

所有lua类型都用一个union来表示:

/*
** Union of all Lua values
*/
typedef union {GCObject *gc;void *p; /* lightuserdata */lua_Number n;int b; /* boolean */
} Value;

引用类型用一个gc指针来引用,其他值类型都直接保存在Value中。

每个引用类型的开头都是CommonHeader;,所以都可强转成GCheader*使用:

/*
** Common Header for all collectable objects (in macro form, to be
** included in other objects)
*/
#define CommonHeader GCObject *next; lu_byte tt; lu_byte marked/*
** Common header in struct form
*/
typedef struct {CommonHeader;
} GCheader;/*
** Union of all collectable objects
*/
union GCObject {GCheader gch;TString ts;Udata u;Closure cl;Table h;Proto p;UpVal uv;lua_State th; /* thread */
};

为了区分Value中存放的数据类型,再额外绑定一个类型字段:

/*
** Tagged Values
*/
typedef struct {Value value;int tt;
} TValue;

lua_State、数据栈、调用栈

lua_State表示一个线程/协程(后面线程与协程通用)的状态,lua_newstate用于创建主线程:

/*
** Main thread combines a thread state and the global state
*/
typedef struct {lua_State l;global_State g;
} LG;LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {int i;lua_State *L;global_State *g;void *l = (*f)(ud, NULL, 0, state_size(LG));if (l == NULL) return NULL;...

用lua_newstate创建主线程的时候,同时也创建了一个global_State,所有的线程共享这个global_State,luaE_newthread用于创建协程:

lua_State *luaE_newthread (lua_State *L) {lua_State *L1 = tostate(luaM_malloc(L, state_size(lua_State)));luaC_link(L, obj2gco(L1), LUA_TTHREAD);preinit_state(L1, G(L));...

lua的数据栈是一个TValue数组,代码中用StkId类型用来指代对TValue的引用:

typedef TValue *StkId; /* index to stack elements */

调用栈放在CallInfo数组中,CallInfo保存着正在调用的函数的运行状态:

/*
** informations about a call
*/
typedef struct {StkId base; /* base for this function */StkId func; /* function index in the stack */StkId top; /* top for this function */const Instruction *savedpc;int nresults; /* expected number of results from this function */int tailcalls; /* number of tail calls lost under this entry */
} CallInfo;

正在调用的函数一定存在于数据栈上,由func引用正在调用的函数对象。
[base,top)指示了正在调用的函数的堆栈在数据栈上的范围。
为什么没有堆栈的当前位置?lua_State的top就是正在调用的函数的堆栈的位置啊。

/*
** `per thread' state
*/
struct lua_State {CommonHeader;lu_byte status;StkId top; /* first free slot in the stack */StkId base; /* base of current function */global_State *l_G;CallInfo *ci; /* call info for current function */const Instruction *savedpc; /* `savedpc' of current function */StkId stack_last; /* last free slot in the stack */StkId stack; /* stack base */CallInfo *last_ci; /* last free slot in the ci array*/CallInfo *base_ci; /* array of CallInfo's */int stacksize;int size_ci; /* size of array `base_ci' */...

[stack,stack_last],[base_ci,last_ci]分别是数据栈数组和调用栈数组,stacksize,size_ci分别是两个数组的大小,在需要的时候它们会进行增长。
ci是当前正在调用的函数的运行状态,base是该函数的栈底指针。

lua_newstate和luaE_newthread都调用了stack_init来初始化堆栈:

static void stack_init (lua_State *L1, lua_State *L) {/* initialize CallInfo array */L1->base_ci = luaM_newvector(L, BASIC_CI_SIZE, CallInfo);L1->ci = L1->base_ci;L1->size_ci = BASIC_CI_SIZE;L1->last_ci = L1->base_ci + L1->size_ci - 1;/* initialize stack array */L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, TValue);L1->stacksize = BASIC_STACK_SIZE + EXTRA_STACK;L1->top = L1->stack;L1->stack_last = L1->stack + (L1->stacksize - EXTRA_STACK) - 1;/* initialize first ci */L1->ci->func = L1->top;setnilvalue(L1->top++); /* `function' entry for this `ci' */L1->base = L1->ci->base = L1->top;L1->ci->top = L1->top + LUA_MINSTACK;
}

可以看到first ci只是占了个位置,它的func只是一个空值。

c代码中的函数调用

包括lua闭包,和c闭包

lua_call,lua_pcall都可以调lua或c函数,需要准备好函数在栈上
参数作为c闭包的upvalues,用起来略麻烦些

lua_cpcall,用一个lightuserdata作为参数

luaD_call 最终都是调它

luaD_pcall,oldtop是干嘛用的

协程

TODO

lua代码中的函数调用

TODO

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/7307.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

IT养生知识之:子午流注

《子午流注口诀》 肺寅大卯胃辰宫, 脾巳心午小未中, 申膀酉肾心包戌, 亥焦子胆丑肝通。 何为子午流注? 子午流注是中医圣贤发现的一种规律,中医认为人体中十二条经脉对应着每日的十二个时辰,由于时辰在…

【Osek网络管理测试】[TG3_TC5]等待总线睡眠状态_1

🙋‍♂️ 【Osek网络管理测试】系列💁‍♂️点击跳转 文章目录 1.环境搭建2.测试目的3.测试步骤4.预期结果5.测试结果 1.环境搭建 硬件:VN1630 软件:CANoe 2.测试目的 验证DUT在满足进入等待睡眠状态的条件时是否进入该状态 …

C#算法之堆排序算法

算法释义:堆排序算法的基本原理,其实就是利用二叉堆的数据结构,通过构建一个最大堆,然后将堆顶元素(最大值)与末尾元素交换,接着缩小堆的大小并重新调整堆,直到堆中只剩下一个元素。…

WP Rocket插件下载:加速您的WordPress网站,提升用户体验

在互联网速度决定用户体验的今天,一个快速加载的网站对于吸引和保留访问者至关重要。WP Rocket插件,作为一款专为WordPress设计的高性能缓存插件,提供了一套完整的解决方案,帮助您优化网站性能,提升用户体验。 [WP Ro…

Django实验(远程访问+图片显示)

众所周知,Python除了不能生孩子什么都会。Python也是可以做web服务的。 Python做web有一个重点优势是:做一个快速的AI Demo。 第一步:安装一个版本5.0以上django 第二步:构建咱们的Django工程,我取名为BBQ django-adm…

flask 前后台文件多张图片api;AIGC streamlit、gradio多图片页面展示

1、flask 前后台文件多张图片api send_file 传递zip: send_file(zip_data, mimetype=‘application/zip’, as_attachment=True, download_name=‘images.zip’) from flask import Flask, Response, request,send_file from PIL import Image import torch import io from …

【copilot 使用指南 - @workspace】

为什么需要workspace 默认情况下,copilot只能分析当前文件中的代码内容, 那么如何让copliot 跨文件分析,分析整个项目,分析整个代码目录下的代码,就要用到workspace,举例 :假设如下代码 index…

如何使用ArcGIS Pro进行选房分析

无论是研究城市规划布局还是寻找理想的住房,都需要综合考虑购物、医疗、教育和休闲等多方面因素,此时我们的GIS软件就可以派上用场了,这里为大家介绍一下如何使用 ArcGIS Pro 进行选房分析,希望能对你有所帮助。 数据来源 教程所…

解决mac出现npm install 卡在“sill idealTree buildDeps“的问题

问题出现场景: 在新建一个项目尝试npm install命令时,一直卡在“sill idealTree buildDeps“ 尝试过的无效解决方案包括: 切换/关闭梯子重启更换网络更换npm源更新删除 package.json 最终解决方案: 引起问题的原因是MacOS设置中…

sqlx执行案例

SQLx简介 SQLx是Rust语言中的一个异步SQL数据库连接库,它支持多种数据库,如PostgreSQL、MySQL和SQLite。SQLx提供了简单的API和异步执行查询的能力,使得Rust程序员可以轻松地与数据库交互1。 本章节以PostgreSQL为例。 目录结构 cargo.tom…

uniapp生成二维码(uQRCode)与自定义绘制样式与内容

二维码生成使用了一款基于Javascript环境开发的插件 uQRCode ,它不仅适用于uniapp,也适用于所有Javascript运行环境的前端应用和Node.js。 uQRCode 插件地址:https://ext.dcloud.net.cn/plugin?id1287 目录 1、npm安装 2、通过import引…

华为热题总结(1)

200,924,739,179,1,20,93 200. 岛屿数量 中等 给你一个由 1(陆地)和 0(水)组成的的二维网格,请你计算网格中岛屿的数量。 岛屿总是被水包围&a…

Springboot集成Mybatispuls操作mysql数据库-03

MyBatis-Plus(简称MP)是一个MyBatis的增强工具,在MyBatis的基础上只做增强而不做改变。它支持所有MyBatis原生的特性,因此引入MyBatis-Plus不会对现有的MyBatis构架产生任何影响。MyBatis-Plus旨在简化开发、提高效率,…

土壤重金属含量分布、Cd镉含量、Cr、Pb、Cu、Zn、As和Hg、土壤采样点、土壤类型分布

土壤是人类赖以生存和发展的重要资源之一,也是陆地生态系统重要的组成部分。近年来, 随着我国城市化进程加快,矿产资源开发、金属加工冶炼、化工生产、污水灌溉以及不合理的化肥农药施用等因素导致重金属在农田土壤中不断富集。重金属作为土壤环境中一种具有潜在危害…

练习题(2024/5/6)

1路径总和 II 给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。 叶子节点 是指没有子节点的节点。 示例 1: 输入:root [5,4,8,11,null,13,4,7,2,null,null,5,1], target…

vue3 axios数据请求封装

准备工作 vue3jsvite 首先确认package.json中有axios 如果没有 运行 npm install axios 安装axios 成功后在package.json文件会显示。 第一步 创建app.js、request.js 两个文件在同级目录下即可 api.js import instance from "./request"; const api_name "&qu…

前端小案例

案例一: 在 onLoad 函数中,首先通过 wx.getStorageSync(userInfo) 获取用户信息,如果用户信息存在,则从中提取用户ID,并将其存储在页面数据中,以便后续使用。如果用户信息不存在,你可以根据实际需求进行相…

linux安装 mysql

环境:centOS8 一、安装 1 安装wget库 sudo yum -y install wget 2. 安装 mysql 换yum源 亲测成功!!!!!! 换yum源 1.下载对应版本的repo文件 wget -O CentOS-Base.repo http://mirrors…

watch侦听器

在 Vue.js 中,watch 侦听器用于观察和响应 Vue 实例上的数据变动。当你想在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。与计算属性不同,watch 侦听器允许你执行更复杂的逻辑,包括异步操作,并且只有当观…

C#编程模式之外观模式

创作背景:给位伙伴,五一小长假结束,我们继续对C#编程之路进行探索。本文将继续编程模式的研究,主要介绍外观模式。外观模式也称为门面模式,是一种结构型设计模式,它的目的是为子系统中的一组接口提供一个统…