InfoQ

新闻

Evan Phoenix谈Rubinius:虚拟机内幕面面观

作者 Werner Schuster 译者 高昂 发布于 2007年7月25日 上午1时41分

社区
Ruby
主题
开放源代码
标签
SmallTalk,
采访,
Rubinius,
RSpec

数周以前,Evan Phoenix加盟EngineYard,在那里他每天的工作中有一半时间花在Rubinius项目上。我们对Evan进行了一次采访,了解项目项目的进展和虚拟机的内部情况,并且(在采访的第二部分)探讨了最新的一些特性的实现方式。

其它的Ruby实现,比如说JRuby、XRuby、Gardens Point Ruby.NET、IronRuby,要么针对已有的虚拟机,要么和Ruby 1.x一样使用C语言编写,而Rubinius另辟蹊径,它从Smalltalk虚拟机处获得灵感,尤其是在Squeak Smalltalk之中Squeak是用它自己Smalltalk的一个子集写成,这个子集名叫Slang,它基本上是使用了Smalltalk语法的C语言代码,并加入了一定的限制。Rubinius的目标之一,就是使用这种方式贯穿项目始终,它使用的语言名叫Garnet(以前被称为“Cuby”),目前仍处于开发阶段。Evan就目前进展解释说:

这仍然是我计划在近期要做的事情,而不是今后的。之前,我们遇到了许多需要处理的问题,而且我们还没有时间回来着手Garnet(Cuby的新名字)上的工作。目前我们尚未找到什么特别的问题,但我相信我们会发现的。

第一眼看过去Garnet语言和Ruby长得没什么区别,但是里面一些东西代表的语义进行了一些修改。

举例来说,在Garnet语言中,“d = c.to_ref”这样的代码看似调用了c对象的to_ref方法,但实际上Garnet会把这段代码翻译成“d = &c”这样的C代码。我们可以把它看作一个非常先进的C预处理器,试图尽可能将自己和对应的C语言构造映射起来。我们的想法就是写出看起来像 Ruby的代码,而行为则和C语言类似。

目前,虚拟机的基础部分是使用C语言编写的,也采取源自Smalltalk的方式。Evan就此解释了基础实现(primitives)的本意:

他们是可以在Ruby中调用的小块C语言代码,用来实现Ruby无法完成的功能。一个很好的例子是给一个对象分配 (内存)。在系统后端,与垃圾回收机制交互,为特定对象的分配准备出足够的空间。这样的操作在Ruby之中无法实现,这种操作方式只存在于系统的最底层, 也就是所谓的基础实现。

Rubinius的基础实现与Smalltalk的基础实现机制很相近。如果方法指定了原生(primitive)的操作号,当方法被执行时,则会调用原 生(primitive)操作而不是常规的Ruby代码。如果primitive操作执行失败(primitive自身报告执行已经失败),那么Ruby 代码就会作为后备的行为被执行。Ruby代码可以使用如抛出包含操作失败原因的异常的方式,将参数转换并再次进行尝试,或者做一些其他的操作。

为了展现它实际运行的方式,这里附一段rubinius的primitive操作代码作为例子:

  def fixnum_size(_ = fixnum)
<<-CODE
stack_push(I2N(sizeof(int)));
CODE
end

接着Evan给我们解释了一遍代码的运行过程:

primitives和指令使用一系列有趣的格式来保持其操作的简单性。所有的操作都是Ruby方法,而程序体是 包含C代码的字符串。在编译的时候,这些文件被执行,然后某些代码会调用每一个方法,收集C的代码并且在其它C代码的#include部分声明。这样做的 主要原因是基础实现和指令在C语言的声明中可以包装为一个大的switch表达式,如果使用手工的方式来完成无疑将会是非常痛苦的。

而且,它 提供给我们一些程序预处理的能力。例如,在这里(代码示例),你看见我们在定义参数的原生类型(primitive)fixnum_size的时候使用了 一些小的技巧。首先,代码的关键是在调用的方法的代码执行前会自动注册C语言代码段“POP(self, FIXNUM_P)”。调用并且输出C语言代码的方法将会正确的声明和写入这些代码。用这样的形式,我们可以方便基础实现(primitives)的编 写。

但是我声明,目前并非所有基础实现(primitives)都使用了这样的形式。很快,我们将会进行审查,将所有的实现都统一使用这种形式。

