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.mfbz.cn/a/597273.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++类细节,面试题02

文章目录 2. 虚函数vs纯虚函数3. 重写vs重载vs隐藏3.1. 为什么C可以重载? 4. 类变量vs实例变量5. 类方法及其特点6. 空类vs空结构体6.1. 八个默认函数:6.2. 为什么空类占用1字节 7. const作用7.1 指针常量vs常量指针vs常量指针常量 8. 接口vs抽象类9. 浅…

CSS选择器、字体文本属性、三大特性、盒子模型等

目录 导入css简介HTML的局限性CSS-网页美化CSS语法规范CSS代码风格 选择器基础选择器复合选择器 CSS字体属性字体系列font-family字体大小font-size字体粗细font-weight文字样式font-style字体复合属性font CSS文本属性文本颜色color对齐文本text-align装饰文本text-decoration…

Hive数据模型

Hive数据模型 1. 表(Table): 表是数据库中的基本组成单位,用于存储数据。它由一系列的行和列组成,每行代表一个记录,每列代表一种属性或字段。创建表时,你需要定义列的数据类型、约束和索引等信…

水电站LCU屏技术参数,应用案例解析

项目咨询请点击:设备自动化技术商务咨询 水电站LCU屏简介: 水电站LCU屏一般布置在水电站设备附近,对电站设备的运行工况进行实时监视和控制,是电站计算机监控系统的较底层控制部分。水电站一般会配置一个公用LCU屏柜,…

linux学习笔记——硬盘原理以及linux中的sector与block

在计算机硬盘中,最小的存储单位叫做扇区sector,0.5kb,多个连续扇区组合在一起形成了块block,最小的块包含8个扇区,4kb 我们可以在linux中印证 创建一个新的文件2.txt,查看文件大小为0k 在文件中添加字符后…

2022——蓝桥杯十三届2022国赛大学B组真题

问题分析 看到这个问题的同学很容易想到用十层循环暴力计算&#xff0c;反正是道填空题&#xff0c;一直算总能算得出来的&#xff0c;还有些同学可能觉得十层循环太恐怖了&#xff0c;写成回溯更简洁一点。像下面这样 #include <bits/stdc.h> using namespace std; in…

大厂Java面试题:MyBatis是如何进行分页的?分页插件的实现原理是什么?

大家好&#xff0c;我是王有志。 今天给大家带来的是一道来自京东的关于 MyBatis 实现分页功能的面试题&#xff1a;MyBatis是如何进行分页的&#xff1f;分页插件的实现原理是什么&#xff1f;通常&#xff0c;分页的方式可以分为两种&#xff1a; 逻辑&#xff08;内存&…

PON网络和HFC网络

目录 1.概念 2.分类 3.重点 1.概念 PON PON是一种典型的无源光纤网络&#xff0c;是一种点到多点的无源光纤接入技术。 是指 (光配线网中) 不含有任何电子器件及电子电源&#xff0c;ODN全部由光分路器 (Splitter) 等无源器件组成&#xff0c;不需要贵重的有源电子设备。一个…

Java | Leetcode Java题解之第73题矩阵置零

题目&#xff1a; 题解&#xff1a; class Solution {public void setZeroes(int[][] matrix) {int m matrix.length, n matrix[0].length;boolean flagCol0 false;for (int i 0; i < m; i) {if (matrix[i][0] 0) {flagCol0 true;}for (int j 1; j < n; j) {if (…

【1小时掌握速通深度学习面试8】生成模型-中

目录 28.DBN与DBM 有什么区别? 29.VAE如何控制生成图像的类别? 30.如何修改VAE的损失函数&#xff0c;使得隐藏层的编码是相互解耦的? 31.自回归方法如何应用在生成模型上? 32.原始 VAE存在哪些问题? 有哪些改进方式? 33.如何将VAE与GAN 进行结合&#xff1f; 34.…

【LeetCode】环形队列实现

目录 前言1. 环形队列概念2. 循环队列实现设计3. 功能实现3.1 定义3.2 初始化3.3 判断队列是否为空3.4 判断队列是否为满3.5 入栈3.6 出栈3.7 获取队头数据3.8 获取队尾数据3.9 销毁 4. 总结5. 完整通过代码 前言 之前我们学习环形链表相关问题&#xff0c;现在我们来看看环形…

抖音爆火的QQ价格评估前端源码

最近抖音很火直播给别人测qq价值多少&#xff0c;这个源码只有前端&#xff0c; 包含激活码验证页&#xff0c;评估页 源码免费下载地址抄笔记 (chaobiji.cn)

流畅的python-学习笔记_符合python风格的对象

对象表示形式 查看对象说明&#xff0c;可以通过__repr__和__str__方法&#xff0c;前者主要用于开发者&#xff0c;后者主要用于用户&#xff0c;这两个方法分别对内置函数repr和str函数提供支持 向量类 备选构造方法 classmethod和staticmethod staticmethod用的不是特别…

力扣每日一练(螺旋矩阵)

54. 螺旋矩阵 - 力扣&#xff08;LeetCode&#xff09; 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 输出&#xff1a;[1,2,3,6,9,8,7,4,…

数据库提权

1.此时实验需要用到的软件&#xff1a; &#xff08;1&#xff09;phpStudy该程序包集成最新的ApachePHPMySQL phpMyAdminZendOptimizer,一次性安装,无须配置即可使用,是非常方便、好用的PHP调试环境.该程序不仅包括PHP调试环境,还包括了开发工具、开发手册等.总之学习PHP只需…

STM32——TIMER(定时器)篇

技术笔记&#xff01; 1. 定时器概述&#xff08;了解&#xff09; 1.1 软件定时器原理 使用纯软件&#xff08;CPU死等&#xff09;的方式实现定时&#xff08;延时&#xff09;功能 缺点&#xff1a;1. 延时不准确 2. CPU死等。 1.2 定时器定时原理 1.…

在Codelab对llama3做Lora Fine tune微调

Unsloth 高效微调大模型的工具&#xff0c;通过Unsloth微调Llama3, Mistral, Gemma 速度提升2-5倍&#xff0c;内存减少70%&#xff01; Codelab 创建一个jupyter notebook 选择 T4 GPU 安装Fine tune 相关的lib %%capture import torch major_version, minor_version torch…

等保测评—Linux-CentOS标准范例截图

密码输入错误无法登录 用户账户情况包含root、guanli、shenji 查看审计用户权限 身份鉴别&#xff1a; cat /etc/passwd&#xff0c;核查用户名和 UID&#xff0c;是否存在同样的用户名和 UID cat /etc/shadow&#xff0c;查看文件中各用户名状态 &#xff0c; 核查密码一栏为…

day1Qt作业

#include "mywidget.h"MyWidget::MyWidget(QWidget *parent): QWidget(parent) {this->resize(540,415);//窗口大小this->setFixedSize(540,415);//固定窗口大小this->setWindowTitle("QQ");//标题this->setWindowIcon(QIcon("E:\\hqyjap…

获取转转数据,研究完转转请求,tx在算法方面很友好。

本篇文章仅供学习讨论。 文章中涉及到的代码、实例&#xff0c;仅是个人日常学习研究的部分成果。 如有不当&#xff0c;请联系删除。 在研究完阿里的算法以后&#xff08;其实很难说研究完&#xff0c;还有很多内容没有研究透&#xff0c;只能说暂时告一段落&#xff09;&…
最新文章