Commit 222918de authored by Ryan Scott's avatar Ryan Scott

First implementation of ObjectSpace moved outside of gc.c

parent a71bf5e3
/*
** gc.c - garbage collector for mruby
**
** See Copyright Notice in mruby.h
*/
#ifndef MRUBY_GC_H
#define MRUBY_GC_H
#if defined(__cplusplus)
extern "C" {
#endif
#include "mruby.h"
#include "mruby/array.h"
#include "mruby/class.h"
#include "mruby/data.h"
#include "mruby/hash.h"
#include "mruby/proc.h"
#include "mruby/range.h"
#include "mruby/string.h"
#include "mruby/variable.h"
struct free_obj {
MRB_OBJECT_HEADER;
struct RBasic *next;
};
struct RVALUE {
union {
struct free_obj free;
struct RBasic basic;
struct RObject object;
struct RClass klass;
struct RString string;
struct RArray array;
struct RHash hash;
struct RRange range;
struct RData data;
struct RProc proc;
} as;
};
typedef struct RVALUE RVALUE;
typedef int each_object_callback(RVALUE *obj, void *data);
void mrb_objspace_each_objects(mrb_state *mrb, each_object_callback* callback, void *data);
#if defined(__cplusplus)
} /* extern "C" { */
#endif
#endif /* MRUBY_GC_H */
MRuby ObjectSpace Implementation
=========
Currently only supports count_objects
\ No newline at end of file
MRuby::Gem::Specification.new('mruby-objectspace') do |spec|
spec.license = 'MIT'
spec.authors = 'mruby developers'
end
#include <mruby.h>
#include <mruby/gc.h>
#include <mruby/hash.h>
#include <stdio.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 counts[MRB_TT_MAXDEFINE+1];
};
void os_count_object_type(RVALUE *obj, void *data)
{
struct os_count_struct* obj_count;
obj_count = (struct os_count_struct*)(data);
obj_count->counts[mrb_type(obj->as.basic)]++;
obj_count->total++;
}
mrb_value
os_count_objects(mrb_state *mrb, mrb_value self)
{
struct os_count_struct obj_count;
size_t freed = 0;
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;
}
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(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
}
assert('ObjectSpace.count_objects') do
h = {}
ObjectSpace.count_objects(h)
assert_kind_of(Hash, h)
assert_true(h.keys.all? {|x| x.is_a?(Symbol) || x.is_a?(Integer) })
assert_true(h.values.all? {|x| x.is_a?(Integer) })
h = ObjectSpace.count_objects
assert_kind_of(Hash, h)
assert_true(h.keys.all? {|x| x.is_a?(Symbol) || x.is_a?(Integer) })
assert_true(h.values.all? {|x| x.is_a?(Integer) })
assert_raise(TypeError) { ObjectSpace.count_objects(1) }
h0 = {:MRB_TT_FOO=>1000}
h = ObjectSpace.count_objects(h0)
assert_false(h0.has_key?(:MRB_TT_FOO))
GC.start
h_after = {}
h_before = ObjectSpace.count_objects
objs = []
1000.times do
objs << {}
end
objs = nil
ObjectSpace.count_objects(h)
GC.start
ObjectSpace.count_objects(h_after)
assert_equal(h_before[:MRB_TT_HASH] + 1000, h[:MRB_TT_HASH])
assert_equal(h_before[:MRB_TT_HASH], h_after[:MRB_TT_HASH])
end
\ No newline at end of file
......@@ -20,6 +20,7 @@
#include "mruby/range.h"
#include "mruby/string.h"
#include "mruby/variable.h"
#include "mruby/gc.h"
/*
= Tri-color Incremental Garbage Collection
......@@ -72,26 +73,6 @@
*/
struct free_obj {
MRB_OBJECT_HEADER;
struct RBasic *next;
};
typedef struct {
union {
struct free_obj free;
struct RBasic basic;
struct RObject object;
struct RClass klass;
struct RString string;
struct RArray array;
struct RHash hash;
struct RRange range;
struct RData data;
struct RProc proc;
} as;
} RVALUE;
#ifdef GC_PROFILE
#include <stdio.h>
#include <sys/time.h>
......@@ -1141,105 +1122,22 @@ gc_generational_mode_set(mrb_state *mrb, mrb_value self)
return mrb_bool_value(enable);
}
/*
* 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.
*
*/
mrb_value
os_count_objects(mrb_state *mrb, mrb_value self)
void
mrb_objspace_each_objects(mrb_state *mrb, each_object_callback* callback, void *data)
{
size_t counts[MRB_TT_MAXDEFINE+1];
size_t freed = 0;
size_t total = 0;
size_t i;
mrb_value hash;
RVALUE *free;
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++) {
counts[i] = 0;
}
while (page != NULL) {
RVALUE *p, *pend;
p = page->objects;
pend = p + MRB_HEAP_PAGE_SIZE;
for (;p < pend; p++) {
counts[mrb_type(p->as.basic)]++;
callback(p, data);
}
free = (RVALUE*)page->freelist;
while (free) {
freed++;
free = (RVALUE*)free->as.free.next;
}
total += MRB_HEAP_PAGE_SIZE;
page = page->next;
}
mrb_hash_set(mrb, hash, mrb_symbol_value(mrb_intern_cstr(mrb, "TOTAL")), mrb_fixnum_value(total));
mrb_hash_set(mrb, hash, mrb_symbol_value(mrb_intern_cstr(mrb, "FREE")), mrb_fixnum_value(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 (counts[i])
mrb_hash_set(mrb, hash, type, mrb_fixnum_value(counts[i]));
}
return hash;
}
#ifdef GC_TEST
......@@ -1252,7 +1150,6 @@ void
mrb_init_gc(mrb_state *mrb)
{
struct RClass *gc;
struct RClass *os;
gc = mrb_define_module(mrb, "GC");
......@@ -1270,9 +1167,6 @@ mrb_init_gc(mrb_state *mrb)
mrb_define_class_method(mrb, gc, "test", gc_test, MRB_ARGS_NONE());
#endif
#endif
os = mrb_define_module(mrb, "ObjectSpace");
mrb_define_class_method(mrb, os, "count_objects", os_count_objects, MRB_ARGS_ANY());
}
#ifdef GC_TEST
......
assert('ObjectSpace.count_objects') do
h = {}
ObjectSpace.count_objects(h)
assert_kind_of(Hash, h)
assert_true(h.keys.all? {|x| x.is_a?(Symbol) || x.is_a?(Integer) })
assert_true(h.values.all? {|x| x.is_a?(Integer) })
h = ObjectSpace.count_objects
assert_kind_of(Hash, h)
assert_true(h.keys.all? {|x| x.is_a?(Symbol) || x.is_a?(Integer) })
assert_true(h.values.all? {|x| x.is_a?(Integer) })
assert_raise(TypeError) { ObjectSpace.count_objects(1) }
h0 = {:MRB_TT_FOO=>1000}
h = ObjectSpace.count_objects(h0)
assert_false(h0.has_key?(:MRB_TT_FOO))
GC.start
h_after = {}
h_before = ObjectSpace.count_objects
objs = []
1000.times do
objs << {}
end
objs = nil
ObjectSpace.count_objects(h)
GC.start
ObjectSpace.count_objects(h_after)
assert_equal(h_before[:MRB_TT_HASH] + 1000, h[:MRB_TT_HASH])
assert_equal(h_before[:MRB_TT_HASH], h_after[:MRB_TT_HASH])
end
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment