Author Archives: mrbrdo

Companion object in Ruby

Scala has this concept of a companion object. One of the things the companion object does is let you define class methods. In Ruby we usually use one of these two approaches:

We could have a similar construct to Scala. It seems Rails does something that clashes with defining the method ‘object’ in Kernel, so let’s call it companion instead.

Maybe not the most useful thing, but it looks tidy and nice, especially if you have a lot of class methods.

present? is killing Ruby

I don’t mean this literally, but have you ever seen code like this:

post = Post.first
if post.present?

If you think about it, the present? is not necessary. It’ll be either nil or it will be a record. But we don’t usually even think about it and we just use it everywhere. I’m talking about Rails developers.

What do you think, is it being abused?

On a side note, I would love to see Coffeescript’s existential operator in Ruby. It could actually be implemented with method missing, except for local variables.

Number of classes and methods in a Rails project

A relatively small Rails project has

n_methods = 746703
n_unique_method_names = 2500
n_classes = 2500
avg_methods_per_class = 298
#
# n_methods = ObjectSpace.each_object(Class).map{|c| c.methods + c.private_methods}.flatten.count
# n_unique_method_names = ObjectSpace.each_object(Class).map{|c| c.methods + c.private_methods}.flatten.uniq.count
# n_classes = ObjectSpace.each_object(Class).count
# avg_methods_per_class = n_methods / n_classes

mruby internals

ensure

mrb_state int eidx; // ensure block index into ensure array

void ecall // calls ensure block
// ensure called like this:

while (eidx > mrb->ci->eidx) {
ecall(mrb, –eidx);
}

other

mrb_state int ridx; // rescue block index into rescue array

Easy null object pattern in Ruby

Ever wanna chain some methods on something but want to ignore nil, without having to special-case for nil?

Edit: I actually use this quite often so I made a gem for it: https://github.com/mrbrdo/nullobject_chain

Here is my first solution:
Here is my second solution:And also solution without using exceptions, maybe a little more reliable because we know that NoMethodError occurs on NilClass instance:

Ruby Binding

In C binding looks like this:

// GetBindingPtr(bindval, bind) -> bind = rb_binding_t
typedef struct {
    VALUE env; // GetEnvPtr(envval, env) -> env = rb_env_t
    VALUE path;
    unsigned short first_lineno;
} rb_binding_t;

typedef struct {
    VALUE *env; // memory
    int env_size;
    int local_size;
    VALUE prev_envval;		/* for GC mark */
    rb_block_t block;
} rb_env_t;

typedef struct rb_block_struct {
    VALUE self;			/* share with method frame if it's only block */
    VALUE *ep;			/* share with method frame if it's only block */
    rb_iseq_t *iseq; // instruction sequence
    VALUE proc;
} rb_block_t;

The interesting part is environment (I made some comments about it):

envval = env_alloc();
GetEnvPtr(envval, env);
env->env_size = local_size + 1 + 1;
env->local_size = local_size;
env->prev_envval = penvval;
env->env = ALLOC_N(VALUE, env->env_size);
/* env->env looks like this (2 local variables in this case)
   mem 0000 setlocal 3
   mem 0008 setlocal 2
   mem 0010 RubyVM::Env object, previous "frame self" - not 100% about this one <-- cfp->ep points here
   mem 0018 RubyVM::Env object, "frame self" (= envval)
*/

And how to eval on binding from C (assuming you have binding object only in C)?

VALUE bind_eval_c(VALUE self, VALUE bindval, const char *eval_str, const char *vfile, const int vline) {
  VALUE args[4];
  args[0] = rb_str_new2(eval_str); // eval string
  args[1] = bindval; // VALUE object with class Binding
  args[2] = rb_str_new2(vfile); // what you want ruby to think ruby file is
  args[3] = LL2NUM(vline); // what you want ruby to think line number is
  //rb_f_eval(4, args, self);
  return rb_funcall(self, rb_intern("eval"), 4, args[0], args[1], args[2], args[3]);
}

Writing a Ruby compiler: Part 2

