对于 MRI 1.9+ 和 Rubinius 实现,Ruby 源代码被编译成字节码,然后由 VM 解释该字节码。当使用解释器从命令行运行 Ruby 脚本时,我想知道这种机制的细节。
- 解释器是否首先编译脚本中所需的所有相关源文件,然后运行所有内容?还是它会执行一些代码,然后在需要时以一种懒惰的方式编译其他文件?
- 如果是后者(我怀疑),这个过程是通过文件还是通过代码块完成的?
- 在什么时候它停止执行字节码并再次运行编译过程?
- 这个过程与 MRI 和 Rubinius 有什么不同吗?
例如,如果我运行“ruby my_main_script.rb”,它需要 3 个其他 rb 源文件(并且这个文件本身没有任何要求),我想象的可能性是:
答:解释器解析 my_main_script.rb 和 3 个文件。在解析之后,它将所有 AST 树编译为字节码。然后它继续使用 VM 运行字节码。
B : Ruby 解析 my_main_script.rb 并将其编译为字节码。然后它运行字节码。当遇到对另一个文件中的方法的调用时,它首先解析并编译该文件并继续执行。如果是这种情况,我想详细了解一下。
C : Ruby 根据一些(对我来说不知道的)标准解析和编译来自 my_main_script.rb 的一些代码,它运行该字节码,然后在需要时解析和编译另一段。这个过程和“当需要时”条件检测方法对我来说是有趣的理解。
2016 年 3 月 30 日更新
我编写了这个小实验脚本来尝试检查 B 是否是正确答案:
class RubyVM
class InstructionSequence
class << self
alias :old_compile_file :compile_file
def compile_file(code, opt)
puts "Injecting code..."
old_compile_file(code, opt)
end
alias :old_compile :compile
def compile(code)
puts "Injecting code..."
old_compile(code)
end
end
end
end
require_relative 'say_hi'
'say_hi.rb' 只包含“puts 'hello'”这一行。如果 B 是正确答案,那么输出不应该如下吗?
Injecting code...
hello
它只是输出“你好”......