Rc-lang开发周记8 OOP之成员函数调用
本周做的内容不多,主要都是在做基础的成员调用相关工作(也只处理了成员函数,还没处理成员变量),然后就是修复一些问题添加了一些dump设施(目前做的并不好,等做好了可以单独拿一期讲一下),以及学习了解了一些其他语言相关的知识。
成员函数调用的过程
我们先来想一下这个过程大致是怎样的
- 被调用对象
非静态方法的时候首先成员函数要依赖于一个具体的对象,那么我们则需要在调用之前先将被调用对象的指针push到栈上 - 方法查找
根据对象的信息找到对应的类表,然后在类表中找到对应方法的地址(牵扯到继承的话也是在这里找父类的方法)
编译器的实现
AST
成员函数调用的AST是这样的
1 | class ClassMemberAccess |
其实这里当初设计想的是能够同时支持函数和成员变量的调用(也会加上无括号调用),但是我们现在认为它就是一个成员函数调用
Translate
1 | def on_class_member_access(access) |
再对比看一下旧的fun_call
1 | def on_fun_call(fun_call) |
没什么可讲的,非常直观
VM的实现
call的实现思路
之前的call的参数是一个类和一个函数名,完全可以说是用于静态函数调用的做法。(关于静态函数调用的实现我们之后再考虑)
上面提到非静态方法需要依赖于具体对象,因此我们需要先将被调用对象的指针push到栈上。而类信息可以从对象上获取,因此不需要call参数中的类型名。而获取指针则需要知道有多少个参数,因此我们需要传递进去参数的数量。这个做法也可以处理变长参数的情况
传递参数数量在ruby中也是类似的
1 | 0004 opt_mult <calldata!mid:*, argc:1, ARGS_SIMPLE>[CcCr] |
写到这里的时候我突然想到了一个问题,为什么要先push被调用对象指针?顾思考了一下,如果在push完所有参数之后再push被调用对象指针则前面的参数无法直接作用于被调用函数中。
代码实现
1 | FunInfo &method_search(const RcObject * const obj, const std::string &f) |
也很直观,先获取被调用对象,之后找到函数,开始处理调用栈,除了获取调用对象的部分和之前差不多。而栈帧会多保存一个当前的obj。在这里我新记录了调用栈的深度,便于调试
1 | void begin_call(size_t argc, size_t locals, size_t ret_addr, RcObject *this_ptr) |
关于set_pc
1 | void set_pc(size_t new_pc) |
新增了一个控制pc是否递增的成员,pc跳转的时候不应当继续递增pc,所以在各种跳转指令中都会直接使用set_pc
而递增的逻辑也相应的发生了变化
1 | void pc_increase() |
- 本文标题:Rc-lang开发周记8 OOP之成员函数调用
- 本文作者:Homura
- 创建时间:2022-02-12 10:45:49
- 本文链接:https://homura.live/2022/02/12/rc-lang-dev/rc-lang-dev-8/
- 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!