Bootstrap

lua 调用文件中的函数调用_Lua设计与实现--函数篇

a6c4b001ee8a12d32ea7fdf7f81377a3.png

函数是任何语言设计里都不可或缺的一环,因为代码的执行几乎完全是依附在函数body里来完成的。本文主要从lua函数的C源码实现机制着手,来介绍lua函数的设计和实现特点。

本篇文章是Lua设计与实现专栏的第5篇,由于《Lua设计与实现》一书中,并没有对函数的实现做过多的阐述,因此本文主要是我自己根据lua5.3源码进行的一些总结,表述如有不当之处还望不吝指出。

1. 函数闭包

首先,所有的lua函数,都是一个函数闭包。函数闭包是目前主流语言几乎都支持的一个机制,它指的是一个内部结构,该结构存储了函数本身以及一个在词法上包围该函数的环境,该环境包含了函数外围作用域的局部变量,通常这些局部变量又称作upvalue。关于函数闭包的详情,可以参考维基百科的解释:https://en.wikipedia.org/wiki/Closure_(computer_programming)。

下图是lua5.3中函数闭包的定义:

5f37c1f3f94f7cff254fbe3954ae410d.png

可以看出lua中的函数闭包,分为了CClosure和LClosure两种类型,任意lua的函数调用栈中的函数,无非也就是这两种类型。其中CClosure是指使用Lua提供的lua_pushcclosure这个C Api加入到虚拟栈中的C函数,它是对LClosure的一种C模拟,因此本文主要着重讲解最纯粹的lua函数实现,也就是LClosure。

2. LClosure

2.1 LClosure结构

从第1节中的图中可以看出,LClosure主要由3部分构成:

  • ClosureHeader:跟GC相关的结构,因为函数与是参与GC的。
  • upvals:函数的upvalue指针列表,记录了该函数引用的所有upvals。正是由于该字段的存在,导致函数对upvalue的访问要快于从全局表_G中向下查找。函数对upvalue的访问,一般就2个步骤:(1)从closure的upvals数组中按索引号取出upvalue。(2)将upvalue加到luastate的stack中。源码如下
;