博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
tinypy源码分析(四)——函数调用的实现分析
阅读量:4294 次
发布时间:2019-05-27

本文共 2622 字,大约阅读时间需要 8 分钟。

一、函数的分类

在tinypy中,函数分三类

1. 内置函数(或者说C函数,builtin-function)
2. python函数,包括python的方法
3. 对象的实例化方法

二、函数的结构体

typedef struct tp_fnc_ {    int type;    struct _tp_fnc *info;    int ftype;    void *val;} tp_fnc_;typedef struct _tp_fnc {    int gci;    tp_obj self;    tp_obj globals;} _tp_fnc;

从结构体可以看出来一个函数包括如下成员变量

  • ftype:函数类型,0代表C函数,1代表python函数,2代表python对象的方法
  • val:脚本函数体的字节码
  • self:方法函数的自身对象
  • globals:模块的全局变量

三、函数调用的实现

1. 函数调用的入口

/* TP是一个宏,具体内容如下,实际上就是一个虚拟机的结构体,函数并没有用到。 */#define TP tp_vm *tpvoid _tp_call(TP,tp_obj *dest, tp_obj fnc, tp_obj params) {    /* 对象的实例化 */    if (fnc.type == TP_DICT) {        _tp_call(tp,dest,tp_get(tp,fnc,tp_string("__call__")),params);        return;    }    /* 调用C函数 */    if (fnc.type == TP_FNC && !(fnc.fnc.ftype&1)) {        *dest = _tp_tcall(tp,fnc);        tp_grey(tp,*dest);        return;    }    /* 调用Python函数 */    if (fnc.type == TP_FNC) {        tp_frame(tp,fnc.fnc.info->globals,(tp_code*)fnc.fnc.val,dest);        /* 方法调用的参数处理,在python中调用对象方法时self参数是不写的,实际上还是需要传给函数 */        if ((fnc.fnc.ftype&2)) {            tp->frames[tp->cur].regs[0] = params;            _tp_list_insert(tp,params.list.val,0,fnc.fnc.info->self);        } else {            tp->frames[tp->cur].regs[0] = params;        }        return;    }    tp_params_v(tp,1,fnc); tp_print(tp);    tp_raise(,"tp_call: %s is not callable",TP_CSTR(fnc));}.

2. C函数

C函数的处理比较简单,直接调用C的函数指针。

/* 执行C函数 */tp_obj _tp_dcall(TP,tp_obj fnc(TP)) {    return fnc(tp);}/* 调用C函数 */tp_obj _tp_tcall(TP,tp_obj fnc) {    /* 方法调用的参数处理,在python中调用对象方法时self参数是不写的,实际上还是需要传给函数 */    if (fnc.fnc.ftype&2) {        _tp_list_insert(tp,tp->params.list.val,0,fnc.fnc.info->self);    }    return _tp_dcall(tp,(tp_obj (*)(tp_vm *))fnc.fnc.val);}

3. python函数

这里需要给出函数栈的结构体

typedef struct tp_frame_ {    tp_code *codes;    tp_code *cur;    tp_code *jmp;    tp_obj *regs; /* 局部变量 */    tp_obj *ret_dest; /* 返回值指针 */    tp_obj fname;    tp_obj name;    tp_obj line;    tp_obj globals; /* 模块的全局变量 */    int lineno;    int cregs;} tp_frame_;

从代码中可以看出,python函数是新构建了一个调用栈,然后会返回到解释器循环进行执行。这里有一个问题,函数执行完了怎么返回呢?tinypy有一个返回机制。

void tp_return(TP, tp_obj v) {    tp_obj *dest = tp->frames[tp->cur].ret_dest;    if (dest) { *dest = v; tp_grey(tp,v); }    memset(tp->frames[tp->cur].regs,0,tp->frames[tp->cur].cregs*sizeof(tp_obj));    tp->cur -= 1;}

可以看出,虚拟机在执行return的时候给该函数栈的ret_dest指针的指向值赋值了,而在调用的时候就指定了ret_dest的值,这样返回的时候就已经赋值好了。

4. python对象实例化

对象的实例化实际上直接把字典当成函数来调用(在tinypy里类的本质就是字典,其实python也是这样),实例化的时候先从字典中取出__call__方法,然后调用它。这里有点类似于python的函数调用,在python中,func(args)等价于func.__call__(args)

具体如下:

>>> chr
>>> chr.__call__
>>> chr(0x30)'0'>>> chr.__call__(0x30)'0'

转载地址:http://vtuws.baihongyu.com/

你可能感兴趣的文章
Opengl——深度测试
查看>>
Opengl学习之——模板测试
查看>>
OpenGL学习之混合——Blending
查看>>
OpenGL学习之面剔除——Face Culling
查看>>
OpenGL学习之帧缓冲——FBO
查看>>
NDK 开发之 Android Studio 中使用 JNI
查看>>
Android 蓝牙开发 —— BLE
查看>>
Android 数据库 —— greeDAO
查看>>
Retrofit 2.0 学习第二弹——使用篇
查看>>
Retrofit2.0学习第一弹——准备篇
查看>>
数据库学习之 greenDAO 实战
查看>>
RecyclerView 全面使用及分析 - 基础篇(一)
查看>>
RecyclerView 全面使用及分析 - 使用细节(二)
查看>>
一篇文章介绍完 Drawable
查看>>
数据结构与算法学习-数组
查看>>
数据结构与算法学习-数组练习
查看>>
数据结构与算法学习-复杂度分析
查看>>
自定义 View - 基础
查看>>
数据结构与算法学习-栈
查看>>
数据结构与算法学习-队列
查看>>