lua源码分析之函数调用

本文基于lua5.1.4源码,探讨了lua函数调用的受保护调用和不受保护调用机制。受保护调用利用C堆栈保护状态,不受保护调用则使用CallInfo数组作为调用栈。luaD_pcall用于异常处理,luaD_precall和luaD_poscall分别负责函数调用和返回。C层函数调用非递归方式进行,C函数调用完整且独立。
摘要由CSDN通过智能技术生成

根据lua5.1.4版 的源码分析其函数调用的原理。

函数调用分为受保护调用和不受保护的调用。

lua函数的调用原理主要分为:

(1)受保护调用,用C层面的堆栈来保护和恢复状态

(2)不受保护的调用,使用自定义的栈存储结构CallInfo数组作为调用栈,修正数据栈,然后把字节码的执行位置跳转到被调用的函数开头,

lua 函数的return操作则做了相反的操作,恢复数据栈,弹出 CallInfo ,修改字节码的执行位置,恢复到原有的执行序列上。


 本文目录:

1、受保护的函数调用
2、不受保护的函数调用
(1)luaD_precall 环境保存
(2)luaD_poscall 环境恢复
3、函数调用使用实例
(1)不受保护的函数调用
(2)受保护的函数调用



本文内容:
1、受保护的函数调用
受保护的函数调用用C层面的堆栈来保护和恢复状态。
受保护的函数调用可以看成是一个 C 层面意义上完整的过程。在 lua 代码中,pcall是用函数而不是语
言机制完成的。受保护的函数调用一定在 C 层面进出了一次调用栈。它使用独立的一个内部 API luaD_pcall
来实现。公开API 仅需要对它做一些封装即可。
源代码lua5.14版   ldo.c :luaD_pcall(369行)
LUA_API int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc) {
  struct CallS c;
  int status;
  ptrdiff_t func;
  lua_lock(L);
  api_checknelems(L, nargs+1);//检查栈上元素个数
  checkresults(L, nargs, nresults);
  if (errfunc == 0)
    func = 0;
  else {
    StkId o = index2adr(L, errfunc);
    api_checkvalidindex(L, o);
    func = savestack(L, o);
  }
  c.func = L->top - (nargs+1);  /* function to be called */
  c.nresults = nresults;
  status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func);
  adjustresults(L, nresults);
  lua_unlock(L);
  return status;
}

int luaD_pcall (lua_State *L, Pfunc func, void *u,
                ptrdiff_t old_top, ptrdiff_t ef) {
  int status;
  unsigned short oldnCcalls = L->nCcalls;
  ptrdiff_t old_ci = saveci(L, L->ci);
  lu_byte old_allowhooks = L->allowhook;
  ptrdiff_t old_errfunc = L->errfunc;
  L->errfunc = ef;
  status = luaD_rawrunprotected(L, func, u);
  if (status != 0) {  /* an error occurred? */
    StkId oldtop = restorestack(L, old_top);
    luaF_close(L, oldtop);  /* close eventual pending closures */
    luaD_seterrorobj(L, status, oldtop);
    L->nCcalls = oldnCcalls;
    L->ci = restoreci(L, old_ci);
    L->base = L->ci->base;
    L->savedpc = L->ci->savedpc;
    L->allowhook = old_allowhooks;
    restore_stack_limit(L);
  }
  L->errfunc = old_errfunc;
  return status;
}



从这段代码我们可以看到pcall的处理模式:用C层面的堆栈来保护和恢复状态。


ci(调用栈)、allowhooks(钩子)、errfunc(函数错误时的栈索引)都保护在luaD_pcall的C堆栈上,一旦出错(luaD_rawrunprotected判断),就可以恢复lua的运行环境。

luaD_rawrunprotected没有正确返回是,需要根据old_top找到堆栈上的刚才调用的函数,给它做弹栈操作。因为luaD_rawrunprotected调用的是一个函数对象,
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值