Reputation: 7855
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!
Upvotes: 3
Views: 760
Reputation: 17030
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.
Upvotes: 1
Reputation:
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)
Upvotes: 4
Reputation: 13926
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/
Upvotes: 2