I finished implementing the most basic instructions (define class, module, method, local variables, Proc, opt_minus, opt_plus, opt_lt). There is not much to say yet, but I ran Fibonacci and at first the results were not so encouraging – For fib(39) I got 15 seconds while YARV got 19. This is not very significant.
But then I only changed that the recursive function was not called through YARV send, but directly (so with a CALL instruction). Now it completed in 4 seconds.
So the biggest benefit is when you are working with compiled classes, because then we can bypass YARV method dispatch. Now even class reopen and redefining methods can work in compiled mode. But only between compiled modules. So in theory even if you have a big project, if you compile everything then you can basically do everything. If one time the compiler would support the full Ruby specs, then we could easily run everything in compiled mode.
Also something to be learned from this is that send in Ruby is not very fast. And all method dispatch is basically done with send in the end.

YARVInstructionSequence/SimpleDataFormat

InstructionSequence:

["YARVInstructionSequence/SimpleDataFormat", # magic
 1, # major version
 2, # minor version
 1, # format type (hardcoded to 1 as of 1.9.3)
 {:arg_size=>3, :local_size=>6, :stack_max=>2}, # misc data
 "method_name", # label (name of method)
 "", # file name (relative path)
 nil, # absolute path
 1, # first line number
 :method, # type
 [:arg1, :arg2, :args, :loc1, :loc2], # locals
 [2, [], 0, 3, 2, -1, 0], # args
 catch_table, # exception (catch_table)
 # body
 [1, # line number
   [:trace, 1], # YARV instruction
   :label_1, #label
   ...,
   [:leave] # YARV instruction
 ]
]

# example of catch table
catch_table = [
  [:rescue, InstructionSequence, :label_2, :label_15, :label_16, 0],
  [:retry, nil, :label_15, :label_16, :label_2, 0]
]

type:

:top, :method, :block, :class, :rescue, :ensure, :eval, :main, :defined_guard

args:

[
argc, # argc
[label1, label2, ...] # opt labels
post_len,
post_start,
rest index,
block index,
simple
]

For more info look at “iseq_data_to_ary” in iseq.c.

Examples:

def x &block
  @m = block
end

 2,
 1,
 {:arg_size=>1, :local_size=>2, :stack_max=>2},
 "x",
 "<compiled>",
 nil,
 1,
 :method,
 [:block],
 [0, [], 0, 0, -1, 0, 0],
 [],
 [1,
  [:trace, 8],
  [:trace, 1],
  [:getlocal, 2],
  [:dup],
  [:setinstancevariable, :@m, 0],
  [:trace, 16],
  [:leave]]]

###

def x
  yield
end

 1,
 2,
 1,
 {:arg_size=>0, :local_size=>1, :stack_max=>1},
 "x",
 "<compiled>",
 nil,
 1,
 :method,
 [],
 0,
 [],
 [1,
  [:trace, 8],
  [:trace, 1],
  [:invokeblock, 0, 0],
  [:trace, 16],
  [:leave]]]

Writing a Ruby compiler: Part 1

So I am writing a Ruby compiler (or shall I say translator)… YARV only has around 80 bytecode instructions and the majority of them are pretty simple. I can let YARV parse .rb files and create the AST and parse that into bytecode. All I need to do then is implement all the bytecode instructions (well, kind of, of course there is more work here).

So at first I started writing it in assembler. I made a little Ruby DSL so I could write assembly in Intel syntax as Ruby functions and mix it with Ruby code. But after some time I got tired of looking up the binary codes for all the instructions I needed. So I was thinking of using metasm, an assembler written in Ruby. It seems like a cool project, however it is not packaged as a gem which is a minus. The biggest problem is, though, that documentation for it is virtually non-existant. So because I needed a little more control over stuff this was a problem for me.

I started thinking, writing in ASM might not be a good idea… There are 2 big problems, first I have to write for a very specific architecture, like x86_64. I can’t even write for both IA-32 and x86_64 (btw did you know that x86_64 and IA-64 is not the same thing? IA-64 is Itanium). Since most of the things are wrriten in ASM, basically the code is unportable.

