[前][次][番号順一覧][スレッド一覧]

ruby-changes:38597

From: normal <ko1@a...>
Date: Sat, 30 May 2015 08:42:58 +0900 (JST)
Subject: [ruby-changes:38597] normal:r50678 (trunk): variable.c: use indices for generic ivars

normal	2015-05-30 08:42:49 +0900 (Sat, 30 May 2015)

  New Revision: 50678

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=50678

  Log:
    variable.c: use indices for generic ivars
    
    This reduces memory overhead of ivars for common types such as
    T_DATA the same way T_OBJECT does it.
    
    For 9992 accepted clients on an OpenSSL server, this reduces
    memory from 77160K to 69248K with the script in
    https://bugs.ruby-lang.org/issues/11170
    
    * variable.c (static int special_generic_ivar): move
      (rb_generic_ivar_table): rewrite for compatibility
      (gen_ivtbl_bytes): new function
      (generic_ivar_get): update to use ivar index
      (generic_ivar_update): ditto
      (generic_ivar_set): ditto
      (generic_ivar_defined): ditto
      (generic_ivar_remove): ditto
      (rb_mark_generic_ivar): ditto
      (givar_i): ditto
      (rb_free_generic_ivar): ditto
      (rb_mark_generic_ivar_tbl): ditto
      (rb_generic_ivar_memsize): ditto
      (rb_copy_generic_ivar): ditto
      (rb_ivar_set): ditto
      (rb_ivar_foreach): ditto
      (rb_ivar_count): ditto
      (givar_mark_i): remove
      (gen_ivtbl_mark): new function
      (gen_ivar_each): ditto
      (iv_index_tbl_extend): update for struct ivar_update
      (iv_index_tbl_newsize): ditto
      [ruby-core:69323] [Feature #11170]

  Modified files:
    trunk/ChangeLog
    trunk/variable.c
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 50677)
+++ ChangeLog	(revision 50678)
@@ -1,3 +1,29 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Sat May 30 08:36:04 2015  Eric Wong  <e@8...>
+
+	* variable.c (static int special_generic_ivar): move
+	  (rb_generic_ivar_table): rewrite for compatibility
+	  (gen_ivtbl_bytes): new function
+	  (generic_ivar_get): update to use ivar index
+	  (generic_ivar_update): ditto
+	  (generic_ivar_set): ditto
+	  (generic_ivar_defined): ditto
+	  (generic_ivar_remove): ditto
+	  (rb_mark_generic_ivar): ditto
+	  (givar_i): ditto
+	  (rb_free_generic_ivar): ditto
+	  (rb_mark_generic_ivar_tbl): ditto
+	  (rb_generic_ivar_memsize): ditto
+	  (rb_copy_generic_ivar): ditto
+	  (rb_ivar_set): ditto
+	  (rb_ivar_foreach): ditto
+	  (rb_ivar_count): ditto
+	  (givar_mark_i): remove
+	  (gen_ivtbl_mark): new function
+	  (gen_ivar_each): ditto
+	  (iv_index_tbl_extend): update for struct ivar_update
+	  (iv_index_tbl_newsize): ditto
+	  [ruby-core:69323] [Feature #11170]
+
 Sat May 30 08:10:46 2015  Eric Wong  <e@8...>
 
 	* variable.c (iv_index_tbl_make): extract from rb_ivar_set
Index: variable.c
===================================================================
--- variable.c	(revision 50677)
+++ variable.c	(revision 50678)
@@ -24,6 +24,23 @@ static void check_before_mod_set(VALUE, https://github.com/ruby/ruby/blob/trunk/variable.c#L24
 static void setup_const_entry(rb_const_entry_t *, VALUE, VALUE, rb_const_flag_t);
 static int const_update(st_data_t *, st_data_t *, st_data_t, int);
 static st_table *generic_iv_tbl;
+static st_table *generic_iv_tbl_compat;
+static int special_generic_ivar;
+
+/* 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;
+    } u;
+    st_data_t index;
+    int extended;
+};
 
 void
 Init_var_tables(void)
@@ -932,124 +949,224 @@ rb_alias_variable(ID name1, ID name2) https://github.com/ruby/ruby/blob/trunk/variable.c#L949
     entry1->var = entry2->var;
 }
 
-static int special_generic_ivar = 0;
+struct gen_ivar_compat_tbl {
+    struct gen_ivtbl *ivtbl;
+    st_table *tbl;
+};
+
+static int
+gen_ivar_compat_tbl_i(st_data_t id, st_data_t index, st_data_t arg)
+{
+    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 (val != Qundef) {
+	    st_add_direct(a->tbl, id, (st_data_t)val);
+	}
+    }
+    return ST_CONTINUE;
+}
+
+static int
+gen_ivtbl_get(VALUE obj, struct gen_ivtbl **ivtbl)
+{
+    st_data_t data;
+
+    if (st_lookup(generic_iv_tbl, (st_data_t)obj, &data)) {
+	*ivtbl = (struct gen_ivtbl *)data;
+	return 1;
+    }
+    return 0;
+}
 
+/* for backwards compatibility only */
 st_table*
 rb_generic_ivar_table(VALUE obj)
 {
-    st_data_t tbl;
+    st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(rb_obj_class(obj));
+    struct gen_ivar_compat_tbl a;
+    st_data_t d;
 
+    if (!iv_index_tbl) return 0;
     if (!FL_TEST(obj, FL_EXIVAR)) return 0;
-    if (!st_lookup(generic_iv_tbl, (st_data_t)obj, &tbl)) return 0;
-    return (st_table *)tbl;
+    if (!gen_ivtbl_get(obj, &a.ivtbl)) return 0;
+
+    a.tbl = 0;
+    if (!generic_iv_tbl_compat) {
+	generic_iv_tbl_compat = st_init_numtable();
+    }
+    else {
+	if (st_lookup(generic_iv_tbl_compat, (st_data_t)obj, &d)) {
+	    a.tbl = (st_table *)d;
+	    st_clear(a.tbl);
+	}
+    }
+    if (!a.tbl) {
+	a.tbl = st_init_numtable();
+	d = (st_data_t)a.tbl;
+	st_add_direct(generic_iv_tbl_compat, (st_data_t)obj, d);
+    }
+    st_foreach_safe(iv_index_tbl, gen_ivar_compat_tbl_i, (st_data_t)&a);
+
+    return a.tbl;
 }
 
 static VALUE
 generic_ivar_get(VALUE obj, ID id, VALUE undef)
 {
-    st_data_t tbl, val;
+    struct gen_ivtbl *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(generic_iv_tbl, (st_data_t)obj, &tbl)) {
-	if (st_lookup((st_table *)tbl, (st_data_t)id, &val)) {
-	    return (VALUE)val;
+	if (st_lookup(iv_index_tbl, (st_data_t)id, &index)) {
+	    if ((long)index < ivtbl->numiv) {
+		VALUE ret = ivtbl->ivptr[index];
+
+		return ret == Qundef ? undef : ret;
+	    }
 	}
     }
     return undef;
 }
 
-static int
-generic_ivar_update(st_data_t *k, st_data_t *v, st_data_t a, int existing)
+static size_t
+gen_ivtbl_bytes(size_t n)
 {
-    VALUE obj = (VALUE)*k;
-    st_table **tbl = (st_table **)a;
+    return sizeof(struct gen_ivtbl) + n * sizeof(VALUE) - sizeof(VALUE);
+}
 
-    if (!existing) {
-	FL_SET(obj, FL_EXIVAR);
-	*v = (st_data_t)(*tbl = st_init_numtable());
-	return ST_CONTINUE;
-    }
-    else {
-	*tbl = (st_table *)*v;
-	return ST_STOP;
+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;
 }
 
-static void
-generic_ivar_set(VALUE obj, ID id, VALUE val)
+struct gen_ivtbl *
+gen_ivtbl_dup(const struct gen_ivtbl *orig)
 {
-    st_table *tbl;
+    size_t s = gen_ivtbl_bytes(orig->numiv);
+    struct gen_ivtbl *ivtbl = xmalloc(s);
 
-    if (rb_special_const_p(obj)) {
-	if (rb_obj_frozen_p(obj)) rb_error_frozen("object");
-	special_generic_ivar = 1;
+    memcpy(ivtbl, orig, s);
+
+    return ivtbl;
+}
+
+static long
+iv_index_tbl_newsize(struct ivar_update *ivup)
+{
+    long newsize = (ivup->index+1) + (ivup->index+1)/4; /* (index+1)*1.25 */
+
+    if (!ivup->extended &&
+        ivup->u.iv_index_tbl->num_entries < (st_index_t)newsize) {
+        newsize = ivup->u.iv_index_tbl->num_entries;
     }
-    if (!st_update(generic_iv_tbl, (st_data_t)obj,
-		   generic_ivar_update, (st_data_t)&tbl)) {
-	st_add_direct(tbl, (st_data_t)id, (st_data_t)val);
+    return newsize;
+}
+
+static int
+generic_ivar_update(st_data_t *k, st_data_t *v, st_data_t u, int existing)
+{
+    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 {
-	st_insert(tbl, (st_data_t)id, (st_data_t)val);
+	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;
     }
-    if (FL_ABLE(obj)) RB_OBJ_WRITTEN(obj, Qundef, val);
+    ivup->u.ivtbl = ivtbl;
+    return ret;
 }
 
 static VALUE
 generic_ivar_defined(VALUE obj, ID id)
 {
-    st_table *tbl;
-    st_data_t data;
+    struct gen_ivtbl *ivtbl;
+    st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(rb_obj_class(obj));
+    st_data_t index;
+
+    if (!iv_index_tbl) return Qfalse;
+    if (!st_lookup(iv_index_tbl, (st_data_t)id, &index)) return Qfalse;
+    if (!gen_ivtbl_get(obj, &ivtbl)) return Qfalse;
 
-    if (!st_lookup(generic_iv_tbl, (st_data_t)obj, &data)) return Qfalse;
-    tbl = (st_table *)data;
-    if (st_lookup(tbl, (st_data_t)id, &data)) {
+    if (((long)index < ivtbl->numiv) && (ivtbl->ivptr[index] != Qundef))
 	return Qtrue;
-    }
+
     return Qfalse;
 }
 
 static int
 generic_ivar_remove(VALUE obj, ID id, st_data_t *valp)
 {
-    st_table *tbl;
-    st_data_t data, key = (st_data_t)id;
-    int status;
+    struct gen_ivtbl *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(generic_iv_tbl, (st_data_t)obj, &data)) return 0;
-    tbl = (st_table *)data;
-    status = st_delete(tbl, &key, valp);
-    if (tbl->num_entries == 0) {
-	key = (st_data_t)obj;
-	st_delete(generic_iv_tbl, &key, &data);
-	st_free_table((st_table *)data);
+    if (!iv_index_tbl) return 0;
+    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;
+	    return 1;
+	}
     }
-    return status;
+    return 0;
 }
 
-void
-rb_mark_generic_ivar(VALUE obj)
+static void
+gen_ivtbl_mark(const struct gen_ivtbl *ivtbl)
 {
-    st_data_t tbl;
+    long i;
 
-    if (st_lookup(generic_iv_tbl, (st_data_t)obj, &tbl)) {
-	rb_mark_tbl((st_table *)tbl);
+    for (i = 0; i < ivtbl->numiv; i++) {
+	rb_gc_mark(ivtbl->ivptr[i]);
     }
 }
 
-static int
-givar_mark_i(st_data_t k, st_data_t v, st_data_t a)
+void
+rb_mark_generic_ivar(VALUE obj)
 {
-    VALUE value = (VALUE)v;
-    rb_gc_mark(value);
-    return ST_CONTINUE;
+    struct gen_ivtbl *ivtbl;
+
+    if (gen_ivtbl_get(obj, &ivtbl)) {
+	gen_ivtbl_mark(ivtbl);
+    }
 }
 
 static int
 givar_i(st_data_t k, st_data_t v, st_data_t a)
 {
     VALUE obj = (VALUE)k;
-    st_table *tbl = (st_table *)v;
     if (rb_special_const_p(obj)) {
-	st_foreach_safe(tbl, givar_mark_i, 0);
+	gen_ivtbl_mark((const struct gen_ivtbl *)v);
     }
     return ST_CONTINUE;
 }
@@ -1064,49 +1181,43 @@ rb_mark_generic_ivar_tbl(void) https://github.com/ruby/ruby/blob/trunk/variable.c#L1181
 void
 rb_free_generic_ivar(VALUE obj)
 {
-    st_data_t key = (st_data_t)obj, tbl;
+    st_data_t key = (st_data_t)obj;
+    struct gen_ivtbl *ivtbl;
+
+    if (st_delete(generic_iv_tbl, &key, (st_data_t *)&ivtbl))
+	xfree(ivtbl);
+
+    if (generic_iv_tbl_compat) {
+	st_table *tbl;
 
-    if (st_delete(generic_iv_tbl, &key, &tbl))
-	st_free_table((st_table *)tbl);
+	if (st_delete(generic_iv_tbl_compat, &key, (st_data_t *)&tbl))
+	    st_free_table(tbl);
+    }
 }
 
 RUBY_FUNC_EXPORTED size_t
 rb_generic_ivar_memsize(VALUE obj)
 {
-    st_data_t tbl;
-    if (st_lookup(generic_iv_tbl, (st_data_t)obj, &tbl))
-	return st_memsize((st_table *)tbl);
+    struct gen_ivtbl *ivtbl;
+
+    if (gen_ivtbl_get(obj, &ivtbl))
+	return gen_ivtbl_bytes(ivtbl->numiv);
     return 0;
 }
 
-void
-rb_copy_generic_ivar(VALUE clone, VALUE obj)
+static size_t
+gen_ivtbl_count(const struct gen_ivtbl *ivtbl)
 {
-    st_data_t data;
+    long i;
+    size_t n = 0;
 
-    if (!FL_TEST(obj, FL_EXIVAR)) {
-      clear:
-        if (FL_TEST(clone, FL_EXIVAR)) {
-            rb_free_generic_ivar(clone);
-            FL_UNSET(clone, FL_EXIVAR);
-        }
-        return;
-    }
-    if (st_lookup(generic_iv_tbl, (st_data_t)obj, &data)) {
-	st_table *tbl = (st_table *)data;
-
-        if (tbl->num_entries == 0)
-            goto clear;
-
-	if (st_lookup(generic_iv_tbl, (st_data_t)clone, &data)) {
-	    st_free_table((st_table *)data);
-	    st_insert(generic_iv_tbl, (st_data_t)clone, (st_data_t)st_copy(tbl));
-	}
-	else {
-	    st_add_direct(generic_iv_tbl, (st_data_t)clone, (st_data_t)st_copy(tbl));
-	    FL_SET(clone, FL_EXIVAR);
+    for (i = 0; i < ivtbl->numiv; i++) {
+	if (ivtbl->ivptr[i] != Qundef) {
+	    n++;
 	}
     }
+
+    return n;
 }
 
 static VALUE
@@ -1176,50 +1287,58 @@ iv_index_tbl_make(VALUE obj) https://github.com/ruby/ruby/blob/trunk/variable.c#L1287
     return iv_index_tbl;
 }
 
-static int
-iv_index_tbl_extend(st_table *iv_index_tbl, ID id, st_data_t *index)
+static void
+iv_index_tbl_extend(struct ivar_update *ivup, ID id)
 {
-    if (st_lookup(iv_index_tbl, (st_data_t)id, index)) {
-	return 0;
+    if (st_lookup(ivup->u.iv_index_tbl, (st_data_t)id, &ivup->index)) {
+	return;
     }
-    *index = iv_index_tbl->num_entries;
-    if (*index >= INT_MAX) {
+    if (ivup->u.iv_index_tbl->num_entries >= INT_MAX) {
 	rb_raise(rb_eArgError, "too many instance variables");
     }
-    st_add_direct(iv_index_tbl, (st_data_t)id, *index);
-    return 1;
+    ivup->index = (st_data_t)ivup->u.iv_index_tbl->num_entries;
+    st_add_direct(ivup->u.iv_index_tbl, (st_data_t)id, ivup->index);
+    ivup->extended = 1;
 }
 
-static long
-iv_index_tbl_newsize(st_table *iv_index_tbl, st_data_t index, int ivar_extended)
+static void
+generic_ivar_set(VALUE obj, ID id, VALUE val)
 {
-    long newsize = (index+1) + (index+1)/4; /* (index+1)*1.25 */
+    struct ivar_update ivup;
 
-    if (!ivar_extended &&
-        iv_index_tbl->num_entries < (st_index_t)newsize) {
-        newsize = iv_index_tbl->num_entries;
+    if (rb_special_const_p(obj)) {
+	if (rb_obj_frozen_p(obj)) rb_error_frozen("object");
+	special_generic_ivar = 1;
     }
-    return newsize;
+
+    ivup.extended = 0;
+    ivup.u.iv_index_tbl = iv_index_tbl_make(obj);
+    iv_index_tbl_extend(&ivup, id);
+    st_update(generic_iv_tbl, (st_data_t)obj, generic_ivar_update,
+	      (st_data_t)&ivup);
+
+    ivup.u.ivtbl->ivptr[ivup.index] = val;
+
+    if (FL_ABLE(obj)) RB_OBJ_WRITTEN(obj, Qundef, val);
 }
 
 VALUE
 rb_ivar_set(VALUE obj, ID id, VALUE val)
 {
-    struct st_table *iv_index_tbl;
-    st_data_t index;
+    struct ivar_update ivup;
     long i, len;
-    int ivar_extended;
 
     rb_check_frozen(obj);
     if (SPECIAL_CONST_P(obj)) goto generic;
     switch (BUILTIN_TYPE(obj)) {
       case T_OBJECT:
-        iv_index_tbl = iv_index_tbl_make(obj);
-        ivar_extended = iv_index_tbl_extend(iv_index_tbl, id, &index);
+        ivup.extended = 0;
+        ivup.u.iv_index_tbl = iv_index_tbl_make(obj);
+        iv_index_tbl_extend(&ivup, id);
         len = ROBJECT_NUMIV(obj);
-        if (len <= (long)index) {
+        if (len <= (long)ivup.index) {
             VALUE *ptr = ROBJECT_IVPTR(obj);
-            if (index < ROBJECT_EMBED_LEN_MAX) {
+            if (ivup.index < ROBJECT_EMBED_LEN_MAX) {
                 RBASIC(obj)->flags |= ROBJECT_EMBED;
                 ptr = ROBJECT(obj)->as.ary;
                 for (i = 0; i < ROBJECT_EMBED_LEN_MAX; i++) {
@@ -1228,8 +1347,7 @@ rb_ivar_set(VALUE obj, ID id, VALUE val) https://github.com/ruby/ruby/blob/trunk/variable.c#L1347
             }
             else {
                 VALUE *newptr;
-                long newsize = iv_index_tbl_newsize(iv_index_tbl, index,
-                                                      ivar_extended);
+                long newsize = iv_index_tbl_newsize(&ivup);
 
                 if (RBASIC(obj)->flags & ROBJECT_EMBED) {
                     newptr = ALLOC_N(VALUE, newsize);
@@ -1244,10 +1362,10 @@ rb_ivar_set(VALUE obj, ID id, VALUE val) https://github.com/ruby/ruby/blob/trunk/variable.c#L1362
                 for (; len < newsize; len++)
                     newptr[len] = Qundef;
                 ROBJECT(obj)->as.heap.numiv = newsize;
-                ROBJECT(obj)->as.heap.iv_index_tbl = iv_index_tbl;
+                ROBJECT(obj)->as.heap.iv_index_tbl = ivup.u.iv_index_tbl;
             }
         }
-        RB_OBJ_WRITE(obj, &ROBJECT_IVPTR(obj)[index], val);
+        RB_OBJ_WRITE(obj, &ROBJECT_IVPTR(obj)[ivup.index], val);
 	break;
       case T_CLASS:
       case T_MODULE:
@@ -1329,6 +1447,113 @@ obj_ivar_each(VALUE obj, int (*func)(ANY https://github.com/ruby/ruby/blob/trunk/variable.c#L1447
     st_foreach_safe(tbl, obj_ivar_i, (st_data_t)&data);
 }
 
+struct gen_ivar_tag {
+    struct gen_ivtbl *ivtbl;
+    int (*func)(ID key, VALUE val, st_data_t arg);
+    st_data_t arg;
+};
+
+static int
+gen_ivar_each_i(st_data_t key, st_data_t index, st_data_t data)
+{
+    struct gen_ivar_tag *arg = (struct gen_ivar_tag *)data;
+
+    if ((long)index < arg->ivtbl->numiv) {
+        VALUE val = arg->ivtbl->ivptr[index];
+        if (val != Qundef) {
+            return (arg->func)((ID)key, val, arg->arg);
+        }
+    }
+    return ST_CONTINUE;
+}
+
+static void
+gen_ivar_each(VALUE obj, int (*func)(ANYARGS), st_data_t arg)
+{
+    struct gen_ivar_tag data;
+    st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(rb_obj_class(obj));
+
+    if (!iv_index_tbl) return;
+    if (!gen_ivtbl_get(obj, &data.ivtbl)) return;
+
+    data.func = (int (*)(ID key, VALUE val, st_data_t arg))func;
+    data.arg = arg;
+
+    st_foreach_safe(iv_index_tbl, gen_ivar_each_i, (st_data_t)&data);
+}
+
+struct givar_copy {
+    VALUE obj;
+    st_table *iv_index_tbl;
+    struct gen_ivtbl *ivtbl;
+};
+
+static int
+gen_ivar_copy(ID id, VALUE val, st_data_t arg)
+{
+    struct givar_copy *c = (struct givar_copy *)arg;
+    struct ivar_update ivup;
+
+    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;
+
+    if (FL_ABLE(c->obj)) RB_OBJ_WRITTEN(c->obj, Qundef, val);
+
+    return ST_CONTINUE;
+}
+
+void
+rb_copy_generic_ivar(VALUE clone, VALUE obj)
+{
+    struct gen_ivtbl *ivtbl;
+
+    if (rb_special_const_p(clone)) {
+	if (rb_obj_frozen_p(clone)) rb_error_frozen("object");
+	special_generic_ivar = 1;
+    }
+
+    if (!FL_TEST(obj, FL_EXIVAR)) {
+      clear:
+        if (FL_TEST(clone, FL_EXIVAR)) {
+            rb_free_generic_ivar(clone);
+            FL_UNSET(clone, FL_EXIVAR);
+        }
+        return;
+    }
+    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;
+	}
+	else {
+	    c.ivtbl = gen_ivtbl_resize(0, ivtbl->numiv);
+	    FL_SET(clone, FL_EXIVAR);
+	}
+
+	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);
+    }
+}
+
 void
 rb_ivar_foreach(VALUE obj, int (*func)(ANYARGS), st_data_t arg)
 {
@@ -1346,11 +1571,7 @@ rb_ivar_foreach(VALUE obj, int (*func)(A https://github.com/ruby/ruby/blob/trunk/variable.c#L1571
       default:
       generic:
 	if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) {
-	    st_data_t tbl;
-
-	    if (st_lookup(generic_iv_tbl, (st_data_t)obj, &tbl)) {
-		st_foreach_safe((st_table *)tbl, func, arg);
-	    }
+	    gen_ivar_each(obj, func, arg);
 	}
 	break;
     }
@@ -1383,11 +1604,10 @@ rb_ivar_count(VALUE obj) https://github.com/ruby/ruby/blob/trunk/variable.c#L1604
       default:
       generic:
 	if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) {
-	    st_data_t data;
+	    struct gen_ivtbl *ivtbl;
 
-	    if (st_lookup(generic_iv_tbl, (st_data_t)obj, &data) &&
-		(tbl = (st_table *)data) != 0) {
-		return tbl->num_entries;
+	    if (gen_ivtbl_get(obj, &ivtbl)) {
+		return gen_ivtbl_count(ivtbl);
 	    }
 	}
 	break;

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]