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
131 131

  
132 132
#define ARY_SET(a, i, v) RARRAY_ASET((assert(!ARY_SHARED_P(a)), (a)), (i), (v))
133 133

  
134
void
135
rb_mem_clear(register VALUE *mem, register long size)
134
static inline void
135
memfill(register VALUE *mem, register long size, register VALUE val)
136 136
{
137 137
    while (size--) {
138
	*mem++ = Qnil;
138
	*mem++ = val;
139 139
    }
140 140
}
141 141

  
142
void
143
rb_mem_clear(register VALUE *mem, register long size)
144
{
145
    memfill(mem, size, Qnil);
146
}
147

  
142 148
static void
143 149
ary_mem_clear(VALUE ary, long beg, long size)
144 150
{
......
147 153
    });
148 154
}
149 155

  
150
static inline void
151
memfill(register VALUE *mem, register long size, register VALUE val)
152
{
153
    while (size--) {
154
	*mem++ = val;
155
    }
156
}
157

  
158 156
static void
159 157
ary_memfill(VALUE ary, long beg, long size, VALUE val)
160 158
{
......
803 801
void
804 802
rb_ary_store(VALUE ary, long idx, VALUE val)
805 803
{
804
    rb_ary_store_fill(ary, idx, val, Qnil);
805
}
806

  
807
void
808
rb_ary_store_fill(VALUE ary, long idx, VALUE val, VALUE fill)
809
{
806 810
    long len = RARRAY_LEN(ary);
807 811

  
808 812
    if (idx < 0) {
......
821 825
	ary_double_capa(ary, idx);
822 826
    }
823 827
    if (idx > len) {
824
	ary_mem_clear(ary, len, idx - len + 1);
828
	ary_memfill(ary, len, idx - len + 1, fill);
825 829
    }
826 830

  
827 831
    if (idx >= len) {
internal.h
639 639
void rb_ary_delete_same(VALUE, VALUE);
640 640
VALUE rb_ary_tmp_new_fill(long capa);
641 641
size_t rb_ary_memsize(VALUE);
642
void rb_ary_store_fill(VALUE ary, long idx, VALUE val, VALUE fill);
642 643
#ifdef __GNUC__
643 644
#define rb_ary_new_from_args(n, ...) \
644 645
    __extension__ ({ \
variable.c
26 26
static st_table *generic_iv_tbl;
27 27
static st_table *generic_iv_tbl_compat;
28 28

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

  
35 29
struct ivar_update {
36 30
    union {
37 31
	st_table *iv_index_tbl;
38
	struct gen_ivtbl *ivtbl;
32
	VALUE ivtbl;
39 33
    } u;
40 34
    st_data_t index;
41 35
    int extended;
......
949 943
}
950 944

  
951 945
struct gen_ivar_compat_tbl {
952
    struct gen_ivtbl *ivtbl;
946
    VALUE ivtbl;
953 947
    st_table *tbl;
954 948
};
955 949

  
......
958 952
{
959 953
    struct gen_ivar_compat_tbl *a = (struct gen_ivar_compat_tbl *)arg;
960 954

  
961
    if ((long)index < a->ivtbl->numiv) {
962
	VALUE val = a->ivtbl->ivptr[index];
955
    if ((long)index < RARRAY_LEN(a->ivtbl)) {
956
	VALUE val = RARRAY_AREF(a->ivtbl, index);
963 957
	if (val != Qundef) {
964 958
	    st_add_direct(a->tbl, id, (st_data_t)val);
965 959
	}
......
968 962
}
969 963

  
970 964
static int
971
gen_ivtbl_get(VALUE obj, struct gen_ivtbl **ivtbl)
965
gen_ivtbl_get(VALUE obj, VALUE *ivtbl)
972 966
{
973 967
    st_data_t data;
974 968

  
975 969
    if (st_lookup(generic_iv_tbl, (st_data_t)obj, &data)) {
976
	*ivtbl = (struct gen_ivtbl *)data;
970
	*ivtbl = (VALUE)data;
977 971
	return 1;
978 972
    }
979 973
    return 0;
......
1014 1008
static VALUE
1015 1009
generic_ivar_delete(VALUE obj, ID id, VALUE undef)
1016 1010
{
1017
    struct gen_ivtbl *ivtbl;
1011
    VALUE ivtbl;
1018 1012

  
1019 1013
    if (gen_ivtbl_get(obj, &ivtbl)) {
1020 1014
	st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(rb_obj_class(obj));
1021 1015
	st_data_t index;
1022 1016

  
1023 1017
	if (st_lookup(iv_index_tbl, (st_data_t)id, &index)) {
1024
	    if ((long)index < ivtbl->numiv) {
1025
		VALUE ret = ivtbl->ivptr[index];
1018
	    if ((long)index < RARRAY_LEN(ivtbl)) {
1019
		VALUE ret = RARRAY_AREF(ivtbl, index);
1026 1020

  
1027
		ivtbl->ivptr[index] = Qundef;
1021
		RARRAY_ASET(ivtbl, index, Qundef);
1028 1022
		return ret == Qundef ? undef : ret;
1029 1023
	    }
1030 1024
	}
......
1035 1029
static VALUE
1036 1030
generic_ivar_get(VALUE obj, ID id, VALUE undef)
1037 1031
{
1038
    struct gen_ivtbl *ivtbl;
1032
    VALUE ivtbl;
1039 1033

  
1040 1034
    if (gen_ivtbl_get(obj, &ivtbl)) {
1041 1035
	st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(rb_obj_class(obj));
1042 1036
	st_data_t index;
1043 1037

  
1044 1038
	if (st_lookup(iv_index_tbl, (st_data_t)id, &index)) {
1045
	    if ((long)index < ivtbl->numiv) {
1046
		VALUE ret = ivtbl->ivptr[index];
1039
	    if ((long)index < RARRAY_LEN(ivtbl)) {
1040
		VALUE ret = RARRAY_AREF(ivtbl, index);
1047 1041

  
1048 1042
		return ret == Qundef ? undef : ret;
1049 1043
	    }
......
1052 1046
    return undef;
1053 1047
}
1054 1048

  
1055
static size_t
1056
gen_ivtbl_bytes(size_t n)
1057
{
1058
    return sizeof(struct gen_ivtbl) + n * sizeof(VALUE) - sizeof(VALUE);
1059
}
1060

  
1061
struct gen_ivtbl *
1062
gen_ivtbl_resize(struct gen_ivtbl *old, long n)
1063
{
1064
    long len = old ? old->numiv : 0;
1065
    struct gen_ivtbl *ivtbl = xrealloc(old, gen_ivtbl_bytes(n));
1066

  
1067
    ivtbl->numiv = n;
1068
    for (; len < n; len++) {
1069
	ivtbl->ivptr[len] = Qundef;
1070
    }
1071

  
1072
    return ivtbl;
1073
}
1074

  
1075
struct gen_ivtbl *
1076
gen_ivtbl_dup(const struct gen_ivtbl *orig)
1077
{
1078
    size_t s = gen_ivtbl_bytes(orig->numiv);
1079
    struct gen_ivtbl *ivtbl = xmalloc(s);
1080

  
1081
    memcpy(ivtbl, orig, s);
1082

  
1083
    return ivtbl;
1084
}
1085

  
1086 1049
static long
1087 1050
iv_index_tbl_newsize(struct ivar_update *ivup)
1088 1051
{
......
1100 1063
{
1101 1064
    VALUE obj = (VALUE)*k;
1102 1065
    struct ivar_update *ivup = (struct ivar_update *)u;
1103
    long newsize;
1104
    int ret = ST_CONTINUE;
1105
    struct gen_ivtbl *ivtbl;
1106 1066

  
1107 1067
    if (existing) {
1108
	ivtbl = (struct gen_ivtbl *)*v;
1109
	if ((long)ivup->index >= ivtbl->numiv) {
1110
	    goto resize;
1111
	}
1112
	ret = ST_STOP;
1113
    }
1114
    else {
1115
	FL_SET(obj, FL_EXIVAR);
1116
	ivtbl = 0;
1117
resize:
1118
	newsize = iv_index_tbl_newsize(ivup);
1119
	ivtbl = gen_ivtbl_resize(ivtbl, newsize);
1120
	*v = (st_data_t)ivtbl;
1068
	ivup->u.ivtbl = (VALUE)*v;
1069
	return ST_STOP;
1121 1070
    }
1122
    ivup->u.ivtbl = ivtbl;
1123
    return ret;
1071

  
1072
    ivup->u.ivtbl = rb_ary_tmp_new(0);
1073
    FL_SET(obj, FL_EXIVAR);
1074
    *v = (st_data_t)ivup->u.ivtbl;
1075
    return ST_CONTINUE;
1124 1076
}
1125 1077

  
1126 1078
static VALUE
1127 1079
generic_ivar_defined(VALUE obj, ID id)
1128 1080
{
1129
    struct gen_ivtbl *ivtbl;
1081
    VALUE ivtbl;
1130 1082
    st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(rb_obj_class(obj));
1131 1083
    st_data_t index;
1132 1084

  
......
1134 1086
    if (!st_lookup(iv_index_tbl, (st_data_t)id, &index)) return Qfalse;
1135 1087
    if (!gen_ivtbl_get(obj, &ivtbl)) return Qfalse;
1136 1088

  
1137
    if (((long)index < ivtbl->numiv) && (ivtbl->ivptr[index] != Qundef))
1089
    if ((long)index < RARRAY_LEN(ivtbl) && RARRAY_AREF(ivtbl, index) != Qundef)
1138 1090
	return Qtrue;
1139 1091

  
1140 1092
    return Qfalse;
......
1143 1095
static int
1144 1096
generic_ivar_remove(VALUE obj, ID id, st_data_t *valp)
1145 1097
{
1146
    struct gen_ivtbl *ivtbl;
1098
    VALUE ivtbl;
1147 1099
    st_data_t key = (st_data_t)id;
1148 1100
    st_data_t index;
1149 1101
    st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(rb_obj_class(obj));
......
1152 1104
    if (!st_lookup(iv_index_tbl, key, &index)) return 0;
1153 1105
    if (!gen_ivtbl_get(obj, &ivtbl)) return 0;
1154 1106

  
1155
    if ((long)index < ivtbl->numiv) {
1156
	if (ivtbl->ivptr[index] != Qundef) {
1157
	    ivtbl->ivptr[index] = Qundef;
1107
    if ((long)index < RARRAY_LEN(ivtbl)) {
1108
	if (RARRAY_AREF(ivtbl, index) != Qundef) {
1109
	    RARRAY_ASET(ivtbl, index, Qundef);
1158 1110
	    return 1;
1159 1111
	}
1160 1112
    }
1161 1113
    return 0;
1162 1114
}
1163 1115

  
1164
static void
1165
gen_ivtbl_mark(const struct gen_ivtbl *ivtbl)
1166
{
1167
    long i;
1168

  
1169
    for (i = 0; i < ivtbl->numiv; i++) {
1170
	rb_gc_mark(ivtbl->ivptr[i]);
1171
    }
1172
}
1173

  
1174 1116
void
1175 1117
rb_mark_generic_ivar(VALUE obj)
1176 1118
{
1177
    struct gen_ivtbl *ivtbl;
1119
    VALUE ivtbl;
1178 1120

  
1179 1121
    if (gen_ivtbl_get(obj, &ivtbl)) {
1180
	gen_ivtbl_mark(ivtbl);
1122
	rb_gc_mark(ivtbl);
1181 1123
    }
1182 1124
}
1183 1125

  
......
1185 1127
rb_free_generic_ivar(VALUE obj)
1186 1128
{
1187 1129
    st_data_t key = (st_data_t)obj;
1188
    struct gen_ivtbl *ivtbl;
1130
    VALUE ivtbl;
1189 1131

  
1190
    if (st_delete(generic_iv_tbl, &key, (st_data_t *)&ivtbl))
1191
	xfree(ivtbl);
1132
    (void)st_delete(generic_iv_tbl, &key, (st_data_t *)&ivtbl);
1133
    /* rb_ary_clear is not suitable here since that can realloc, rely on GC */
1192 1134

  
1193 1135
    if (generic_iv_tbl_compat) {
1194 1136
	st_table *tbl;
......
1201 1143
RUBY_FUNC_EXPORTED size_t
1202 1144
rb_generic_ivar_memsize(VALUE obj)
1203 1145
{
1204
    struct gen_ivtbl *ivtbl;
1146
    VALUE ivtbl;
1205 1147

  
1206 1148
    if (gen_ivtbl_get(obj, &ivtbl))
1207
	return gen_ivtbl_bytes(ivtbl->numiv);
1149
	return rb_ary_memsize(ivtbl);
1208 1150
    return 0;
1209 1151
}
1210 1152

  
1211 1153
static size_t
1212
gen_ivtbl_count(const struct gen_ivtbl *ivtbl)
1154
gen_ivtbl_count(const VALUE ivtbl)
1213 1155
{
1214 1156
    long i;
1215 1157
    size_t n = 0;
1158
    long len = RARRAY_LEN(ivtbl);
1159
    const VALUE *ptr = RARRAY_CONST_PTR(ivtbl);
1216 1160

  
1217
    for (i = 0; i < ivtbl->numiv; i++) {
1218
	if (ivtbl->ivptr[i] != Qundef) {
1161
    for (i = 0; i < len; i++) {
1162
	if (ptr[i] != Qundef) {
1219 1163
	    n++;
1220 1164
	}
1221 1165
    }
......
1355 1299
    st_update(generic_iv_tbl, (st_data_t)obj, generic_ivar_update,
1356 1300
	      (st_data_t)&ivup);
1357 1301

  
1358
    ivup.u.ivtbl->ivptr[ivup.index] = val;
1302
    rb_ary_store_fill(ivup.u.ivtbl, ivup.index, val, Qundef);
1359 1303

  
1360
    if (FL_ABLE(obj)) RB_OBJ_WRITTEN(obj, Qundef, val);
1304
    if (FL_ABLE(obj)) RB_OBJ_WRITTEN(obj, Qundef, ivup.u.ivtbl);
1361 1305
}
1362 1306

  
1363 1307
VALUE
......
1485 1429
}
1486 1430

  
1487 1431
struct gen_ivar_tag {
1488
    struct gen_ivtbl *ivtbl;
1432
    VALUE ivtbl;
1433

  
1489 1434
    int (*func)(ID key, VALUE val, st_data_t arg);
1490 1435
    st_data_t arg;
1491 1436
};
......
1495 1440
{
1496 1441
    struct gen_ivar_tag *arg = (struct gen_ivar_tag *)data;
1497 1442

  
1498
    if ((long)index < arg->ivtbl->numiv) {
1499
        VALUE val = arg->ivtbl->ivptr[index];
1443
    if ((long)index < RARRAY_LEN(arg->ivtbl)) {
1444
        VALUE val = RARRAY_AREF(arg->ivtbl, index);
1500 1445
        if (val != Qundef) {
1501 1446
            return (arg->func)((ID)key, val, arg->arg);
1502 1447
        }
......
1522 1467
struct givar_copy {
1523 1468
    VALUE obj;
1524 1469
    st_table *iv_index_tbl;
1525
    struct gen_ivtbl *ivtbl;
1470
    VALUE ivtbl;
1526 1471
};
1527 1472

  
1528 1473
static int
......
1534 1479
    ivup.extended = 0;
1535 1480
    ivup.u.iv_index_tbl = c->iv_index_tbl;
1536 1481
    iv_index_tbl_extend(&ivup, id);
1537
    if ((long)ivup.index >= c->ivtbl->numiv) {
1538
	size_t newsize = iv_index_tbl_newsize(&ivup);
1539

  
1540
	c->ivtbl = gen_ivtbl_resize(c->ivtbl, newsize);
1541
    }
1542
    c->ivtbl->ivptr[ivup.index] = val;
1482
    rb_ary_store_fill(c->ivtbl, ivup.index, val, Qundef);
1543 1483

  
1544
    if (FL_ABLE(c->obj)) RB_OBJ_WRITTEN(c->obj, Qundef, val);
1484
    if (FL_ABLE(c->obj)) RB_OBJ_WRITTEN(c->obj, Qundef, c->ivtbl);
1545 1485

  
1546 1486
    return ST_CONTINUE;
1547 1487
}
......
1549 1489
void
1550 1490
rb_copy_generic_ivar(VALUE clone, VALUE obj)
1551 1491
{
1552
    struct gen_ivtbl *ivtbl;
1492
    VALUE ivtbl;
1553 1493

  
1554 1494
    rb_check_frozen(clone);
1555 1495

  
......
1563 1503
    }
1564 1504
    if (gen_ivtbl_get(obj, &ivtbl)) {
1565 1505
	struct givar_copy c;
1566
	long i;
1567 1506

  
1568 1507
	if (gen_ivtbl_count(ivtbl) == 0)
1569 1508
	    goto clear;
1570 1509

  
1571 1510
	if (gen_ivtbl_get(clone, &c.ivtbl)) {
1572
	    for (i = 0; i < c.ivtbl->numiv; i++)
1573
		c.ivtbl->ivptr[i] = Qundef;
1511
	    rb_ary_clear(c.ivtbl);
1574 1512
	}
1575 1513
	else {
1576
	    c.ivtbl = gen_ivtbl_resize(0, ivtbl->numiv);
1514
	    c.ivtbl = rb_ary_tmp_new(0);
1577 1515
	    FL_SET(clone, FL_EXIVAR);
1516
	    st_add_direct(generic_iv_tbl, (st_data_t)clone, (st_data_t)c.ivtbl);
1578 1517
	}
1579 1518

  
1580 1519
	c.iv_index_tbl = iv_index_tbl_make(clone);
1581 1520
	c.obj = clone;
1582 1521
	gen_ivar_each(obj, gen_ivar_copy, (st_data_t)&c);
1583
	/*
1584
	 * c.ivtbl may change in gen_ivar_copy due to realloc,
1585
	 * no need to free
1586
	 */
1587
	st_insert(generic_iv_tbl, (st_data_t)clone, (st_data_t)c.ivtbl);
1588 1522
    }
1589 1523
}
1590 1524

  
......
1638 1572
	break;
1639 1573
      default:
1640 1574
	if (FL_TEST(obj, FL_EXIVAR)) {
1641
	    struct gen_ivtbl *ivtbl;
1575
	    VALUE ivtbl;
1642 1576

  
1643 1577
	    if (gen_ivtbl_get(obj, &ivtbl)) {
1644 1578
		return gen_ivtbl_count(ivtbl);
1645
-