Skip to content

Commit

Permalink
* id_table.h: introduce ID key table.
Browse files Browse the repository at this point in the history
  [Feature ruby#11420]
  This table only manage ID->VALUE table to reduce overhead of st.
  Some functions prefixed rb_id_table_* are provided.
* id_table.c: implement rb_id_table_*.
  There are several algorithms to implement it.
  Now, there are roughly 4 types:
    * st
    * array
    * hash (implemented by  Yura Sokolov)
    * mix of array and hash
  The macro ID_TABLE_IMPL can choose implementation.
  You can see detailes about them at the head of id_table.c.
  At the default, I choose 34 (mix of list and hash).
  This is not final decision.
  Please report your suitable parameters or
  your data structure.
  * symbol.c: introduce rb_id_serial_t and rb_id_to_serial()
    to represent ID by serial number.
  * internal.h: use id_table for method tables.
  * class.c, gc.c, marshal.c, vm.c, vm_method.c: ditto.



git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51541 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
  • Loading branch information
ko1 committed Aug 12, 2015
1 parent ce5196b commit c35ff11
Show file tree
Hide file tree
Showing 12 changed files with 1,707 additions and 99 deletions.
35 changes: 35 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,38 @@
Wed Aug 12 17:05:36 2015 Koichi Sasada <ko1@atdot.net>

* id_table.h: introduce ID key table.
[Feature #11420]

This table only manage ID->VALUE table to reduce overhead of st.

Some functions prefixed rb_id_table_* are provided.

* id_table.c: implement rb_id_table_*.

There are several algorithms to implement it.

Now, there are roughly 4 types:

* st
* array
* hash (implemented by Yura Sokolov)
* mix of array and hash

The macro ID_TABLE_IMPL can choose implementation.
You can see detailes about them at the head of id_table.c.

At the default, I choose 34 (mix of list and hash).
This is not final decision.
Please report your suitable parameters or
your data structure.

* symbol.c: introduce rb_id_serial_t and rb_id_to_serial()
to represent ID by serial number.

* internal.h: use id_table for method tables.

* class.c, gc.c, marshal.c, vm.c, vm_method.c: ditto.

Wed Aug 12 05:19:11 2015 Eric Wong <e@80x24.org>

* parse.y (rb_parser_compile_cstr): remove volatile arg
Expand Down
63 changes: 31 additions & 32 deletions class.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "ruby/st.h"
#include "constant.h"
#include "vm_core.h"
#include "id_table.h"
#include <ctype.h>

#define id_attached id__attached__
Expand Down Expand Up @@ -181,6 +182,11 @@ class_alloc(VALUE flags, VALUE klass)
return (VALUE)obj;
}

static void
RCLASS_M_TBL_INIT(VALUE c)
{
RCLASS_M_TBL(c) = rb_id_table_create(0);
}

/*!
* A utility function that wraps class_alloc.
Expand Down Expand Up @@ -258,11 +264,11 @@ struct clone_method_arg {
VALUE old_klass;
};

static int
clone_method_i(st_data_t key, st_data_t value, st_data_t data)
static enum rb_id_table_iterator_result
clone_method_i(ID key, VALUE value, void *data)
{
const struct clone_method_arg *arg = (struct clone_method_arg *)data;
clone_method(arg->old_klass, arg->new_klass, (ID)key, (const rb_method_entry_t *)value);
clone_method(arg->old_klass, arg->new_klass, key, (const rb_method_entry_t *)value);
return ST_CONTINUE;
}

Expand Down Expand Up @@ -350,7 +356,7 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
arg.old_klass = orig;
arg.new_klass = clone;
RCLASS_M_TBL_INIT(clone);
st_foreach(RCLASS_M_TBL(orig), clone_method_i, (st_data_t)&arg);
rb_id_table_foreach(RCLASS_M_TBL(orig), clone_method_i, &arg);
}

return clone;
Expand Down Expand Up @@ -400,7 +406,7 @@ rb_singleton_class_clone_and_attach(VALUE obj, VALUE attach)
struct clone_method_arg arg;
arg.old_klass = klass;
arg.new_klass = clone;
st_foreach(RCLASS_M_TBL(klass), clone_method_i, (st_data_t)&arg);
rb_id_table_foreach(RCLASS_M_TBL(klass), clone_method_i, &arg);
}
rb_singleton_class_attached(RBASIC(clone)->klass, clone);
FL_SET(clone, FL_SINGLETON);
Expand Down Expand Up @@ -836,10 +842,10 @@ rb_include_module(VALUE klass, VALUE module)
rb_raise(rb_eArgError, "cyclic include detected");
}

static int
add_refined_method_entry_i(st_data_t key, st_data_t value, st_data_t data)
static enum rb_id_table_iterator_result
add_refined_method_entry_i(ID key, VALUE value, void *data)
{
rb_add_refined_method_entry((VALUE) data, (ID) key);
rb_add_refined_method_entry((VALUE)data, key);
return ST_CONTINUE;
}

Expand All @@ -848,7 +854,7 @@ include_modules_at(const VALUE klass, VALUE c, VALUE module, int search_super)
{
VALUE p, iclass;
int method_changed = 0, constant_changed = 0;
const st_table *const klass_m_tbl = RCLASS_M_TBL(RCLASS_ORIGIN(klass));
struct rb_id_table *const klass_m_tbl = RCLASS_M_TBL(RCLASS_ORIGIN(klass));

while (module) {
int superclass_seen = FALSE;
Expand Down Expand Up @@ -886,14 +892,11 @@ include_modules_at(const VALUE klass, VALUE c, VALUE module, int search_super)
VALUE refined_class =
rb_refinement_module_get_refined_class(klass);

st_foreach(RMODULE_M_TBL(module), add_refined_method_entry_i,
(st_data_t) refined_class);
rb_id_table_foreach(RMODULE_M_TBL(module), add_refined_method_entry_i, (void *)refined_class);
FL_SET(c, RMODULE_INCLUDED_INTO_REFINEMENT);
}
if (RMODULE_M_TBL(module) && RMODULE_M_TBL(module)->num_entries)
method_changed = 1;
if (RMODULE_CONST_TBL(module) && RMODULE_CONST_TBL(module)->num_entries)
constant_changed = 1;
if (RMODULE_M_TBL(module) && rb_id_table_size(RMODULE_M_TBL(module))) method_changed = 1;
if (RMODULE_CONST_TBL(module) && RMODULE_CONST_TBL(module)->num_entries) constant_changed = 1;
skip:
module = RCLASS_SUPER(module);
}
Expand All @@ -904,23 +907,23 @@ include_modules_at(const VALUE klass, VALUE c, VALUE module, int search_super)
return method_changed;
}

static int
move_refined_method(st_data_t key, st_data_t value, st_data_t data)
static enum rb_id_table_iterator_result
move_refined_method(ID key, VALUE value, void *data)
{
rb_method_entry_t *me = (rb_method_entry_t *) value;
st_table *tbl = (st_table *) data;
struct rb_id_table *tbl = (struct rb_id_table *) data;

if (me->def->type == VM_METHOD_TYPE_REFINED) {
if (me->def->body.refined.orig_me) {
const rb_method_entry_t *orig_me = me->def->body.refined.orig_me, *new_me;
RB_OBJ_WRITE(me, &me->def->body.refined.orig_me, NULL);
new_me = rb_method_entry_clone(me);
st_add_direct(tbl, key, (st_data_t) new_me);
rb_id_table_insert(tbl, key, (VALUE)new_me);
rb_method_entry_copy(me, orig_me);
return ST_CONTINUE;
}
else {
st_add_direct(tbl, key, (st_data_t) me);
rb_id_table_insert(tbl, key, (VALUE)me);
return ST_DELETE;
}
}
Expand Down Expand Up @@ -950,8 +953,7 @@ rb_prepend_module(VALUE klass, VALUE module)
RCLASS_SET_ORIGIN(klass, origin);
RCLASS_M_TBL(origin) = RCLASS_M_TBL(klass);
RCLASS_M_TBL_INIT(klass);
st_foreach(RCLASS_M_TBL(origin), move_refined_method,
(st_data_t) RCLASS_M_TBL(klass));
rb_id_table_foreach(RCLASS_M_TBL(origin), move_refined_method, (void *)RCLASS_M_TBL(klass));
}
changed = include_modules_at(klass, klass, module, FALSE);
if (changed < 0)
Expand Down Expand Up @@ -1109,8 +1111,8 @@ struct method_entry_arg {
int recur;
};

static int
method_entry_i(st_data_t key, st_data_t value, st_data_t data)
static enum rb_id_table_iterator_result
method_entry_i(ID key, VALUE value, void *data)
{
const rb_method_entry_t *me = (const rb_method_entry_t *)value;
struct method_entry_arg *arg = (struct method_entry_arg *)data;
Expand Down Expand Up @@ -1158,7 +1160,7 @@ class_instance_method_list(int argc, const VALUE *argv, VALUE mod, int obj, int
me_arg.list = st_init_numtable();
me_arg.recur = recur;
for (; mod; mod = RCLASS_SUPER(mod)) {
if (RCLASS_M_TBL(mod)) st_foreach(RCLASS_M_TBL(mod), method_entry_i, (st_data_t)&me_arg);
if (RCLASS_M_TBL(mod)) rb_id_table_foreach(RCLASS_M_TBL(mod), method_entry_i, &me_arg);
if (BUILTIN_TYPE(mod) == T_ICLASS && !prepended) continue;
if (obj && FL_TEST(mod, FL_SINGLETON)) continue;
if (!recur) break;
Expand Down Expand Up @@ -1379,7 +1381,7 @@ rb_obj_singleton_methods(int argc, const VALUE *argv, VALUE obj)
{
VALUE recur, ary, klass, origin;
struct method_entry_arg me_arg;
st_table *mtbl;
struct rb_id_table *mtbl;

if (argc == 0) {
recur = Qtrue;
Expand All @@ -1392,14 +1394,12 @@ rb_obj_singleton_methods(int argc, const VALUE *argv, VALUE obj)
me_arg.list = st_init_numtable();
me_arg.recur = RTEST(recur);
if (klass && FL_TEST(klass, FL_SINGLETON)) {
if ((mtbl = RCLASS_M_TBL(origin)) != 0)
st_foreach(mtbl, method_entry_i, (st_data_t)&me_arg);
if ((mtbl = RCLASS_M_TBL(origin)) != 0) rb_id_table_foreach(mtbl, method_entry_i, &me_arg);
klass = RCLASS_SUPER(klass);
}
if (RTEST(recur)) {
while (klass && (FL_TEST(klass, FL_SINGLETON) || RB_TYPE_P(klass, T_ICLASS))) {
if (klass != origin && (mtbl = RCLASS_M_TBL(klass)) != 0)
st_foreach(mtbl, method_entry_i, (st_data_t)&me_arg);
if (klass != origin && (mtbl = RCLASS_M_TBL(klass)) != 0) rb_id_table_foreach(mtbl, method_entry_i, &me_arg);
klass = RCLASS_SUPER(klass);
}
}
Expand Down Expand Up @@ -1989,8 +1989,7 @@ rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, V
int
rb_class_has_methods(VALUE c)
{
st_table *mtbl = RCLASS_M_TBL(c);
return mtbl && mtbl->num_entries ? TRUE : FALSE;
return rb_id_table_size(RCLASS_M_TBL(c)) == 0 ? FALSE : TRUE;
}

/*!
Expand Down
8 changes: 7 additions & 1 deletion common.mk
Original file line number Diff line number Diff line change
Expand Up @@ -1117,6 +1117,7 @@ class.$(OBJEXT): {$(VPATH)}constant.h
class.$(OBJEXT): {$(VPATH)}defines.h
class.$(OBJEXT): {$(VPATH)}encoding.h
class.$(OBJEXT): {$(VPATH)}id.h
class.$(OBJEXT): {$(VPATH)}id_table.h
class.$(OBJEXT): {$(VPATH)}intern.h
class.$(OBJEXT): {$(VPATH)}internal.h
class.$(OBJEXT): {$(VPATH)}io.h
Expand Down Expand Up @@ -1456,6 +1457,7 @@ gc.$(OBJEXT): {$(VPATH)}eval_intern.h
gc.$(OBJEXT): {$(VPATH)}gc.c
gc.$(OBJEXT): {$(VPATH)}gc.h
gc.$(OBJEXT): {$(VPATH)}id.h
gc.$(OBJEXT): {$(VPATH)}id_table.h
gc.$(OBJEXT): {$(VPATH)}intern.h
gc.$(OBJEXT): {$(VPATH)}internal.h
gc.$(OBJEXT): {$(VPATH)}io.h
Expand Down Expand Up @@ -1668,7 +1670,8 @@ marshal.$(OBJEXT): $(top_srcdir)/include/ruby.h
marshal.$(OBJEXT): {$(VPATH)}config.h
marshal.$(OBJEXT): {$(VPATH)}defines.h
marshal.$(OBJEXT): {$(VPATH)}encoding.h
marshal.$(OBJEXT): {$(VPATH)}intern.h
marshal.$(OBJEXT): {$(VPATH)}id_table.h
marshal.$(OBJEXT): {$(VPATH)}intern.h
marshal.$(OBJEXT): {$(VPATH)}internal.h
marshal.$(OBJEXT): {$(VPATH)}io.h
marshal.$(OBJEXT): {$(VPATH)}marshal.c
Expand Down Expand Up @@ -2215,6 +2218,8 @@ symbol.$(OBJEXT): {$(VPATH)}probes.h
symbol.$(OBJEXT): {$(VPATH)}st.h
symbol.$(OBJEXT): {$(VPATH)}subst.h
symbol.$(OBJEXT): {$(VPATH)}symbol.c
symbol.$(OBJEXT): {$(VPATH)}id_table.c
symbol.$(OBJEXT): {$(VPATH)}id_table.h
symbol.$(OBJEXT): {$(VPATH)}symbol.h
symbol.$(OBJEXT): {$(VPATH)}vm_opts.h
thread.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
Expand Down Expand Up @@ -2330,6 +2335,7 @@ vm.$(OBJEXT): {$(VPATH)}encoding.h
vm.$(OBJEXT): {$(VPATH)}eval_intern.h
vm.$(OBJEXT): {$(VPATH)}gc.h
vm.$(OBJEXT): {$(VPATH)}id.h
vm.$(OBJEXT): {$(VPATH)}id_table.h
vm.$(OBJEXT): {$(VPATH)}insns.def
vm.$(OBJEXT): {$(VPATH)}insns.inc
vm.$(OBJEXT): {$(VPATH)}intern.h
Expand Down
30 changes: 12 additions & 18 deletions gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "constant.h"
#include "ruby_atomic.h"
#include "probes.h"
#include "id_table.h"
#include <stdio.h>
#include <stdarg.h>
#include <setjmp.h>
Expand Down Expand Up @@ -1928,14 +1929,6 @@ is_pointer_to_heap(rb_objspace_t *objspace, void *ptr)
return FALSE;
}

static void
rb_free_m_tbl(st_table *tbl)
{
if (tbl) {
st_free_table(tbl);
}
}

static int
free_const_entry_i(st_data_t key, st_data_t value, st_data_t data)
{
Expand Down Expand Up @@ -2010,7 +2003,7 @@ obj_free(rb_objspace_t *objspace, VALUE obj)
break;
case T_MODULE:
case T_CLASS:
rb_free_m_tbl(RCLASS_M_TBL(obj));
rb_id_table_free(RCLASS_M_TBL(obj));
if (RCLASS_IV_TBL(obj)) {
st_free_table(RCLASS_IV_TBL(obj));
}
Expand Down Expand Up @@ -2104,9 +2097,11 @@ obj_free(rb_objspace_t *objspace, VALUE obj)
case T_ICLASS:
/* Basically , T_ICLASS shares table with the module */
if (FL_TEST(obj, RICLASS_IS_ORIGIN)) {
rb_free_m_tbl(RCLASS_M_TBL(obj));
rb_id_table_free(RCLASS_M_TBL(obj));
}
if (RCLASS_CALLABLE_M_TBL(obj) != NULL) {
rb_id_table_free(RCLASS_CALLABLE_M_TBL(obj));
}
rb_free_m_tbl(RCLASS_CALLABLE_M_TBL(obj));
if (RCLASS_EXT(obj)->subclasses) {
rb_class_detach_subclasses(obj);
RCLASS_EXT(obj)->subclasses = NULL;
Expand Down Expand Up @@ -3001,7 +2996,7 @@ obj_memsize_of(VALUE obj, int use_all_types)
case T_MODULE:
case T_CLASS:
if (RCLASS_M_TBL(obj)) {
size += st_memsize(RCLASS_M_TBL(obj));
size += rb_id_table_memsize(RCLASS_M_TBL(obj));
}
if (RCLASS_EXT(obj)) {
if (RCLASS_IV_TBL(obj)) {
Expand All @@ -3022,7 +3017,7 @@ obj_memsize_of(VALUE obj, int use_all_types)
case T_ICLASS:
if (FL_TEST(obj, RICLASS_IS_ORIGIN)) {
if (RCLASS_M_TBL(obj)) {
size += st_memsize(RCLASS_M_TBL(obj));
size += rb_id_table_memsize(RCLASS_M_TBL(obj));
}
}
break;
Expand Down Expand Up @@ -3966,21 +3961,20 @@ mark_method_entry(rb_objspace_t *objspace, const rb_method_entry_t *me)
}
}

static int
mark_method_entry_i(st_data_t key, st_data_t value, st_data_t data)
static enum rb_id_table_iterator_result
mark_method_entry_i(VALUE me, void *data)
{
VALUE me = (VALUE)value;
rb_objspace_t *objspace = (rb_objspace_t *)data;

gc_mark(objspace, me);
return ST_CONTINUE;
}

static void
mark_m_tbl(rb_objspace_t *objspace, struct st_table *tbl)
mark_m_tbl(rb_objspace_t *objspace, struct rb_id_table *tbl)
{
if (tbl) {
st_foreach(tbl, mark_method_entry_i, (st_data_t)objspace);
rb_id_table_foreach_values(tbl, mark_method_entry_i, objspace);
}
}

Expand Down
Loading

0 comments on commit c35ff11

Please sign in to comment.