看到 Ruby 的底层了吗?

发布于 2024-12-21 22:47:22 字数 326 浏览 2 评论 0原文

最近,我一直在学习《编程语言语用学》第三版,以了解有关语言底层工作原理的更多信息,并且通过查看由真正基本的 GCC 编译的 C 代码生成的程序集,我获得了很多收获。我开始对 C 系列的静态语言更加熟悉,并且我也想开始研究解释型语言。

Ruby 作为我最喜欢的脚本语言,将是一个很好的候选者。我认为从 MRI 开始进行学习是可以的,并弄清楚所有扫描/解析/语义分析/绑定/范围界定和其他魔法到底是如何在幕后发生的。

这是否在任何地方都有详细描述,或者我有什么方法可以深入研究它,比如通过反汇编已编译的程序?我还没有对解释语言进行太多挖掘,所以就 MRI 而言,我不太知道从哪里开始。

谢谢!

I've been recently working my way through Programming Language Pragmatics 3rd ed to learn more about how languages work underneath, and I've gotten a lot of mileage out of looking at the assembly produced by really basic GCC-compiled C code. I'm starting to get more comfortable with static languages from the C family, and I would like to begin looking into interpreted languages as well.

Ruby, being my favorite scripting language, would be an excellent candidate for this. I think it'd be OK to start with MRI for learning purposes, and figure out how exactly all of the scanning/parsing/semantic analysis/binding/scoping and other magic happens behind the scenes.

Is this described in detail anywhere, or is there any way for me to dig into it, like say, with the disassembly of a compiled program? I haven't done much digging with interpreted languages, so I wouldn't quite know where to start as far as MRI is concerned.

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

西瓜 2024-12-28 22:47:22

您可以使用 RubyVM::InstructionSequence 查看任意 Ruby 源代码的 YARV 字节码

。这是一个简单的示例:

class Greeter
  def initialize(name)
    @name = name
  end
  def greet!
    puts @name
  end
end

Greeter.new("Charlie").greet!

然后您可以编译它并反汇编它:

puts RubyVM::InstructionSequence.compile(src).disassemble

并获得如下输出:

== disasm: <RubyVM::InstructionSequence:<compiled>@<compiled>>==========
0000 trace            1                                               (   1)
0002 putspecialobject 3
0004 putnil           
0005 defineclass      :Greeter, <class:Greeter>, 3
0009 pop              
0010 trace            1                                               (  10)
0012 getinlinecache   19, <ic:0>
0015 getconstant      :Greeter
0017 setinlinecache   <ic:0>
0019 putstring        "Charlie"
0021 send             :new, 1, nil, 0, <ic:1>
0027 send             :greet!, 0, nil, 0, <ic:2>
0033 leave            
== disasm: <RubyVM::InstructionSequence:<class:Greeter>@<compiled>>=====
0000 trace            2                                               (   1)
0002 trace            1                                               (   2)
0004 putspecialobject 1
0006 putspecialobject 2
0008 putobject        :initialize
0010 putiseq          initialize
0012 send             :"core#define_method", 3, nil, 0, <ic:0>
0018 pop              
0019 trace            1                                               (   5)
0021 putspecialobject 1
0023 putspecialobject 2
0025 putobject        :greet!
0027 putiseq          greet!
0029 send             :"core#define_method", 3, nil, 0, <ic:1>
0035 trace            4                                               (   8)
0037 leave                                                            (   5)
== disasm: <RubyVM::InstructionSequence:initialize@<compiled>>==========
local table (size: 2, argc: 1 [opts: 0, rest: -1, post: 0, block: -1] s1)
[ 2] name<Arg>  
0000 trace            8                                               (   2)
0002 trace            1                                               (   3)
0004 getlocal         name
0006 dup              
0007 setinstancevariable :@name, <ic:0>
0010 trace            16                                              (   4)
0012 leave                                                            (   3)
== disasm: <RubyVM::InstructionSequence:greet!@<compiled>>==============
0000 trace            8                                               (   5)
0002 trace            1                                               (   6)
0004 putnil           
0005 getinstancevariable :@name, <ic:0>
0008 send             :puts, 1, nil, 8, <ic:1>
0014 trace            16                                              (   7)
0016 leave                                                            (   6)

