Project

General

Profile

Feature #10585 » 0004-struct.c-speedup-for-big-structs.patch

funny_falcon (Yura Sokolov), 12/10/2014 02:31 PM

View differences:

struct.c
#include "internal.h"
#include "vm_core.h"
#include "method.h"
#include "id.h"
VALUE rb_method_for_self_aref(VALUE name, VALUE arg);
VALUE rb_method_for_self_aset(VALUE name, VALUE arg);
VALUE rb_cStruct;
static ID id_members;
static ID id_members, id_back_members;
static VALUE struct_alloc(VALUE);
......
return members;
}
static void
struct_set_members(VALUE klass, VALUE members)
{
VALUE back = rb_ary_new();
members = rb_ary_dup(members);
if (RARRAY_LEN(members) <= 10) {
back = members;
} else {
long i, j, mask = 64;
VALUE name;
while (mask < RARRAY_LEN(members) * 5) mask *= 2;
rb_ary_resize(back, mask+1);
rb_ary_store(back, mask, INT2FIX(RARRAY_LEN(members)));
mask -= 2; /* mask = (2**k-1)*2 */
for (i=0; i<RARRAY_LEN(members); i++) {
name = RARRAY_AREF(members, i);
j = (SYM2ID(name) >> (ID_SCOPE_SHIFT - 1)) & mask; /* j = (id & (mask/2)) * 2 */
for (;;) {
if (!RTEST(RARRAY_AREF(back, j))) {
rb_ary_store(back, j, name);
rb_ary_store(back, j + 1, INT2FIX(i));
break;
}
j = (j * 5 + 2) & mask; /* j=(((j/2)*5+1)&(mask/2))*2 */
}
}
}
rb_obj_freeze(back);
rb_ivar_set(klass, id_members, members);
rb_ivar_set(klass, id_back_members, back);
RB_GC_GUARD(members);
}
static inline int
struct_member_pos(VALUE s, VALUE name)
{
VALUE back = struct_ivar_get(rb_obj_class(s), id_back_members);
VALUE const * p;
long j, mask;
if (UNLIKELY(NIL_P(back))) {
rb_raise(rb_eTypeError, "uninitialized struct");
}
if (UNLIKELY(!RB_TYPE_P(back, T_ARRAY))) {
rb_raise(rb_eTypeError, "corrupted struct");
}
p = RARRAY_CONST_PTR(back);
mask = RARRAY_LEN(back);
if (mask <= 10) {
if (UNLIKELY(RSTRUCT_LEN(s) != RARRAY_LEN(back))) {
rb_raise(rb_eTypeError, "struct size differs (%ld required %ld given)",
mask, RSTRUCT_LEN(s));
}
for (j=0; j<mask; j++) {
if (p[j] == name)
return j;
}
return -1;
}
if (UNLIKELY(RSTRUCT_LEN(s) != FIX2INT(RARRAY_AREF(back, mask-1)))) {
rb_raise(rb_eTypeError, "struct size differs (%d required %ld given)",
FIX2INT(RARRAY_AREF(back, mask-1)), RSTRUCT_LEN(s));
}
mask -= 3;
j = (SYM2ID(name) >> (ID_SCOPE_SHIFT - 1)) & mask;
for (;;) {
if (p[j] == name)
return FIX2INT(p[j + 1]);
if (!RTEST(p[j])) {
return -1;
}
j = (j * 5 + 2) & mask;
}
}
static VALUE
rb_struct_s_members_m(VALUE klass)
{
......
VALUE
rb_struct_getmember(VALUE obj, ID id)
{
VALUE members, slot;
long i, len;
members = rb_struct_members(obj);
slot = ID2SYM(id);
len = RARRAY_LEN(members);
for (i=0; i<len; i++) {
if (RARRAY_AREF(members, i) == slot) {
return RSTRUCT_GET(obj, i);
}
VALUE slot = ID2SYM(id);
int i = struct_member_pos(obj, slot);
if (i != -1) {
return RSTRUCT_GET(obj, i);
}
not_a_member(id);
......
long i, len;
OBJ_FREEZE(members);
rb_ivar_set(nstr, id_members, members);
struct_set_members(nstr, members);
rb_define_alloc_func(nstr, struct_alloc);
rb_define_singleton_method(nstr, "new", rb_class_new_instance, -1);
......
klass = anonymous_struct(super);
}
rb_ivar_set(klass, id_members, members);
struct_set_members(klass, members);
if (alloc) {
rb_define_alloc_func(klass, alloc);
......
static VALUE
rb_struct_aref_sym(VALUE s, VALUE name)
{
VALUE members = rb_struct_members(s);
long i, len = RARRAY_LEN(members);
for (i=0; i<len; i++) {
if (RARRAY_AREF(members, i) == name) {
return RSTRUCT_GET(s, i);
}
int pos = struct_member_pos(s, name);
if (pos != -1) {
return RSTRUCT_GET(s, pos);
}
rb_name_error_str(name, "no member '% "PRIsVALUE"' in struct", name);
......
static VALUE
rb_struct_aset_sym(VALUE s, VALUE name, VALUE val)
{
VALUE members = rb_struct_members(s);
long i, len = RARRAY_LEN(members);
if (RSTRUCT_LEN(s) != len) {
rb_raise(rb_eTypeError, "struct size differs (%ld required %ld given)",
len, RSTRUCT_LEN(s));
int pos = struct_member_pos(s, name);
if (pos != -1) {
rb_struct_modify(s);
RSTRUCT_SET(s, pos, val);
return val;
}
for (i=0; i<len; i++) {
if (RARRAY_AREF(members, i) == name) {
rb_struct_modify(s);
RSTRUCT_SET(s, i, val);
return val;
}
}
rb_name_error_str(name, "no member '% "PRIsVALUE"' in struct", name);
UNREACHABLE;
......
Init_Struct(void)
{
id_members = rb_intern("__members__");
id_back_members = rb_intern("__members_back__");
InitVM(Struct);
}
(4-4/5)