博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Ruby 2.x 源代码学习:解释器概述
阅读量:6240 次
发布时间:2019-06-22

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

前言

本文作为这一系列的开篇,简单介绍了 Ruby 解释器运行轨迹,为后续详细分析 Ruby 源代码提供一个纲领。

之所以选择学习 Ruby 源代码主要是出于:

  • Ruby 源代码主要使用 C 语言编写,不像 JVM 使用 C++,要看懂 JVM 首先得有相当的 C++ 功底

  • Ruby 解释器(CRuby)目前还没有实现 JIT,代码流程比较简单,清晰,利于学习一门语言以及虚拟机实现

  • 相比于其它的动态脚本语言(Python),Ruby 的面向对象实现应该是比较纯正的,比较符合 Me 的口味

本系列的灵感来源于《Ruby原理剖析》这本著作,让一个 Java 技术栈的~从业者~有兴趣和勇气向大家分享这一系列^_-

  • 所有的伟大,源于一个勇敢的开始,把源代码下载下来,编译,调试/运行!

解释器入口

代码片段省略掉 (万能的!!!)宏定义 和一些无关主干的细节(下同)

# main.cint main(int argc, char **argv) {    ruby_init();    ruby_run_node(ruby_options(argc, argv));}

main 方法很干净简洁,不绕来绕去

  • 初始化(ruby_init)

  • 处理命令行参数,词法分析,语法分析(生成 AST),字节码生成(ruby_options)

  • 解释执行(ruby_run_node)

虚拟机初始化

ruby_init 函数调用栈

ruby_init    ruby_setup        ruby_init_stack        Init_BareVM        Init_heap        Init_vm_objects        rb_call_inits        ruby_prog_init        GET_VM()->running = 1

从名字能够大概猜出各个函数的功能,这里比较有意思的是 rb_call_inits 函数

它调用 Init_XXX 函数初始化 Ruby 内置的 Class(Array, Hash .etc)

#define CALL(n) {void Init_##n(void); Init_##n();}void rb_call_inits(void) {    CALL(Method);    // other calls    CALL(Array);    // other calls}

词法分析,语法分析,中间代码生成

ruby_options 函数调用栈

ruby_options    ruby_process_options        process_options            rb_iseq_new_main                rb_iseq_new_with_opt                    iseq_alloc                    prepare_iseq_build                    rb_iseq_compile_node                        iseq_setup                    iseq_translate                        iseq_optimize                        iseq_insns_unification                        iseq_set_sequence_stackcaching                        iseq_set_sequence

以 iseq(instruction sequence)开头的函数基本上都是和 字节码处理相关的,几个重要的函数:

  • rb_iseq_new_main: 将 ruby 脚本加工成 rb_iseq_struct

  • iseq_optimize: 字节码优化

  • iseq_set_sequence: 将双向链表链接的字节码指令结构体编码为数组形式线性存储,方便虚拟机取指令

字节码解释执行

字节码定义

Ruby 源代码包下有个 insns.def 的 文件,在编译 Ruby 的时候会将该文件转化成 vm.inc 文件

下面是 insns.def 文件的一个片段,定义了 getlocal 指令,该指令用于从本地变量表中获取一个本地变量

/**  @c variable  @e Get local variable (pointed by `idx' and `level').     'level' indicates the nesting depth from the current block.  @j level, idx で指定されたローカル変数の値をスタックに置く。     level はブロックのネストレベルで、何段上かを示す。 */DEFINE_INSNgetlocal(lindex_t idx, rb_num_t level)()(VALUE val){    int i, lev = (int)level;    const VALUE *ep = GET_EP();    /* optimized insns generated for level == (0|1) in defs/opt_operand.def */    for (i = 0; i < lev; i++) {    ep = GET_PREV_EP(ep);    }    val = *(ep - idx);}

解释执行

编译 Ruby 的时候可以在 vm_opts.h 头文件中打开 OPT_CALL_THREADED_CODE 开关

ruby_run_node 调用栈

ruby_run_node    ruby_exec_node        ruby_exec_internal            rb_iseq_eval_main                vm_exec                    vm_exec_core

我们直接来看 vm_exec_core 函数,和想象中的差不多,一个 while 循环

vm_exec_core(rb_thread_t *th, VALUE initial){    register rb_control_frame_t *reg_cfp = th->cfp;    while (1) {    reg_cfp = ((rb_insn_func_t) (*GET_PC()))(th, reg_cfp);    if (UNLIKELY(reg_cfp == 0)) {        break;    }    }    if (th->retval != Qundef) {    VALUE ret = th->retval;    th->retval = Qundef;    return ret;    }    else {    VALUE err = th->errinfo;    th->errinfo = Qnil;    return err;    }}

rb_control_frame_t 是对函数调用栈的抽象

rb_thread_t 是对线程的抽象
rb_insn_func_t 是 ruby 字节码指令处理函数,每条指令都对应一个处理函数
GET_PC 方法用于获取当前指令指针

字节码处理函数

vm_exec.h 中定义了几个用于申明字节码处理函数的 宏定义

#define LABEL(x)  insn_func_##x#define INSN_ENTRY(insn) \  static rb_control_frame_t * \    FUNC_FASTCALL(LABEL(insn))(rb_thread_t *th, rb_control_frame_t *reg_cfp) {#define END_INSN(insn) return reg_cfp;}

结合上文提到的 vm.inc,下面的函数声明

INSN_ENTRY(getlocal)

会被展开成

static rb_control_frame_t* insn_func_getlocal(rb_thread_t *th, rb_control_frame_t *reg_cfp)

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

你可能感兴趣的文章
python---基本数据结构
查看>>
Windows下JDK,Tomcat,Eclipse安装配置
查看>>
vue的checkbox或多选的select的代码例子
查看>>
es6-Set和Map数据结构
查看>>
使用ffmpeg将录屏文件转换成gif
查看>>
作业七 总结
查看>>
Oracle的静默安装 升级和卸载 参考规范
查看>>
高效存储过程分页
查看>>
电脑用U盘启动
查看>>
Web漏洞扫描
查看>>
使用xtrabackup做数据库的增量备份
查看>>
“程序已停止工作”问题的解决方法,停止解决方法
查看>>
[c++] 幂法求特征向量
查看>>
WEB项目(B/S系统)打包安装(总结篇)
查看>>
Cartographer源码阅读(8):imu_tracker
查看>>
U盘,移动硬盘显示显示需要格式化怎么修复
查看>>
JVM基础和调优(一)
查看>>
ICommand in Silverlight
查看>>
复选框、单选按钮、下拉列表的定义
查看>>
webdynpro的select_option示例
查看>>