You can peek at the YARV bytecode of any bit of Ruby source code with RubyVM::InstructionSequence

Here's a quick example:

class Greeter
  def initialize(name)
    @name = name
  end
  def greet!
    puts @name
  end
end

Greeter.new("Charlie").greet!

Then you can compile it and disassemble it:

puts RubyVM::InstructionSequence.compile(src).disassemble

And get some output like this:

== disasm: <RubyVM::InstructionSequence:<compiled>@<compiled>>==========
0000 trace            1                                               (   1)
0002 putspecialobject 3
0004 putnil           
0005 defineclass      :Greeter, <class:Greeter>, 3
0009 pop              
0010 trace            1                                               (  10)
0012 getinlinecache   19, <ic:0>
0015 getconstant      :Greeter
0017 setinlinecache   <ic:0>
0019 putstring        "Charlie"
0021 send             :new, 1, nil, 0, <ic:1>
0027 send             :greet!, 0, nil, 0, <ic:2>
0033 leave            
== disasm: <RubyVM::InstructionSequence:<class:Greeter>@<compiled>>=====
0000 trace            2                                               (   1)
0002 trace            1                                               (   2)
0004 putspecialobject 1
0006 putspecialobject 2
0008 putobject        :initialize
0010 putiseq          initialize
0012 send             :"core#define_method", 3, nil, 0, <ic:0>
0018 pop              
0019 trace            1                                               (   5)
0021 putspecialobject 1
0023 putspecialobject 2
0025 putobject        :greet!
0027 putiseq          greet!
0029 send             :"core#define_method", 3, nil, 0, <ic:1>
0035 trace            4                                               (   8)
0037 leave                                                            (   5)
== disasm: <RubyVM::InstructionSequence:initialize@<compiled>>==========
local table (size: 2, argc: 1 [opts: 0, rest: -1, post: 0, block: -1] s1)
[ 2] name<Arg>  
0000 trace            8                                               (   2)
0002 trace            1                                               (   3)
0004 getlocal         name
0006 dup              
0007 setinstancevariable :@name, <ic:0>
0010 trace            16                                              (   4)
0012 leave                                                            (   3)
== disasm: <RubyVM::InstructionSequence:greet!@<compiled>>==============
0000 trace            8                                               (   5)
0002 trace            1                                               (   6)
0004 putnil           
0005 getinstancevariable :@name, <ic:0>
0008 send             :puts, 1, nil, 8, <ic:1>
0014 trace            16                                              (   7)
0016 leave                                                            (   6)
难得心□动 2024-12-28 22:47:22

Ruby 本身是用 C 编写的,因此可能值得看一下代码。 https://github.com/ruby/ruby

我还推荐 Patrick Farley 关于方法调度的文章。 http://www.klankboomklang.com/2007/09/14/method-调度/

Ruby itself is written in C, so it might be worth taking a look at the code. https://github.com/ruby/ruby

I also recommend Patrick Farley's article about method dispatch. http://www.klankboomklang.com/2007/09/14/method-dispatch/

深爱成瘾 2024-12-28 22:47:22

有一本一本日本书描述了 MRI 1.7.3 的内部工作原理,称为 Ruby Hacking指导。 部分英文翻译可用。

尽管翻译并不完整并且这本书基于旧版本的 ruby​​,但我仍然认为它是一个极好的资源。本书中涵盖的许多内容可能仍然与当前的 Ruby 版本相关,例如对象的结构、实例变量如何存储、方法查找如何完成等等。

这是一本非常有趣的读物。不过,您必须注意版本之间的差异。始终将 ruby 源代码放在手边。

There is a Japanese book that describes inner workings of MRI 1.7.3 called the Ruby Hacking Guide. A partial English translation is available.

Even though the translation is not complete and the book was based on an older version of ruby, I still find it to be a superb resource. Many things covered by the book are probably still relevant in current ruby versions, such as the structure of objects, how instance variables are stored, how method lookup is done and so on.

It is a very interesting read. You have to watch out for the differences between versions, though. Always keep the ruby source code at hand.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文