Log In
Or create an account ->
Imperial Library
Home
About
News
Upload
Forum
Help
Login/SignUp
Index
Ruby Under a Microscope: An Illustrated Guide to Ruby Internals
Dedication
Advance Praise for Ruby under a Microscope
About the Author
Foreword
Acknowledgments
Introduction
Who This Book Is For
Using Ruby to Test Itself
Which Implementation of Ruby?
Overview
1. Tokenization and Parsing
Tokens: The Words That Make Up the Ruby Language
Experiment 1-1: Using Ripper to Tokenize Different Ruby Scripts
Parsing: How Ruby Understands Your Code
Understanding the LALR Parse Algorithm
Some Actual Ruby Grammar Rules
Experiment 1-2: Using Ripper to Parse Different Ruby Scripts
Summary
2. Compilation
No Compiler for Ruby 1.8
Ruby 1.9 and 2.0 Introduce a Compiler
How Ruby Compiles a Simple Script
Compiling a Call to a Block
Experiment 2-1: Displaying YARV Instructions
The Local Table
Compiling Optional Arguments
Compiling Keyword Arguments
Experiment 2-2: Displaying the Local Table
Summary
3. How Ruby Executes Your Code
YARV’s Internal Stack and Your Ruby Stack
Stepping Through How Ruby Executes a Simple Script
Executing a Call to a Block
Experiment 3-1: Benchmarking Ruby 2.0 and Ruby 1.9 vs. Ruby 1.8
Local and Dynamic Access of Ruby Variables
Local Variable Access
Method Arguments Are Treated Like Local Variables
Dynamic Variable Access
Experiment 3-2: Exploring Special Variables
Summary
4. Control Structures and Method Dispatch
How Ruby Executes an if Statement
Jumping from One Scope to Another
Catch Tables
Other Uses for Catch Tables
Experiment 4-1: Testing How Ruby Implements for Loops Internally
The send Instruction: Ruby’s Most Complex Control Structure
Method Lookup and Method Dispatch
Eleven Types of Ruby Methods
Calling Normal Ruby Methods
Preparing Arguments for Normal Ruby Methods
Calling Built-In Ruby Methods
Calling attr_reader and attr_writer
Method Dispatch Optimizes attr_reader and attr_writer
Experiment 4-2: Exploring How Ruby Implements Keyword Arguments
Summary
5. Objects and Classes
Inside a Ruby Object
Inspecting klass and ivptr
Visualizing Two Instances of One Class
Generic Objects
Simple Ruby Values Don’t Require a Structure at All
Do Generic Objects Have Instance Variables?
Where Does Ruby Save Instance Variables for Generic Objects?
Experiment 5-1: How Long Does It Take to Save a New Instance Variable?
What’s Inside the RClass Structure?
Inheritance
Class Instance Variables vs. Class Variables
Getting and Setting Class Variables
Constants
The Actual RClass Structure
Experiment 5-2: Where Does Ruby Save Class Methods?
Summary
6. Method Lookup and Constant Lookup
How Ruby Implements Modules
Modules Are Classes
Including a Module into a Class
Ruby’s Method Lookup Algorithm
A Method Lookup Example
The Method Lookup Algorithm in Action
Multiple Inheritance in Ruby
The Global Method Cache
The Inline Method Cache
Clearing Ruby’s Method Caches
Including Two Modules into One Class
Including One Module into Another
A Module#prepend Example
How Ruby Implements Module#prepend
Experiment 6-1: Modifying a Module After Including It
Classes See Methods Added to a Module Later
Classes Don’t See Submodules Included Later
Included Classes Share the Method Table with the Original Module
Constant Lookup
Finding a Constant in a Superclass
How Does Ruby Find a Constant in the Parent Namespace?
Lexical Scope in Ruby
Creating a Constant for a New Class or Module
Finding a Constant in the Parent Namespace Using Lexical Scope
Ruby’s Constant Lookup Algorithm
Experiment 6-2: Which Constant Will Ruby Find First?
Ruby’s Actual Constant Lookup Algorithm
Summary
7. The Hash Table: The Workhorse of Ruby Internals
Hash Tables in Ruby
Saving a Value in a Hash Table
Retrieving a Value from a Hash Table
Experiment 7-1: Retrieving a Value from Hashes of Varying Sizes
How Hash Tables Expand to Accommodate More Values
Hash Collisions
Rehashing Entries
Experiment 7-2: Inserting One New Element into Hashes of Varying Sizes
How Ruby Implements Hash Functions
Experiment 7-3: Using Objects as Keys in a Hash
Hash Optimization in Ruby 2.0
Summary
8. How Ruby Borrowed a Decades-Old Idea from Lisp
Blocks: Closures in Ruby
Stepping Through How Ruby Calls a Block
Borrowing an Idea from 1975
Experiment 8-1: Which Is Faster: A while Loop or Passing a Block to each?
Lambdas and Procs: Treating a Function as a First-Class Citizen
Stack vs. Heap Memory
A Closer Look at How Ruby Saves a String Value
How Ruby Creates a Lambda
How Ruby Calls a Lambda
The Proc Object
Experiment 8-2: Changing Local Variables After Calling lambda
Calling lambda More Than Once in the Same Scope
Summary
9. Metaprogramming
Alternative Ways to Define Methods
Ruby’s Normal Method Definition Process
Defining Class Methods Using an Object Prefix
Defining Class Methods Using a New Lexical Scope
Defining Methods Using Singleton Classes
Defining Methods Using Singleton Classes in a Lexical Scope
Creating Refinements
Using Refinements
Experiment 9-1: Who Am I? How self Changes with Lexical Scope
self in the Top Scope
self in a Class Scope
self in a Metaclass Scope
self Inside a Class Method
Metaprogramming and Closures: eval, instance_eval, and binding
Code That Writes Code
Calling eval with binding
An instance_eval Example
Another Important Part of Ruby Closures
instance_eval Changes self to the Receiver
instance_eval Creates a Singleton Class for a New Lexical Scope
Experiment 9-2: Using a Closure to Define a Method
Using define_method
Methods Acting as Closures
Summary
10. JRuby: Ruby on the JVM
Running Programs with MRI and JRuby
How JRuby Parses and Compiles Your Code
How JRuby Executes Your Code
Implementing Ruby Classes with Java Classes
Experiment 10-1: Monitoring JRuby’s Just-in-Time Compiler
Experiment Code
Using the -J-XX:+PrintCompilation Option
Does JIT Speed Up Your JRuby Program?
Strings in JRuby and MRI
How JRuby and MRI Save String Data
Copy-on-Write
Experiment 10-2: Measuring Copy-on-Write Performance
Creating a Unique, Nonshared String
Experiment Code
Visualizing Copy-on-Write
Modifying a Shared String Is Slower
Summary
11. Rubinius: Ruby Implemented with Ruby
The Rubinius Kernel and Virtual Machine
Tokenization and Parsing
Using Ruby to Compile Ruby
Rubinius Bytecode Instructions
Ruby and C++ Working Together
Implementing Ruby Objects with C++ Objects
Experiment 11-1: Comparing Backtraces in MRI and Rubinius
Backtraces in Rubinius
Arrays in Rubinius and MRI
Arrays Inside of MRI
Arrays Inside of Rubinius
Experiment 11-2: Exploring the Rubinius Implementation of Array#shift
Reading Array#shift
Modifying Array#shift
Summary
12. Garbage Collection in MRI, JRuby, and Rubinius
Garbage Collectors Solve Three Problems
Garbage Collection in MRI: Mark and Sweep
The Free List
Marking
How Does MRI Mark Live Objects?
Sweeping
Lazy Sweeping
Disadvantages of Mark and Sweep
Experiment 12-1: Seeing MRI Garbage Collection in Action
Seeing MRI Perform a Lazy Sweep
Seeing MRI Perform a Full Collection
Interpreting a GC Profile Report
Garbage Collection in JRuby and Rubinius
Copying Garbage Collection
Bump Allocation
The Semi-Space Algorithm
The Eden Heap
Generational Garbage Collection
The Weak Generational Hypothesis
Using the Semi-Space Algorithm for Young Objects
Promoting Objects
Garbage Collection for Mature Objects
Concurrent Garbage Collection
Marking While the Object Graph Changes
Tricolor Marking
Three Garbage Collectors in the JVM
Experiment 12-2: Using Verbose GC Mode in JRuby
Triggering Major Collections
Further Reading
Summary
Index
Copyright
← Prev
Back
Next →
← Prev
Back
Next →