avellable avellable - 3 months ago 11x
Ruby Question

How does the coverage.so works?

I am trying to understand how ruby's internal library coverage.so works. By "works", I do not mean the usage of it. I mean how this calculates the line's execution count. I went through the source but, looks like after some method calls it's beyond my understanding.

Here's what I went through:


The coverage.so module just connects to ruby core to get information, search for rb_get_coverages() function to get this https://github.com/ruby/ruby/blob/38ea561319864fecf92bc61af0d9b9b1f49df6a0/thread.c

    return GET_VM()->coverages;

rb_set_coverages(VALUE coverages)
    GET_VM()->coverages = coverages;
    rb_add_event_hook(update_coverage, RUBY_EVENT_COVERAGE, Qnil);

And this file does the increments (count = old_count +1):

static void
update_coverage(rb_event_flag_t event, VALUE proc, VALUE self, ID id, VALUE klass)
    VALUE coverage = rb_iseq_coverage(GET_THREAD()->cfp->iseq);
    if (RB_TYPE_P(coverage, T_ARRAY) && !RBASIC_CLASS(coverage)) {
    long line = rb_sourceline() - 1;
    long count;
    if (line >= RARRAY_LEN(coverage)) { /* no longer tracked */
    count = FIX2LONG(RARRAY_AREF(coverage, line)) + 1;
    if (POSFIXABLE(count)) {
        RARRAY_ASET(coverage, line, LONG2FIX(count));

Actual hash created in parse.y https://github.com/ruby/ruby/blob/4c4f809e932417137d06e334d79065a4849dda0b/parse.y#L5491

static VALUE
coverage(VALUE fname, int n)
    VALUE coverages = rb_get_coverages();
    if (RTEST(coverages) && RBASIC(coverages)->klass == 0) {
    VALUE lines = n > 0 ? rb_ary_tmp_new_fill(n) : rb_ary_tmp_new(0);
    rb_hash_aset(coverages, fname, lines);
    return lines;
    return 0;