Project

General

Profile

Feature #11170 ยป ivar-reduce-combined.patch

normalperson (Eric Wong), 05/23/2015 01:34 AM

View differences:

variable.c
24 24
static void setup_const_entry(rb_const_entry_t *, VALUE, VALUE, rb_const_flag_t);
25 25
static int const_update(st_data_t *, st_data_t *, st_data_t, int);
26 26
static st_table *generic_iv_tbl;
27
static st_table *generic_iv_tbl_compat;
28
static int special_generic_ivar;
29

  
30
/* per-object */
31
struct gen_ivtbl {
32
    long numiv; /* only uses 32-bits */
33
    VALUE ivptr[1];
34
};
35

  
36
struct ivar_update {
37
    union {
38
	st_table *iv_index_tbl;
39
	struct gen_ivtbl *ivtbl;
40
    } u;
41
    st_data_t index;
42
    int extended;
43
};
27 44

  
28 45
void
29 46
Init_var_tables(void)
......
932 949
    entry1->var = entry2->var;
933 950
}
934 951

  
935
static int special_generic_ivar = 0;
952
struct gen_ivar_compat_tbl {
953
    struct gen_ivtbl *ivtbl;
954
    st_table *tbl;
955
};
956

  
957
static int
958
gen_ivar_compat_tbl_i(st_data_t id, st_data_t index, st_data_t arg)
959
{
960
    struct gen_ivar_compat_tbl *a = (struct gen_ivar_compat_tbl *)arg;
961

  
962
    if ((long)index < a->ivtbl->numiv) {
963
	VALUE val = a->ivtbl->ivptr[index];
964
	if (val != Qundef) {
965
	    st_add_direct(a->tbl, id, (st_data_t)val);
966
	}
967
    }
968
    return ST_CONTINUE;
969
}
970

  
971
static int
972
gen_ivtbl_get(VALUE obj, struct gen_ivtbl **ivtbl)
973
{
974
    st_data_t data;
936 975

  
976
    if (st_lookup(generic_iv_tbl, (st_data_t)obj, &data)) {
977
	*ivtbl = (struct gen_ivtbl *)data;
978
	return 1;
979
    }
980
    return 0;
981
}
982

  
983
/* for backwards compatibility only */
937 984
st_table*
938 985
rb_generic_ivar_table(VALUE obj)
939 986
{
940
    st_data_t tbl;
987
    st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(rb_obj_class(obj));
988
    struct gen_ivar_compat_tbl a;
989
    st_data_t d;
941 990

  
991
    if (!iv_index_tbl) return 0;
942 992
    if (!FL_TEST(obj, FL_EXIVAR)) return 0;
943
    if (!st_lookup(generic_iv_tbl, (st_data_t)obj, &tbl)) return 0;
944
    return (st_table *)tbl;
993
    if (!gen_ivtbl_get(obj, &a.ivtbl)) return 0;
994

  
995
    a.tbl = 0;
996
    if (!generic_iv_tbl_compat) {
997
	generic_iv_tbl_compat = st_init_numtable();
998
    }
999
    else {
1000
	if (st_lookup(generic_iv_tbl_compat, (st_data_t)obj, &d)) {
1001
	    a.tbl = (st_table *)d;
1002
	    st_clear(a.tbl);
1003
	}
1004
    }
1005
    if (!a.tbl) {
1006
	a.tbl = st_init_numtable();
1007
	d = (st_data_t)a.tbl;
1008
	st_add_direct(generic_iv_tbl_compat, (st_data_t)obj, d);
1009
    }
1010
    st_foreach_safe(iv_index_tbl, gen_ivar_compat_tbl_i, (st_data_t)&a);
1011

  
1012
    return a.tbl;
945 1013
}
946 1014

  
947 1015
static VALUE
948 1016
generic_ivar_get(VALUE obj, ID id, VALUE undef)
949 1017
{
950
    st_data_t tbl, val;
1018
    struct gen_ivtbl *ivtbl;
1019

  
1020
    if (gen_ivtbl_get(obj, &ivtbl)) {
1021
	st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(rb_obj_class(obj));
1022
	st_data_t index;
1023

  
1024
	if (st_lookup(iv_index_tbl, (st_data_t)id, &index)) {
1025
	    if ((long)index < ivtbl->numiv) {
1026
		VALUE ret = ivtbl->ivptr[index];
951 1027

  
952
    if (st_lookup(generic_iv_tbl, (st_data_t)obj, &tbl)) {
953
	if (st_lookup((st_table *)tbl, (st_data_t)id, &val)) {
954
	    return (VALUE)val;
1028
		return ret == Qundef ? undef : ret;
1029
	    }
955 1030
	}
956 1031
    }
957 1032
    return undef;
958 1033
}
959 1034

  
960
static int
961
generic_ivar_update(st_data_t *k, st_data_t *v, st_data_t a, int existing)
1035
static size_t
1036
gen_ivtbl_bytes(size_t n)
962 1037
{
963
    VALUE obj = (VALUE)*k;
964
    st_table **tbl = (st_table **)a;
1038
    return sizeof(struct gen_ivtbl) + n * sizeof(VALUE) - sizeof(VALUE);
1039
}
965 1040

  
966
    if (!existing) {
967
	FL_SET(obj, FL_EXIVAR);
968
	*v = (st_data_t)(*tbl = st_init_numtable());
969
	return ST_CONTINUE;
970
    }
971
    else {
972
	*tbl = (st_table *)*v;
973
	return ST_STOP;
1041
struct gen_ivtbl *
1042
gen_ivtbl_resize(struct gen_ivtbl *old, long n)
1043
{
1044
    long len = old ? old->numiv : 0;
1045
    struct gen_ivtbl *ivtbl = xrealloc(old, gen_ivtbl_bytes(n));
1046

  
1047
    ivtbl->numiv = n;
1048
    for (; len < n; len++) {
1049
	ivtbl->ivptr[len] = Qundef;
974 1050
    }
1051

  
1052
    return ivtbl;
975 1053
}
976 1054

  
977
static void
978
generic_ivar_set(VALUE obj, ID id, VALUE val)
1055
struct gen_ivtbl *
1056
gen_ivtbl_dup(const struct gen_ivtbl *orig)
979 1057
{
980
    st_table *tbl;
1058
    size_t s = gen_ivtbl_bytes(orig->numiv);
1059
    struct gen_ivtbl *ivtbl = xmalloc(s);
981 1060

  
982
    if (rb_special_const_p(obj)) {
983
	if (rb_obj_frozen_p(obj)) rb_error_frozen("object");
984
	special_generic_ivar = 1;
1061
    memcpy(ivtbl, orig, s);
1062

  
1063
    return ivtbl;
1064
}
1065

  
1066
static long
1067
iv_index_tbl_newsize(struct ivar_update *ivup)
1068
{
1069
    long newsize = (ivup->index+1) + (ivup->index+1)/4; /* (index+1)*1.25 */
1070

  
1071
    if (!ivup->extended &&
1072
        ivup->u.iv_index_tbl->num_entries < (st_index_t)newsize) {
1073
        newsize = ivup->u.iv_index_tbl->num_entries;
985 1074
    }
986
    if (!st_update(generic_iv_tbl, (st_data_t)obj,
987
		   generic_ivar_update, (st_data_t)&tbl)) {
988
	st_add_direct(tbl, (st_data_t)id, (st_data_t)val);
1075
    return newsize;
1076
}
1077

  
1078
static int
1079
generic_ivar_update(st_data_t *k, st_data_t *v, st_data_t u, int existing)
1080
{
1081
    VALUE obj = (VALUE)*k;
1082
    struct ivar_update *ivup = (struct ivar_update *)u;
1083
    long newsize;
1084
    int ret = ST_CONTINUE;
1085
    struct gen_ivtbl *ivtbl;
1086

  
1087
    if (existing) {
1088
	ivtbl = (struct gen_ivtbl *)*v;
1089
	if ((long)ivup->index >= ivtbl->numiv) {
1090
	    goto resize;
1091
	}
1092
	ret = ST_STOP;
989 1093
    }
990 1094
    else {
991
	st_insert(tbl, (st_data_t)id, (st_data_t)val);
1095
	FL_SET(obj, FL_EXIVAR);
1096
	ivtbl = 0;
1097
resize:
1098
	newsize = iv_index_tbl_newsize(ivup);
1099
	ivtbl = gen_ivtbl_resize(ivtbl, newsize);
1100
	*v = (st_data_t)ivtbl;
992 1101
    }
993
    if (FL_ABLE(obj)) RB_OBJ_WRITTEN(obj, Qundef, val);
1102
    ivup->u.ivtbl = ivtbl;
1103
    return ret;
994 1104
}
995 1105

  
996 1106
static VALUE
997 1107
generic_ivar_defined(VALUE obj, ID id)
998 1108
{
999
    st_table *tbl;
1000
    st_data_t data;
1109
    struct gen_ivtbl *ivtbl;
1110
    st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(rb_obj_class(obj));
1111
    st_data_t index;
1001 1112

  
1002
    if (!st_lookup(generic_iv_tbl, (st_data_t)obj, &data)) return Qfalse;
1003
    tbl = (st_table *)data;
1004
    if (st_lookup(tbl, (st_data_t)id, &data)) {
1113
    if (!iv_index_tbl) return Qfalse;
1114
    if (!st_lookup(iv_index_tbl, (st_data_t)id, &index)) return Qfalse;
1115
    if (!gen_ivtbl_get(obj, &ivtbl)) return Qfalse;
1116

  
1117
    if (((long)index < ivtbl->numiv) && (ivtbl->ivptr[index] != Qundef))
1005 1118
	return Qtrue;
1006
    }
1119

  
1007 1120
    return Qfalse;
1008 1121
}
1009 1122

  
1010 1123
static int
1011 1124
generic_ivar_remove(VALUE obj, ID id, st_data_t *valp)
1012 1125
{
1013
    st_table *tbl;
1014
    st_data_t data, key = (st_data_t)id;
1015
    int status;
1126
    struct gen_ivtbl *ivtbl;
1127
    st_data_t key = (st_data_t)id;
1128
    st_data_t index;
1129
    st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(rb_obj_class(obj));
1130

  
1131
    if (!iv_index_tbl) return 0;
1132
    if (!st_lookup(iv_index_tbl, key, &index)) return 0;
1133
    if (!gen_ivtbl_get(obj, &ivtbl)) return 0;
1016 1134

  
1017
    if (!st_lookup(generic_iv_tbl, (st_data_t)obj, &data)) return 0;
1018
    tbl = (st_table *)data;
1019
    status = st_delete(tbl, &key, valp);
1020
    if (tbl->num_entries == 0) {
1021
	key = (st_data_t)obj;
1022
	st_delete(generic_iv_tbl, &key, &data);
1023
	st_free_table((st_table *)data);
1135
    if ((long)index < ivtbl->numiv) {
1136
	if (ivtbl->ivptr[index] != Qundef) {
1137
	    ivtbl->ivptr[index] = Qundef;
1138
	    return 1;
1139
	}
1024 1140
    }
1025
    return status;
1141
    return 0;
1026 1142
}
1027 1143

  
1028
void
1029
rb_mark_generic_ivar(VALUE obj)
1144
static void
1145
gen_ivtbl_mark(const struct gen_ivtbl *ivtbl)
1030 1146
{
1031
    st_data_t tbl;
1147
    long i;
1032 1148

  
1033
    if (st_lookup(generic_iv_tbl, (st_data_t)obj, &tbl)) {
1034
	rb_mark_tbl((st_table *)tbl);
1149
    for (i = 0; i < ivtbl->numiv; i++) {
1150
	rb_gc_mark(ivtbl->ivptr[i]);
1035 1151
    }
1036 1152
}
1037 1153

  
1038
static int
1039
givar_mark_i(st_data_t k, st_data_t v, st_data_t a)
1154
void
1155
rb_mark_generic_ivar(VALUE obj)
1040 1156
{
1041
    VALUE value = (VALUE)v;
1042
    rb_gc_mark(value);
1043
    return ST_CONTINUE;
1157
    struct gen_ivtbl *ivtbl;
1158

  
1159
    if (gen_ivtbl_get(obj, &ivtbl)) {
1160
	gen_ivtbl_mark(ivtbl);
1161
    }
1044 1162
}
1045 1163

  
1046 1164
static int
1047
givar_i(st_data_t k, st_data_t v, st_data_t a)
1165
gen_ivar_i(st_data_t k, st_data_t v, st_data_t a)
1048 1166
{
1049 1167
    VALUE obj = (VALUE)k;
1050
    st_table *tbl = (st_table *)v;
1051 1168
    if (rb_special_const_p(obj)) {
1052
	st_foreach_safe(tbl, givar_mark_i, 0);
1169
	gen_ivtbl_mark((const struct gen_ivtbl *)v);
1053 1170
    }
1054 1171
    return ST_CONTINUE;
1055 1172
}
......
1058 1175
rb_mark_generic_ivar_tbl(void)
1059 1176
{
1060 1177
    if (special_generic_ivar == 0) return;
1061
    st_foreach_safe(generic_iv_tbl, givar_i, 0);
1178
    st_foreach_safe(generic_iv_tbl, gen_ivar_i, 0);
1062 1179
}
1063 1180

  
1064 1181
void
1065 1182
rb_free_generic_ivar(VALUE obj)
1066 1183
{
1067
    st_data_t key = (st_data_t)obj, tbl;
1184
    st_data_t key = (st_data_t)obj;
1185
    struct gen_ivtbl *ivtbl;
1186

  
1187
    if (st_delete(generic_iv_tbl, &key, (st_data_t *)&ivtbl))
1188
	xfree(ivtbl);
1068 1189

  
1069
    if (st_delete(generic_iv_tbl, &key, &tbl))
1070
	st_free_table((st_table *)tbl);
1190
    if (generic_iv_tbl_compat) {
1191
	st_table *tbl;
1192

  
1193
	if (st_delete(generic_iv_tbl_compat, &key, (st_data_t *)&tbl))
1194
	    st_free_table(tbl);
1195
    }
1071 1196
}
1072 1197

  
1073 1198
RUBY_FUNC_EXPORTED size_t
1074 1199
rb_generic_ivar_memsize(VALUE obj)
1075 1200
{
1076
    st_data_t tbl;
1077
    if (st_lookup(generic_iv_tbl, (st_data_t)obj, &tbl))
1078
	return st_memsize((st_table *)tbl);
1201
    struct gen_ivtbl *ivtbl;
1202

  
1203
    if (gen_ivtbl_get(obj, &ivtbl))
1204
	return gen_ivtbl_bytes(ivtbl->numiv);
1079 1205
    return 0;
1080 1206
}
1081 1207

  
1082
void
1083
rb_copy_generic_ivar(VALUE clone, VALUE obj)
1208
static size_t
1209
gen_ivtbl_count(const struct gen_ivtbl *ivtbl)
1084 1210
{
1085
    st_data_t data;
1086

  
1087
    if (!FL_TEST(obj, FL_EXIVAR)) {
1088
      clear:
1089
        if (FL_TEST(clone, FL_EXIVAR)) {
1090
            rb_free_generic_ivar(clone);
1091
            FL_UNSET(clone, FL_EXIVAR);
1092
        }
1093
        return;
1094
    }
1095
    if (st_lookup(generic_iv_tbl, (st_data_t)obj, &data)) {
1096
	st_table *tbl = (st_table *)data;
1211
    long i;
1212
    size_t n = 0;
1097 1213

  
1098
        if (tbl->num_entries == 0)
1099
            goto clear;
1100

  
1101
	if (st_lookup(generic_iv_tbl, (st_data_t)clone, &data)) {
1102
	    st_free_table((st_table *)data);
1103
	    st_insert(generic_iv_tbl, (st_data_t)clone, (st_data_t)st_copy(tbl));
1104
	}
1105
	else {
1106
	    st_add_direct(generic_iv_tbl, (st_data_t)clone, (st_data_t)st_copy(tbl));
1107
	    FL_SET(clone, FL_EXIVAR);
1214
    for (i = 0; i < ivtbl->numiv; i++) {
1215
	if (ivtbl->ivptr[i] != Qundef) {
1216
	    n++;
1108 1217
	}
1109 1218
    }
1219

  
1220
    return n;
1110 1221
}
1111 1222

  
1112 1223
static VALUE
......
1163 1274
    return rb_ivar_lookup(obj, id, Qnil);
1164 1275
}
1165 1276

  
1277
static st_table *
1278
iv_index_tbl_make(VALUE obj)
1279
{
1280
    VALUE klass = rb_obj_class(obj);
1281
    st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(klass);
1282

  
1283
    if (!iv_index_tbl) {
1284
	iv_index_tbl = RCLASS_IV_INDEX_TBL(klass) = st_init_numtable();
1285
    }
1286

  
1287
    return iv_index_tbl;
1288
}
1289

  
1290
static void
1291
iv_index_tbl_extend(struct ivar_update *ivup, ID id)
1292
{
1293
    if (st_lookup(ivup->u.iv_index_tbl, (st_data_t)id, &ivup->index)) {
1294
	return;
1295
    }
1296
    if (ivup->u.iv_index_tbl->num_entries >= INT_MAX) {
1297
	rb_raise(rb_eArgError, "too many instance variables");
1298
    }
1299
    ivup->index = (st_data_t)ivup->u.iv_index_tbl->num_entries;
1300
    st_add_direct(ivup->u.iv_index_tbl, (st_data_t)id, ivup->index);
1301
    ivup->extended = 1;
1302
}
1303

  
1304
static void
1305
generic_ivar_set(VALUE obj, ID id, VALUE val)
1306
{
1307
    struct ivar_update ivup;
1308

  
1309
    if (rb_special_const_p(obj)) {
1310
	if (rb_obj_frozen_p(obj)) rb_error_frozen("object");
1311
	special_generic_ivar = 1;
1312
    }
1313

  
1314
    ivup.extended = 0;
1315
    ivup.u.iv_index_tbl = iv_index_tbl_make(obj);
1316
    iv_index_tbl_extend(&ivup, id);
1317
    st_update(generic_iv_tbl, (st_data_t)obj, generic_ivar_update,
1318
	      (st_data_t)&ivup);
1319

  
1320
    ivup.u.ivtbl->ivptr[ivup.index] = val;
1321

  
1322
    if (FL_ABLE(obj)) RB_OBJ_WRITTEN(obj, Qundef, val);
1323
}
1324

  
1166 1325
VALUE
1167 1326
rb_ivar_set(VALUE obj, ID id, VALUE val)
1168 1327
{
1169
    struct st_table *iv_index_tbl;
1170
    st_data_t index;
1328
    struct ivar_update ivup;
1171 1329
    long i, len;
1172
    int ivar_extended;
1173 1330

  
1174 1331
    rb_check_frozen(obj);
1175 1332
    if (SPECIAL_CONST_P(obj)) goto generic;
1176 1333
    switch (BUILTIN_TYPE(obj)) {
1177 1334
      case T_OBJECT:
1178
        iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
1179
        if (!iv_index_tbl) {
1180
            VALUE klass = rb_obj_class(obj);
1181
            iv_index_tbl = RCLASS_IV_INDEX_TBL(klass);
1182
            if (!iv_index_tbl) {
1183
                iv_index_tbl = RCLASS_IV_INDEX_TBL(klass) = st_init_numtable();
1184
            }
1185
        }
1186
        ivar_extended = 0;
1187
        if (!st_lookup(iv_index_tbl, (st_data_t)id, &index)) {
1188
            index = iv_index_tbl->num_entries;
1189
	    if (index >= INT_MAX) rb_raise(rb_eArgError, "too many instance variables");
1190
            st_add_direct(iv_index_tbl, (st_data_t)id, index);
1191
            ivar_extended = 1;
1192
        }
1335
        ivup.extended = 0;
1336
        ivup.u.iv_index_tbl = iv_index_tbl_make(obj);
1337
        iv_index_tbl_extend(&ivup, id);
1193 1338
        len = ROBJECT_NUMIV(obj);
1194
        if (len <= (long)index) {
1339
        if (len <= (long)ivup.index) {
1195 1340
            VALUE *ptr = ROBJECT_IVPTR(obj);
1196
            if (index < ROBJECT_EMBED_LEN_MAX) {
1341
            if (ivup.index < ROBJECT_EMBED_LEN_MAX) {
1197 1342
                RBASIC(obj)->flags |= ROBJECT_EMBED;
1198 1343
                ptr = ROBJECT(obj)->as.ary;
1199 1344
                for (i = 0; i < ROBJECT_EMBED_LEN_MAX; i++) {
......
1202 1347
            }
1203 1348
            else {
1204 1349
                VALUE *newptr;
1205
                long newsize = (index+1) + (index+1)/4; /* (index+1)*1.25 */
1206
                if (!ivar_extended &&
1207
                    iv_index_tbl->num_entries < (st_index_t)newsize) {
1208
                    newsize = iv_index_tbl->num_entries;
1209
                }
1350
                long newsize = iv_index_tbl_newsize(&ivup);
1210 1351

  
1211 1352
                if (RBASIC(obj)->flags & ROBJECT_EMBED) {
1212 1353
                    newptr = ALLOC_N(VALUE, newsize);
......
1221 1362
                for (; len < newsize; len++)
1222 1363
                    newptr[len] = Qundef;
1223 1364
                ROBJECT(obj)->as.heap.numiv = newsize;
1224
                ROBJECT(obj)->as.heap.iv_index_tbl = iv_index_tbl;
1365
                ROBJECT(obj)->as.heap.iv_index_tbl = ivup.u.iv_index_tbl;
1225 1366
            }
1226 1367
        }
1227
        RB_OBJ_WRITE(obj, &ROBJECT_IVPTR(obj)[index], val);
1368
        RB_OBJ_WRITE(obj, &ROBJECT_IVPTR(obj)[ivup.index], val);
1228 1369
	break;
1229 1370
      case T_CLASS:
1230 1371
      case T_MODULE:
......
1306 1447
    st_foreach_safe(tbl, obj_ivar_i, (st_data_t)&data);
1307 1448
}
1308 1449

  
1450
struct gen_ivar_tag {
1451
    struct gen_ivtbl *ivtbl;
1452
    int (*func)(ID key, VALUE val, st_data_t arg);
1453
    st_data_t arg;
1454
};
1455

  
1456
static int
1457
gen_ivar_each_i(st_data_t key, st_data_t index, st_data_t data)
1458
{
1459
    struct gen_ivar_tag *arg = (struct gen_ivar_tag *)data;
1460

  
1461
    if ((long)index < arg->ivtbl->numiv) {
1462
        VALUE val = arg->ivtbl->ivptr[index];
1463
        if (val != Qundef) {
1464
            return (arg->func)((ID)key, val, arg->arg);
1465
        }
1466
    }
1467
    return ST_CONTINUE;
1468
}
1469

  
1470
static void
1471
gen_ivar_each(VALUE obj, int (*func)(ANYARGS), st_data_t arg)
1472
{
1473
    struct gen_ivar_tag data;
1474
    st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(rb_obj_class(obj));
1475

  
1476
    if (!iv_index_tbl) return;
1477
    if (!gen_ivtbl_get(obj, &data.ivtbl)) return;
1478

  
1479
    data.func = (int (*)(ID key, VALUE val, st_data_t arg))func;
1480
    data.arg = arg;
1481

  
1482
    st_foreach_safe(iv_index_tbl, gen_ivar_each_i, (st_data_t)&data);
1483
}
1484

  
1485
struct givar_copy {
1486
    VALUE obj;
1487
    st_table *iv_index_tbl;
1488
    struct gen_ivtbl *ivtbl;
1489
};
1490

  
1491
static int
1492
gen_ivar_copy(ID id, VALUE val, st_data_t arg)
1493
{
1494
    struct givar_copy *c = (struct givar_copy *)arg;
1495
    struct ivar_update ivup;
1496

  
1497
    ivup.extended = 0;
1498
    ivup.u.iv_index_tbl = c->iv_index_tbl;
1499
    iv_index_tbl_extend(&ivup, id);
1500
    if ((long)ivup.index >= c->ivtbl->numiv) {
1501
	size_t newsize = iv_index_tbl_newsize(&ivup);
1502

  
1503
	c->ivtbl = gen_ivtbl_resize(c->ivtbl, newsize);
1504
    }
1505
    c->ivtbl->ivptr[ivup.index] = val;
1506

  
1507
    if (FL_ABLE(c->obj)) RB_OBJ_WRITTEN(c->obj, Qundef, val);
1508

  
1509
    return ST_CONTINUE;
1510
}
1511

  
1512
void
1513
rb_copy_generic_ivar(VALUE clone, VALUE obj)
1514
{
1515
    struct gen_ivtbl *ivtbl;
1516

  
1517
    if (rb_special_const_p(clone)) {
1518
	if (rb_obj_frozen_p(clone)) rb_error_frozen("object");
1519
	special_generic_ivar = 1;
1520
    }
1521

  
1522
    if (!FL_TEST(obj, FL_EXIVAR)) {
1523
      clear:
1524
        if (FL_TEST(clone, FL_EXIVAR)) {
1525
            rb_free_generic_ivar(clone);
1526
            FL_UNSET(clone, FL_EXIVAR);
1527
        }
1528
        return;
1529
    }
1530
    if (gen_ivtbl_get(obj, &ivtbl)) {
1531
	struct givar_copy c;
1532
	long i;
1533

  
1534
	if (gen_ivtbl_count(ivtbl) == 0)
1535
	    goto clear;
1536

  
1537
	if (gen_ivtbl_get(clone, &c.ivtbl)) {
1538
	    for (i = 0; i < c.ivtbl->numiv; i++)
1539
		c.ivtbl->ivptr[i] = Qundef;
1540
	}
1541
	else {
1542
	    c.ivtbl = gen_ivtbl_resize(0, ivtbl->numiv);
1543
	    FL_SET(clone, FL_EXIVAR);
1544
	}
1545

  
1546
	c.iv_index_tbl = iv_index_tbl_make(clone);
1547
	c.obj = clone;
1548
	gen_ivar_each(obj, gen_ivar_copy, (st_data_t)&c);
1549
	/*
1550
	 * c.ivtbl may change in gen_ivar_copy due to realloc,
1551
	 * no need to free
1552
	 */
1553
	st_insert(generic_iv_tbl, (st_data_t)clone, (st_data_t)c.ivtbl);
1554
    }
1555
}
1556

  
1309 1557
void
1310 1558
rb_ivar_foreach(VALUE obj, int (*func)(ANYARGS), st_data_t arg)
1311 1559
{
......
1323 1571
      default:
1324 1572
      generic:
1325 1573
	if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) {
1326
	    st_data_t tbl;
1327

  
1328
	    if (st_lookup(generic_iv_tbl, (st_data_t)obj, &tbl)) {
1329
		st_foreach_safe((st_table *)tbl, func, arg);
1330
	    }
1574
	    gen_ivar_each(obj, func, arg);
1331 1575
	}
1332 1576
	break;
1333 1577
    }
......
1360 1604
      default:
1361 1605
      generic:
1362 1606
	if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj)) {
1363
	    st_data_t data;
1607
	    struct gen_ivtbl *ivtbl;
1364 1608

  
1365
	    if (st_lookup(generic_iv_tbl, (st_data_t)obj, &data) &&
1366
		(tbl = (st_table *)data) != 0) {
1367
		return tbl->num_entries;
1609
	    if (gen_ivtbl_get(obj, &ivtbl)) {
1610
		return gen_ivtbl_count(ivtbl);
1368 1611
	    }
1369 1612
	}
1370 1613
	break;