Project

General

Profile

Feature #11299 ยป 0001-use-Array-instead-of-custom-struct-for-generic-ivars.patch

normalperson (Eric Wong), 06/23/2015 11:23 PM

View differences:

array.c
#define ARY_SET(a, i, v) RARRAY_ASET((assert(!ARY_SHARED_P(a)), (a)), (i), (v))
void
rb_mem_clear(register VALUE *mem, register long size)
static inline void
memfill(register VALUE *mem, register long size, register VALUE val)
{
while (size--) {
*mem++ = Qnil;
*mem++ = val;
}
}
void
rb_mem_clear(register VALUE *mem, register long size)
{
memfill(mem, size, Qnil);
}
static void
ary_mem_clear(VALUE ary, long beg, long size)
{
......
});
}
static inline void
memfill(register VALUE *mem, register long size, register VALUE val)
{
while (size--) {
*mem++ = val;
}
}
static void
ary_memfill(VALUE ary, long beg, long size, VALUE val)
{
......
void
rb_ary_store(VALUE ary, long idx, VALUE val)
{
rb_ary_store_fill(ary, idx, val, Qnil);
}
void
rb_ary_store_fill(VALUE ary, long idx, VALUE val, VALUE fill)
{
long len = RARRAY_LEN(ary);
if (idx < 0) {
......
ary_double_capa(ary, idx);
}
if (idx > len) {
ary_mem_clear(ary, len, idx - len + 1);
ary_memfill(ary, len, idx - len + 1, fill);
}
if (idx >= len) {
internal.h
void rb_ary_delete_same(VALUE, VALUE);
VALUE rb_ary_tmp_new_fill(long capa);
size_t rb_ary_memsize(VALUE);
void rb_ary_store_fill(VALUE ary, long idx, VALUE val, VALUE fill);
#ifdef __GNUC__
#define rb_ary_new_from_args(n, ...) \
__extension__ ({ \
variable.c
static st_table *generic_iv_tbl;
static st_table *generic_iv_tbl_compat;
/* per-object */
struct gen_ivtbl {
long numiv; /* only uses 32-bits */
VALUE ivptr[1]; /* flexible array */
};
struct ivar_update {
union {
st_table *iv_index_tbl;
struct gen_ivtbl *ivtbl;
VALUE ivtbl;
} u;
st_data_t index;
int extended;
......
}
struct gen_ivar_compat_tbl {
struct gen_ivtbl *ivtbl;
VALUE ivtbl;
st_table *tbl;
};
......
{
struct gen_ivar_compat_tbl *a = (struct gen_ivar_compat_tbl *)arg;
if ((long)index < a->ivtbl->numiv) {
VALUE val = a->ivtbl->ivptr[index];
if ((long)index < RARRAY_LEN(a->ivtbl)) {
VALUE val = RARRAY_AREF(a->ivtbl, index);
if (val != Qundef) {
st_add_direct(a->tbl, id, (st_data_t)val);
}
......
}
static int
gen_ivtbl_get(VALUE obj, struct gen_ivtbl **ivtbl)
gen_ivtbl_get(VALUE obj, VALUE *ivtbl)
{
st_data_t data;
if (st_lookup(generic_iv_tbl, (st_data_t)obj, &data)) {
*ivtbl = (struct gen_ivtbl *)data;
*ivtbl = (VALUE)data;
return 1;
}
return 0;
......
static VALUE
generic_ivar_delete(VALUE obj, ID id, VALUE undef)
{
struct gen_ivtbl *ivtbl;
VALUE ivtbl;
if (gen_ivtbl_get(obj, &ivtbl)) {
st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(rb_obj_class(obj));
st_data_t index;
if (st_lookup(iv_index_tbl, (st_data_t)id, &index)) {
if ((long)index < ivtbl->numiv) {
VALUE ret = ivtbl->ivptr[index];
if ((long)index < RARRAY_LEN(ivtbl)) {
VALUE ret = RARRAY_AREF(ivtbl, index);
ivtbl->ivptr[index] = Qundef;
RARRAY_ASET(ivtbl, index, Qundef);
return ret == Qundef ? undef : ret;
}
}
......
static VALUE
generic_ivar_get(VALUE obj, ID id, VALUE undef)
{
struct gen_ivtbl *ivtbl;
VALUE ivtbl;
if (gen_ivtbl_get(obj, &ivtbl)) {
st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(rb_obj_class(obj));
st_data_t index;
if (st_lookup(iv_index_tbl, (st_data_t)id, &index)) {
if ((long)index < ivtbl->numiv) {
VALUE ret = ivtbl->ivptr[index];
if ((long)index < RARRAY_LEN(ivtbl)) {
VALUE ret = RARRAY_AREF(ivtbl, index);
return ret == Qundef ? undef : ret;
}
......
return undef;
}
static size_t
gen_ivtbl_bytes(size_t n)
{
return sizeof(struct gen_ivtbl) + n * sizeof(VALUE) - sizeof(VALUE);
}
struct gen_ivtbl *
gen_ivtbl_resize(struct gen_ivtbl *old, long n)
{
long len = old ? old->numiv : 0;
struct gen_ivtbl *ivtbl = xrealloc(old, gen_ivtbl_bytes(n));
ivtbl->numiv = n;
for (; len < n; len++) {
ivtbl->ivptr[len] = Qundef;
}
return ivtbl;
}
struct gen_ivtbl *
gen_ivtbl_dup(const struct gen_ivtbl *orig)
{
size_t s = gen_ivtbl_bytes(orig->numiv);
struct gen_ivtbl *ivtbl = xmalloc(s);
memcpy(ivtbl, orig, s);
return ivtbl;
}
static long
iv_index_tbl_newsize(struct ivar_update *ivup)
{
......
{
VALUE obj = (VALUE)*k;
struct ivar_update *ivup = (struct ivar_update *)u;
long newsize;
int ret = ST_CONTINUE;
struct gen_ivtbl *ivtbl;
if (existing) {
ivtbl = (struct gen_ivtbl *)*v;
if ((long)ivup->index >= ivtbl->numiv) {
goto resize;
}
ret = ST_STOP;
}
else {
FL_SET(obj, FL_EXIVAR);
ivtbl = 0;
resize:
newsize = iv_index_tbl_newsize(ivup);
ivtbl = gen_ivtbl_resize(ivtbl, newsize);
*v = (st_data_t)ivtbl;
ivup->u.ivtbl = (VALUE)*v;
return ST_STOP;
}
ivup->u.ivtbl = ivtbl;
return ret;
ivup->u.ivtbl = rb_ary_tmp_new(0);
FL_SET(obj, FL_EXIVAR);
*v = (st_data_t)ivup->u.ivtbl;
return ST_CONTINUE;
}
static VALUE
generic_ivar_defined(VALUE obj, ID id)
{
struct gen_ivtbl *ivtbl;
VALUE ivtbl;
st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(rb_obj_class(obj));
st_data_t index;
......
if (!st_lookup(iv_index_tbl, (st_data_t)id, &index)) return Qfalse;
if (!gen_ivtbl_get(obj, &ivtbl)) return Qfalse;
if (((long)index < ivtbl->numiv) && (ivtbl->ivptr[index] != Qundef))
if ((long)index < RARRAY_LEN(ivtbl) && RARRAY_AREF(ivtbl, index) != Qundef)
return Qtrue;
return Qfalse;
......
static int
generic_ivar_remove(VALUE obj, ID id, st_data_t *valp)
{
struct gen_ivtbl *ivtbl;
VALUE ivtbl;
st_data_t key = (st_data_t)id;
st_data_t index;
st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(rb_obj_class(obj));
......
if (!st_lookup(iv_index_tbl, key, &index)) return 0;
if (!gen_ivtbl_get(obj, &ivtbl)) return 0;
if ((long)index < ivtbl->numiv) {
if (ivtbl->ivptr[index] != Qundef) {
ivtbl->ivptr[index] = Qundef;
if ((long)index < RARRAY_LEN(ivtbl)) {
if (RARRAY_AREF(ivtbl, index) != Qundef) {
RARRAY_ASET(ivtbl, index, Qundef);
return 1;
}
}
return 0;
}
static void
gen_ivtbl_mark(const struct gen_ivtbl *ivtbl)
{
long i;
for (i = 0; i < ivtbl->numiv; i++) {
rb_gc_mark(ivtbl->ivptr[i]);
}
}
void
rb_mark_generic_ivar(VALUE obj)
{
struct gen_ivtbl *ivtbl;
VALUE ivtbl;
if (gen_ivtbl_get(obj, &ivtbl)) {
gen_ivtbl_mark(ivtbl);
rb_gc_mark(ivtbl);
}
}
......
rb_free_generic_ivar(VALUE obj)
{
st_data_t key = (st_data_t)obj;
struct gen_ivtbl *ivtbl;
VALUE ivtbl;
if (st_delete(generic_iv_tbl, &key, (st_data_t *)&ivtbl))
xfree(ivtbl);
(void)st_delete(generic_iv_tbl, &key, (st_data_t *)&ivtbl);
/* rb_ary_clear is not suitable here since that can realloc, rely on GC */
if (generic_iv_tbl_compat) {
st_table *tbl;
......
RUBY_FUNC_EXPORTED size_t
rb_generic_ivar_memsize(VALUE obj)
{
struct gen_ivtbl *ivtbl;
VALUE ivtbl;
if (gen_ivtbl_get(obj, &ivtbl))
return gen_ivtbl_bytes(ivtbl->numiv);
return rb_ary_memsize(ivtbl);
return 0;
}
static size_t
gen_ivtbl_count(const struct gen_ivtbl *ivtbl)
gen_ivtbl_count(const VALUE ivtbl)
{
long i;
size_t n = 0;
long len = RARRAY_LEN(ivtbl);
const VALUE *ptr = RARRAY_CONST_PTR(ivtbl);
for (i = 0; i < ivtbl->numiv; i++) {
if (ivtbl->ivptr[i] != Qundef) {
for (i = 0; i < len; i++) {
if (ptr[i] != Qundef) {
n++;
}
}
......
st_update(generic_iv_tbl, (st_data_t)obj, generic_ivar_update,
(st_data_t)&ivup);
ivup.u.ivtbl->ivptr[ivup.index] = val;
rb_ary_store_fill(ivup.u.ivtbl, ivup.index, val, Qundef);
if (FL_ABLE(obj)) RB_OBJ_WRITTEN(obj, Qundef, val);
if (FL_ABLE(obj)) RB_OBJ_WRITTEN(obj, Qundef, ivup.u.ivtbl);
}
VALUE
......
}
struct gen_ivar_tag {
struct gen_ivtbl *ivtbl;
VALUE ivtbl;
int (*func)(ID key, VALUE val, st_data_t arg);
st_data_t arg;
};
......
{
struct gen_ivar_tag *arg = (struct gen_ivar_tag *)data;
if ((long)index < arg->ivtbl->numiv) {
VALUE val = arg->ivtbl->ivptr[index];
if ((long)index < RARRAY_LEN(arg->ivtbl)) {
VALUE val = RARRAY_AREF(arg->ivtbl, index);
if (val != Qundef) {
return (arg->func)((ID)key, val, arg->arg);
}
......
struct givar_copy {
VALUE obj;
st_table *iv_index_tbl;
struct gen_ivtbl *ivtbl;
VALUE ivtbl;
};
static int
......
ivup.extended = 0;
ivup.u.iv_index_tbl = c->iv_index_tbl;
iv_index_tbl_extend(&ivup, id);
if ((long)ivup.index >= c->ivtbl->numiv) {
size_t newsize = iv_index_tbl_newsize(&ivup);
c->ivtbl = gen_ivtbl_resize(c->ivtbl, newsize);
}
c->ivtbl->ivptr[ivup.index] = val;
rb_ary_store_fill(c->ivtbl, ivup.index, val, Qundef);
if (FL_ABLE(c->obj)) RB_OBJ_WRITTEN(c->obj, Qundef, val);
if (FL_ABLE(c->obj)) RB_OBJ_WRITTEN(c->obj, Qundef, c->ivtbl);
return ST_CONTINUE;
}
......
void
rb_copy_generic_ivar(VALUE clone, VALUE obj)
{
struct gen_ivtbl *ivtbl;
VALUE ivtbl;
rb_check_frozen(clone);
......
}
if (gen_ivtbl_get(obj, &ivtbl)) {
struct givar_copy c;
long i;
if (gen_ivtbl_count(ivtbl) == 0)
goto clear;
if (gen_ivtbl_get(clone, &c.ivtbl)) {
for (i = 0; i < c.ivtbl->numiv; i++)
c.ivtbl->ivptr[i] = Qundef;
rb_ary_clear(c.ivtbl);
}
else {
c.ivtbl = gen_ivtbl_resize(0, ivtbl->numiv);
c.ivtbl = rb_ary_tmp_new(0);
FL_SET(clone, FL_EXIVAR);
st_add_direct(generic_iv_tbl, (st_data_t)clone, (st_data_t)c.ivtbl);
}
c.iv_index_tbl = iv_index_tbl_make(clone);
c.obj = clone;
gen_ivar_each(obj, gen_ivar_copy, (st_data_t)&c);
/*
* c.ivtbl may change in gen_ivar_copy due to realloc,
* no need to free
*/
st_insert(generic_iv_tbl, (st_data_t)clone, (st_data_t)c.ivtbl);
}
}
......
break;
default:
if (FL_TEST(obj, FL_EXIVAR)) {
struct gen_ivtbl *ivtbl;
VALUE ivtbl;
if (gen_ivtbl_get(obj, &ivtbl)) {
return gen_ivtbl_count(ivtbl);
-
    (1-1/1)