The other problem is that I can’t benefit from compiler optimizations – compilers are really good nowadays and it’s very hard to make better optimized code by hand, especially on newer architecture where you have tons of instructions and registers. For example, did you know that for the function prologue, ENTER is actually slower than PUSH rsp; MOV rbp, rsp; SUB rsp, X. I find this funny – why would there be an instruction that does exactly the same thing as 3 other instructions together, but do it slower. I hear it is only still there due to backwards-compatibility. That’s why if you look at code generated by good compilers you will never see ENTER – they know better.

So due to these reasons I decided to rather write a kind of translator of Ruby to C. What I mean by this is to implement all the bytecode instructions in C. One very obvious benefit is that I can use the native stack and if you look at the Ruby bytecode you can see that it is entirely based around the stack – almost every instruction either pops from or pushes to stack. So if I can reduce the time it takes to push and pop things I expect it to affect performance very much. And since I use native stack it is as fast as it can be.

There is one problem here that must be addressed and that is procs (lambdas). Procs are especially a problem, even more than blocks. A proc can of course access the local variables of the parent scope (like the method that created the proc). But the thing is, you can pass a proc as an argument somewhere else, and the proc may be executed when the parent method has already finished. So this is a problem because the native stack is not accessible anymore after the method/function finishes. In YARV this isn’t a big deal because it just leaves the stack in memory and it lets the garbage collector free it when it’s not needed anymore. But with the native stack this is not possible. There are a few possible solutions that come to mind:

  • Copy the local variables somewhere for the proc. This is not OK because the proc must always be able to access the current value of the local variables, not the value they had when the proc was created. And if you don’t have control over the proc it can’t signal you “hey, give me your locals now”. It’s probably possible to workaround this somehow but…
  • Let the proc access the stack directly. This works great while the function is still running. I am currently using this solution – when the function finishes, I replace the pointer to the parent’s stack with some allocated memory where I copy all the local variables. Then I would have to garbage collect this and possibly optimize so this copy is not done when there are no blocks that would need it. The copy is pretty fast since I use the movs instruction (it loops itself and the processor does all the rest).
  • Allocate some memory and use it for the stack. Then when the function ends this memory can stay allocated until it’s not needed anymore. This solution is similar to the above but it requires allocation at the start. Otherwise you can just mov from and into it so access is still fast. If you use a memory pool this could be also quite an interesting option. But on the other hand you can also use a memory pool with the 2nd method and it seems better.

So the biggest problem with the stack is to garbage collect it somehow. I don’t think I can avoid this. I could probably hook into the garbage collector so that I would mark procs that use my stack and then when there are no more left I can free the memory. Garbage collection in itself is a problem because I am not quite sure yet how it works for C extensions. I will probably have to be careful about that so I don’t leak.

I have been having a lot of hard time with x86_64 ABI. I already wrote about this, basically it defines that parameters should be passed in registers instead of the stack like the good old IA-32. This is a big deal in my case because I am supposed to have the parameters on the stack because they are part of local variables in Ruby. So if I honor ABI I have to copy everything to the stack when the function starts, which takes time. The problem is it’s really hard not to honor ABI… Compilers don’t seem to provide an option to pass parameters on the stack. I was using naked C functions and setting up a stack frame by myself first, but this is a real PITA because the compiler tries to put local variables in places where you already put something, because it doesn’t care what you’re doing. It also requires a lot of ASM which is not good.

I just came up with a reasonably good solution today – using an unaligned struct and union it with my type. It sucks a little because you have to typecast stuff a little, but at least ABI is not a problem anymore. Because ABI says that unaligned structs should be passed on stack. And this does not affect performance at all because the resulting binary code is the same as if you would actually be using stdcall-like calling convetion in IA-32. So this is great. And because I generate C code from Ruby I don’t care if it is a little clunky to use.

I think the biggest problem will be passing stuff between interpreted Ruby and compiled Ruby. Especially letting Ruby access the local variables of a C function. I looked at the struct Ruby uses for an instruction sequence and it’s really complex, so I will need a lot of time to find a good way to do this. The good part is that eval will work fine, I can just pass it to the interpreter and it’s all good (except for the same problem of accessing local variables from the eval). There is a lot of things I can just let the interpreter do for me, which is pretty cool.