summaryrefslogtreecommitdiffhomepage
path: root/mrbgems/mruby-objectspace/src/mruby_objectspace.c
blob: 924eeb0e161505f98aa6e691185242bb3340e607 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include <stdio.h>

#include <mruby.h>
#include <mruby/gc.h>
#include <mruby/hash.h>
#include <mruby/value.h>

/*
 *  call-seq:
 *     ObjectSpace.count_objects([result_hash]) -> hash
 *
 *  Counts objects for each type.
 *
 *  It returns a hash, such as:
 *  {
 *    :TOTAL=>10000,
 *    :FREE=>3011,
 *    :MRB_TT_OBJECT=>6,
 *    :MRB_TT_CLASS=>404,
 *    # ...
 *  }
 *
 *  If the optional argument +result_hash+ is given,
 *  it is overwritten and returned. This is intended to avoid probe effect.
 *
 */

struct os_count_struct {
  size_t total;
 	size_t freed;
  size_t counts[MRB_TT_MAXDEFINE+1];
};

void os_count_object_type(mrb_state *mrb, struct RBasic* obj, void *data)
{
  struct os_count_struct* obj_count;
  obj_count = (struct os_count_struct*)(data);
  obj_count->counts[obj->tt]++;

  if (is_dead(mrb, obj)) {
  	obj_count->freed++;
  } else {
  	obj_count->total++;
  }
}

mrb_value
os_count_objects(mrb_state *mrb, mrb_value self)
{
    struct os_count_struct obj_count;
    size_t i;
    mrb_value hash;
    struct heap_page* page = mrb->heaps;

    if (mrb_get_args(mrb, "|H", &hash) == 0) {
        hash = mrb_hash_new(mrb);
    }

    if (!mrb_test(mrb_hash_empty_p(mrb, hash))) {
        mrb_hash_clear(mrb, hash);
    }

    for (i = 0; i <= MRB_TT_MAXDEFINE; i++) {
        obj_count.counts[i] = 0;
    }
    obj_count.total = 0;
    obj_count.freed = 0;

    mrb_objspace_each_objects(mrb, os_count_object_type, &obj_count);

    mrb_hash_set(mrb, hash, mrb_symbol_value(mrb_intern_cstr(mrb, "TOTAL")), mrb_fixnum_value(obj_count.total));
    mrb_hash_set(mrb, hash, mrb_symbol_value(mrb_intern_cstr(mrb, "FREE")), mrb_fixnum_value(obj_count.freed));

    for (i = 0; i < MRB_TT_MAXDEFINE; i++) {
        mrb_value type;
        switch (i) {
#define COUNT_TYPE(t) case (t): type = mrb_symbol_value(mrb_intern_cstr(mrb, #t)); break;
      COUNT_TYPE(MRB_TT_FALSE);
      COUNT_TYPE(MRB_TT_FREE);
      COUNT_TYPE(MRB_TT_TRUE);
      COUNT_TYPE(MRB_TT_FIXNUM);
      COUNT_TYPE(MRB_TT_SYMBOL);
      COUNT_TYPE(MRB_TT_UNDEF);
      COUNT_TYPE(MRB_TT_FLOAT);
      COUNT_TYPE(MRB_TT_VOIDP);
      COUNT_TYPE(MRB_TT_OBJECT);
      COUNT_TYPE(MRB_TT_CLASS);
      COUNT_TYPE(MRB_TT_MODULE);
      COUNT_TYPE(MRB_TT_ICLASS);
      COUNT_TYPE(MRB_TT_SCLASS);
      COUNT_TYPE(MRB_TT_PROC);
      COUNT_TYPE(MRB_TT_ARRAY);
      COUNT_TYPE(MRB_TT_HASH);
      COUNT_TYPE(MRB_TT_STRING);
      COUNT_TYPE(MRB_TT_RANGE);
      COUNT_TYPE(MRB_TT_EXCEPTION);
      COUNT_TYPE(MRB_TT_FILE);
      COUNT_TYPE(MRB_TT_ENV);
      COUNT_TYPE(MRB_TT_DATA);
#undef COUNT_TYPE
          default:              type = mrb_fixnum_value(i); break;
        }
        if (obj_count.counts[i])
            mrb_hash_set(mrb, hash, type, mrb_fixnum_value(obj_count.counts[i]));
    }

    return hash;
}

void
mrb_mruby_objectspace_gem_init(mrb_state* mrb) {
  struct RClass *os;
  os = mrb_define_module(mrb, "ObjectSpace");
  mrb_define_class_method(mrb, os, "count_objects", os_count_objects, MRB_ARGS_ANY());
}

void
mrb_mruby_objectspace_gem_final(mrb_state* mrb) {
  // finalizer
}