Lua学习与交流——Lua函数调用过程(转载)

【本文内容转自:http://blog.chinaunix.net/uid-52437-id-2108797.html

第3章 lua中函数调用的方法

         前面,以及分析了lua中定义一个函数的方法,现在总结如下:

1、  将函数名作为局部变量存在局部变量表里,并在栈上开辟一个寄存器空间,在运行期,将新建一个closure,并存在已保留的寄存器里;

2、  将在语法解析阶段新建的FuncState结构体保存在其父函数的局部函数定义数组里。

        

         现在,就要分析,当lua进行函数调用的时候,是怎么调用的呢?

        

         当分析到这里,对于lua生成中间码的过程就比较熟悉了。关键是生成的中间码必须要和lua虚拟机的执行联系在一起。所以,对于这里分析的函数调用,要结合lua虚拟机的执行一起来分析。

        

         上篇文章对生成局部函数中间码做了简单的介绍。这里知道,当lua发现一个新定义的函数的时候,会生成OP_CLOSURE指令。那么,lua虚拟机执行到OP_CLOSURE后怎么执行呢?

         在此之前,先说在lua解析代码完了以后,会做那些善后之事呢?

         前面说过,lua会把一个代码文件当作是一个函数解析执行。在解析期间,它会率先生成一个FuncState的结构,作为最外面的函数。但这是解析时做的事情,运行期间,是不会有FuncState这个东西出现的。在运行期间,是由一个个叫CallInfo的数据结果的,它指的是当前运行的函数。

         那么,在解析代码以后,是怎么转入运行的呢?

        

         秘密就在lua做的一些善后工作。在f_parser()函数里,解析完了后,最外层的那个FuncState是有的,其实用的是FuncState里的函数头Proto。然后,lua会新建一个闭包(Closure),通过函数luaF_newLclosure(),并把刚才解析代码生成的Proto保存在这个闭包里,cl->l.p=tf,新建完了这个Closure,lua会把它压入栈。然后就转入运行期进行运行。也就是进入lua_pcall()函数执行。而lua_pcall()这个函数就是假设在当前栈顶有一个Closure,然后执行这个Closure。具体说来如下:

         lua_pcall()经过一系列调用,最后通过调用luaD_precall()来执行。

         这个luaD_precall()做什么呢?如果这个函数是C函数,那么就直接执行,如果是lua函数,这个函数便字如其人了,就是做执行前的准备。

         首先,这个函数就会在L的ci数组里申请一项空槽。也就是说,L里有一个CallInfo数组,代表每个执行的函数。然后用现在的Closure初始化这个CallInfo。并且将这个函数的栈底标志在栈顶,也就是那个Closure压入栈的地方。

         接着,就是转入lua的虚拟机的运行了。也就是函数luaV_execute()。

 

         这时,如果遇到OP_CALL的时候,也就是在lua代码中有函数调用的时候,就会直接用luaD_precall(),将要执行的函数加载到L->ci中去,然后重新开始luaV_execute()虚拟机执行。

        

         与调用函数相对应的,怎么从一个函数里返回呢?

 

         也就是,当lua虚拟机遇到OP_RETUREN的时候,该如何操作呢?

 

         lua会通过一个函数来实现从子函数到调用它的函数里的一个转变:luaD_poscall()。在这个函数里,lua主要做的事情就是,因为L->ci是个链,代表当前运行函数的嵌套调用链,调用过的函数会被直接丢弃。于是,只要L->ci--,也就是让当前ci指针退一格,指向前面调用它的函数,即可返回。另外,要将栈底位置和pc值恢复,这些恢复都很简单。

 

         但是,最主要的一件事,就是如果这个函数里含有upvalue怎么办?这个留在明天再研究一下。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值