可以看出,随着可用的Garnet越来越多之后,Ruby和C语言之间的界限会变得模糊,原有的界限将在今后发生改变。对于更深一层的软件栈来说,标准的类库将使用Ruby来实现。

目前,虚拟机的核心(实际上就是操作码)和基础实现(primitives)都是使用C语言编写的。基础实现(primitives)是我想在Garnet中实现的第一个特性。两者的垃圾回收机制也都同样是使用C语言编写(虽然他们所占的的代码量很少)。

除了这些,所有的一切都是用Ruby实现的。所有解释器都可以解析命令行参数字符串(就像rubinius -d -v这样开启调试和警告信息)。所有代码的运行时环境可以轻松的操作(修改),因为它们也都是Ruby的。
Rubinius虚拟机在过去一段时间内发展很快。为了保持发展的势头并吸引更多的开发者,在更多的开发者开始贡献代码还有更多的测试人员开始加入到Rubinius项目中之后,他们需要得到更多项目相关的信息。
目前,IRC讨论组#rubinius是得到信息的最好渠道(当然,直接读源代码也是非常有效的方式)。讨论组的一些历史记录信息可以在线找到。Evan详细的阐述了增加项目透明度的计划:
我们尽力去保持整个过程的透明度。目前,项目的IRC讨论组是最主要的交流方式,并且我们设法将IRC的记录整合到站点http://rubini.us之上。同时我们鼓励用户使用我们在http://rubini.us上的论坛来反馈问题。论坛拥有RSS的feed读取方式,并且大多数的开发者可以通过订阅RSS来加入讨论(尽管我不得不承认,有些功能还有待真正实现)。

关于如何使得项目更加透明,通过各种方式提出的建议,我都非常欢迎。我们可以一直考虑满足用户提出的规格。一旦我们拥有一个完全规范的套件,其余的功能将很容易的添加在其中。

感兴趣的读者可以继续关注这段采访的下一个章节,下个章节探讨了Rubinius调试器、垃圾回收、ObjectSpace和线程方面的一些最新特性的实现方式。

查看英文原文:Evan Phoenix on Rubinius - VM Internals Interview

深度内容

和Google互补的搜索引擎Wolfram|Alpha

Wolfram|Alpha与Google究竟是什么关系,Wolfram|Alpha自己是如何定位的?Wolfram|Alaph在多大程度上是语义网搜索呢?InfoQ中文站就等等这些问题采访了Wolfram研究公司中国区商务经理王翔。

SOA契约成熟度模型

本文说明了所推荐的契约版本管理设计策略是如何与SOA成熟度模型发生联系的。文章目的是为实现版本管理和可组合性提供一个路线图。

数据服务简介

Vijay Narayanan在这篇文章中对数据服务的几个方面进行了介绍,它们都是SOA实践者和数据架构师感兴趣的内容。本文对数据服务的几个方面进行了介绍,包括需求定义,基本原理和好处、范围、开发以及消费模式。

分块云计算

在本文中,Jimmy Nilsson描述了一种他在过去数年间观察到的一种正在缓慢成长的架构风格,他把这种风格称为“分块云计算”。

豆瓣网技术架构变迁

罗马不是一天建成的,豆瓣的技术架构也是随着用户规模的增长一直在持续变化中。在本次演讲中,豆瓣的首席架构师洪强宁将与大家一起分享从上线时的单台服务器架构开始一直到现在的豆瓣架构变迁历程。

融合思想:深入探索S#arp架构

Billy McCafferty展示了S#arp架构,它在ASP.NET MVC框架的基础上,荟萃了当今的最佳实践,应用在ASP.NET Web应用程序的架构设计中。

王雷谈开源以及新兴市场计划

中国作为新兴市场中的新兴市场,是Sun在美国之外实施SSE(SUN Startup Essentials)项目重点关注的地区。在QCon Beijing 2009期间,InfoQ中文站有幸对此项目的负责人王雷先生进行了采访,探讨了关于开源、新兴市场、SSE等话题。

使用HTML5构建下一代的Web Form

HTML5 是由 WHATWG发起的,最开始的名称叫做Web Application 1.0,而后这个标准吸纳了Web Forms 2.0的标准,并一同被W3C组织所采用,合并成为下一代的HTML5标准。