summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/mruby/gc.h53
-rw-r--r--mrbgems/mruby-objectspace/README.md4
-rw-r--r--mrbgems/mruby-objectspace/mrbgem.rake4
-rw-r--r--mrbgems/mruby-objectspace/src/mruby_objectspace.c111
-rw-r--r--mrbgems/mruby-objectspace/test/objectspace.rb34
-rw-r--r--src/gc.c114
-rw-r--r--test/t/objectspace.rb35
7 files changed, 210 insertions, 145 deletions
diff --git a/include/mruby/gc.h b/include/mruby/gc.h
new file mode 100644
index 000000000..00564c4fa
--- /dev/null
+++ b/include/mruby/gc.h
@@ -0,0 +1,53 @@
+/*
+** 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 */
diff --git a/mrbgems/mruby-objectspace/README.md b/mrbgems/mruby-objectspace/README.md
new file mode 100644
index 000000000..7669c9d7f
--- /dev/null
+++ b/mrbgems/mruby-objectspace/README.md
@@ -0,0 +1,4 @@
+MRuby ObjectSpace Implementation
+=========
+
+Currently only supports count_objects \ No newline at end of file
diff --git a/mrbgems/mruby-objectspace/mrbgem.rake b/mrbgems/mruby-objectspace/mrbgem.rake
new file mode 100644
index 000000000..100df4cdc
--- /dev/null
+++ b/mrbgems/mruby-objectspace/mrbgem.rake
@@ -0,0 +1,4 @@
+MRuby::Gem::Specification.new('mruby-objectspace') do |spec|
+ spec.license = 'MIT'
+ spec.authors = 'mruby developers'
+end
diff --git a/mrbgems/mruby-objectspace/src/mruby_objectspace.c b/mrbgems/mruby-objectspace/src/mruby_objectspace.c
new file mode 100644
index 000000000..2d064044d
--- /dev/null
+++ b/mrbgems/mruby-objectspace/src/mruby_objectspace.c
@@ -0,0 +1,111 @@
+#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
+}
diff --git a/mrbgems/mruby-objectspace/test/objectspace.rb b/mrbgems/mruby-objectspace/test/objectspace.rb
new file mode 100644
index 000000000..dbf3bcbb8
--- /dev/null
+++ b/mrbgems/mruby-objectspace/test/objectspace.rb
@@ -0,0 +1,34 @@
+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
diff --git a/src/gc.c b/src/gc.c
index 7add82eba..199551c55 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -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
diff --git a/test/t/objectspace.rb b/test/t/objectspace.rb
deleted file mode 100644
index 06319dcbb..000000000
--- a/test/t/objectspace.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-
-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