variable.c: avoid compatibility table with generic ivars
This recovers and improves performance of Marshal.dump/load on Time objects compared to when we implemented generic ivars entirely using st_table. This also recovers some performance on other generic ivar objects, but does not bring bring Marshal.dump/load performance up to previous speeds. benchmark results: minimum results in each 10 measurements. Execution time (sec) name trunk geniv after marshal_dump_flo 0.343 0.334 0.335 marshal_dump_load_geniv 0.487 0.527 0.495 marshal_dump_load_time 1.262 1.401 1.257 Speedup ratio: compare with the result of `trunk' (greater is better) name geniv after marshal_dump_flo 1.026 1.023 marshal_dump_load_geniv 0.925 0.985 marshal_dump_load_time 0.901 1.004 * include/ruby/intern.h (rb_generic_ivar_table): deprecate * internal.h (rb_attr_delete): declare * marshal.c (has_ivars): use rb_ivar_foreach (w_ivar): ditto (w_object): update for new interface * time.c (time_mload): use rb_attr_delete * variable.c (generic_ivar_delete): implement (rb_ivar_delete): ditto (rb_attr_delete): ditto [ruby-core:69323] [Feature #11170] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@50680 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
c7ddf9d516
commit
f6cd582505
13
ChangeLog
13
ChangeLog
@ -1,3 +1,16 @@
|
|||||||
|
Sat May 30 09:02:51 2015 Eric Wong <e@80x24.org>
|
||||||
|
|
||||||
|
* include/ruby/intern.h (rb_generic_ivar_table): deprecate
|
||||||
|
* internal.h (rb_attr_delete): declare
|
||||||
|
* marshal.c (has_ivars): use rb_ivar_foreach
|
||||||
|
(w_ivar): ditto
|
||||||
|
(w_object): update for new interface
|
||||||
|
* time.c (time_mload): use rb_attr_delete
|
||||||
|
* variable.c (generic_ivar_delete): implement
|
||||||
|
(rb_ivar_delete): ditto
|
||||||
|
(rb_attr_delete): ditto
|
||||||
|
[ruby-core:69323] [Feature #11170]
|
||||||
|
|
||||||
Sat May 30 09:14:28 2015 Scott Francis <scott.francis@shopify.com>
|
Sat May 30 09:14:28 2015 Scott Francis <scott.francis@shopify.com>
|
||||||
|
|
||||||
* cont.c (cont_free): check if ruby_current_thread is still valid.
|
* cont.c (cont_free): check if ruby_current_thread is still valid.
|
||||||
|
10
benchmark/bm_marshal_dump_load_geniv.rb
Normal file
10
benchmark/bm_marshal_dump_load_geniv.rb
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
a = ''
|
||||||
|
a.instance_eval do
|
||||||
|
@a = :a
|
||||||
|
@b = :b
|
||||||
|
@c = :c
|
||||||
|
end
|
||||||
|
100000.times do
|
||||||
|
a = Marshal.load(Marshal.dump(a))
|
||||||
|
end
|
||||||
|
#p(a.instance_eval { @a == :a && @b == :b && @c == :c })
|
1
benchmark/bm_marshal_dump_load_time.rb
Normal file
1
benchmark/bm_marshal_dump_load_time.rb
Normal file
@ -0,0 +1 @@
|
|||||||
|
100000.times { Marshal.load(Marshal.dump(Time.now)) }
|
@ -936,7 +936,7 @@ VALUE rb_f_trace_var(int, const VALUE*);
|
|||||||
VALUE rb_f_untrace_var(int, const VALUE*);
|
VALUE rb_f_untrace_var(int, const VALUE*);
|
||||||
VALUE rb_f_global_variables(void);
|
VALUE rb_f_global_variables(void);
|
||||||
void rb_alias_variable(ID, ID);
|
void rb_alias_variable(ID, ID);
|
||||||
struct st_table* rb_generic_ivar_table(VALUE);
|
DEPRECATED(struct st_table* rb_generic_ivar_table(VALUE));
|
||||||
void rb_copy_generic_ivar(VALUE,VALUE);
|
void rb_copy_generic_ivar(VALUE,VALUE);
|
||||||
void rb_free_generic_ivar(VALUE);
|
void rb_free_generic_ivar(VALUE);
|
||||||
VALUE rb_ivar_get(VALUE, ID);
|
VALUE rb_ivar_get(VALUE, ID);
|
||||||
|
@ -1142,6 +1142,7 @@ extern rb_encoding OnigEncodingUTF_8;
|
|||||||
/* variable.c */
|
/* variable.c */
|
||||||
size_t rb_generic_ivar_memsize(VALUE);
|
size_t rb_generic_ivar_memsize(VALUE);
|
||||||
VALUE rb_search_class_path(VALUE);
|
VALUE rb_search_class_path(VALUE);
|
||||||
|
VALUE rb_attr_delete(VALUE, ID);
|
||||||
|
|
||||||
/* version.c */
|
/* version.c */
|
||||||
extern VALUE ruby_engine_name;
|
extern VALUE ruby_engine_name;
|
||||||
|
45
marshal.c
45
marshal.c
@ -594,24 +594,33 @@ w_encoding(VALUE encname, struct dump_call_arg *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static st_index_t
|
static st_index_t
|
||||||
has_ivars(VALUE obj, VALUE encname, st_table **ivtbl)
|
has_ivars(VALUE obj, VALUE encname, VALUE *ivobj)
|
||||||
{
|
{
|
||||||
st_index_t num = !NIL_P(encname);
|
st_index_t enc = !NIL_P(encname);
|
||||||
|
st_index_t num = 0;
|
||||||
|
|
||||||
*ivtbl = rb_generic_ivar_table(obj);
|
if (SPECIAL_CONST_P(obj)) goto generic;
|
||||||
if (*ivtbl) {
|
switch (BUILTIN_TYPE(obj)) {
|
||||||
st_foreach_safe(*ivtbl, obj_count_ivars, (st_data_t)&num);
|
case T_OBJECT:
|
||||||
|
case T_CLASS:
|
||||||
|
case T_MODULE:
|
||||||
|
break; /* counted elsewhere */
|
||||||
|
default:
|
||||||
|
generic:
|
||||||
|
rb_ivar_foreach(obj, obj_count_ivars, (st_data_t)&num);
|
||||||
|
if (num) *ivobj = obj;
|
||||||
}
|
}
|
||||||
return num;
|
|
||||||
|
return num + enc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
w_ivar(st_index_t num, st_table *tbl, VALUE encname, struct dump_call_arg *arg)
|
w_ivar(st_index_t num, VALUE ivobj, VALUE encname, struct dump_call_arg *arg)
|
||||||
{
|
{
|
||||||
w_long(num, arg->arg);
|
w_long(num, arg->arg);
|
||||||
w_encoding(encname, arg);
|
w_encoding(encname, arg);
|
||||||
if (tbl) {
|
if (ivobj != Qundef) {
|
||||||
st_foreach_safe(tbl, w_obj_each, (st_data_t)arg);
|
rb_ivar_foreach(ivobj, w_obj_each, (st_data_t)arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -638,7 +647,7 @@ static void
|
|||||||
w_object(VALUE obj, struct dump_arg *arg, int limit)
|
w_object(VALUE obj, struct dump_arg *arg, int limit)
|
||||||
{
|
{
|
||||||
struct dump_call_arg c_arg;
|
struct dump_call_arg c_arg;
|
||||||
st_table *ivtbl = 0;
|
VALUE ivobj = Qundef;
|
||||||
st_data_t num;
|
st_data_t num;
|
||||||
st_index_t hasiv = 0;
|
st_index_t hasiv = 0;
|
||||||
VALUE encname = Qnil;
|
VALUE encname = Qnil;
|
||||||
@ -708,7 +717,7 @@ w_object(VALUE obj, struct dump_arg *arg, int limit)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (rb_obj_respond_to(obj, s_dump, TRUE)) {
|
if (rb_obj_respond_to(obj, s_dump, TRUE)) {
|
||||||
st_table *ivtbl2 = 0;
|
VALUE ivobj2 = Qundef;
|
||||||
st_index_t hasiv2;
|
st_index_t hasiv2;
|
||||||
VALUE encname2;
|
VALUE encname2;
|
||||||
|
|
||||||
@ -718,18 +727,18 @@ w_object(VALUE obj, struct dump_arg *arg, int limit)
|
|||||||
if (!RB_TYPE_P(v, T_STRING)) {
|
if (!RB_TYPE_P(v, T_STRING)) {
|
||||||
rb_raise(rb_eTypeError, "_dump() must return string");
|
rb_raise(rb_eTypeError, "_dump() must return string");
|
||||||
}
|
}
|
||||||
hasiv = has_ivars(obj, (encname = encoding_name(obj, arg)), &ivtbl);
|
hasiv = has_ivars(obj, (encname = encoding_name(obj, arg)), &ivobj);
|
||||||
hasiv2 = has_ivars(v, (encname2 = encoding_name(v, arg)), &ivtbl2);
|
hasiv2 = has_ivars(v, (encname2 = encoding_name(v, arg)), &ivobj2);
|
||||||
if (hasiv2) {
|
if (hasiv2) {
|
||||||
hasiv = hasiv2;
|
hasiv = hasiv2;
|
||||||
ivtbl = ivtbl2;
|
ivobj = ivobj2;
|
||||||
encname = encname2;
|
encname = encname2;
|
||||||
}
|
}
|
||||||
if (hasiv) w_byte(TYPE_IVAR, arg);
|
if (hasiv) w_byte(TYPE_IVAR, arg);
|
||||||
w_class(TYPE_USERDEF, obj, arg, FALSE);
|
w_class(TYPE_USERDEF, obj, arg, FALSE);
|
||||||
w_bytes(RSTRING_PTR(v), RSTRING_LEN(v), arg);
|
w_bytes(RSTRING_PTR(v), RSTRING_LEN(v), arg);
|
||||||
if (hasiv) {
|
if (hasiv) {
|
||||||
w_ivar(hasiv, ivtbl, encname, &c_arg);
|
w_ivar(hasiv, ivobj, encname, &c_arg);
|
||||||
}
|
}
|
||||||
st_add_direct(arg->data, obj, arg->data->num_entries);
|
st_add_direct(arg->data, obj, arg->data->num_entries);
|
||||||
return;
|
return;
|
||||||
@ -737,7 +746,7 @@ w_object(VALUE obj, struct dump_arg *arg, int limit)
|
|||||||
|
|
||||||
st_add_direct(arg->data, obj, arg->data->num_entries);
|
st_add_direct(arg->data, obj, arg->data->num_entries);
|
||||||
|
|
||||||
hasiv = has_ivars(obj, (encname = encoding_name(obj, arg)), &ivtbl);
|
hasiv = has_ivars(obj, (encname = encoding_name(obj, arg)), &ivobj);
|
||||||
{
|
{
|
||||||
st_data_t compat_data;
|
st_data_t compat_data;
|
||||||
rb_alloc_func_t allocator = rb_get_alloc_func(RBASIC(obj)->klass);
|
rb_alloc_func_t allocator = rb_get_alloc_func(RBASIC(obj)->klass);
|
||||||
@ -751,7 +760,7 @@ w_object(VALUE obj, struct dump_arg *arg, int limit)
|
|||||||
arg->compat_tbl = rb_init_identtable();
|
arg->compat_tbl = rb_init_identtable();
|
||||||
}
|
}
|
||||||
st_insert(arg->compat_tbl, (st_data_t)obj, (st_data_t)real_obj);
|
st_insert(arg->compat_tbl, (st_data_t)obj, (st_data_t)real_obj);
|
||||||
if (obj != real_obj && !ivtbl) hasiv = 0;
|
if (obj != real_obj && ivobj == Qundef) hasiv = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (hasiv) w_byte(TYPE_IVAR, arg);
|
if (hasiv) w_byte(TYPE_IVAR, arg);
|
||||||
@ -911,7 +920,7 @@ w_object(VALUE obj, struct dump_arg *arg, int limit)
|
|||||||
RB_GC_GUARD(obj);
|
RB_GC_GUARD(obj);
|
||||||
}
|
}
|
||||||
if (hasiv) {
|
if (hasiv) {
|
||||||
w_ivar(hasiv, ivtbl, encname, &c_arg);
|
w_ivar(hasiv, ivobj, encname, &c_arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
5
time.c
5
time.c
@ -4735,16 +4735,13 @@ time_mload(VALUE time, VALUE str)
|
|||||||
long nsec;
|
long nsec;
|
||||||
VALUE submicro, nano_num, nano_den, offset, zone;
|
VALUE submicro, nano_num, nano_den, offset, zone;
|
||||||
wideval_t timew;
|
wideval_t timew;
|
||||||
st_data_t data;
|
|
||||||
|
|
||||||
time_modify(time);
|
time_modify(time);
|
||||||
|
|
||||||
#define get_attr(attr, iffound) \
|
#define get_attr(attr, iffound) \
|
||||||
attr = rb_attr_get(str, id_##attr); \
|
attr = rb_attr_delete(str, id_##attr); \
|
||||||
if (!NIL_P(attr)) { \
|
if (!NIL_P(attr)) { \
|
||||||
data = id_##attr; \
|
|
||||||
iffound; \
|
iffound; \
|
||||||
st_delete(rb_generic_ivar_table(str), &data, 0); \
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get_attr(nano_num, {});
|
get_attr(nano_num, {});
|
||||||
|
63
variable.c
63
variable.c
@ -1012,6 +1012,27 @@ rb_generic_ivar_table(VALUE obj)
|
|||||||
return a.tbl;
|
return a.tbl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
generic_ivar_delete(VALUE obj, ID id, VALUE undef)
|
||||||
|
{
|
||||||
|
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(iv_index_tbl, (st_data_t)id, &index)) {
|
||||||
|
if ((long)index < ivtbl->numiv) {
|
||||||
|
VALUE ret = ivtbl->ivptr[index];
|
||||||
|
|
||||||
|
ivtbl->ivptr[index] = Qundef;
|
||||||
|
return ret == Qundef ? undef : ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
generic_ivar_get(VALUE obj, ID id, VALUE undef)
|
generic_ivar_get(VALUE obj, ID id, VALUE undef)
|
||||||
{
|
{
|
||||||
@ -1274,6 +1295,48 @@ rb_attr_get(VALUE obj, ID id)
|
|||||||
return rb_ivar_lookup(obj, id, Qnil);
|
return rb_ivar_lookup(obj, id, Qnil);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
rb_ivar_delete(VALUE obj, ID id, VALUE undef)
|
||||||
|
{
|
||||||
|
VALUE val, *ptr;
|
||||||
|
struct st_table *iv_index_tbl;
|
||||||
|
long len;
|
||||||
|
st_data_t index;
|
||||||
|
|
||||||
|
if (SPECIAL_CONST_P(obj)) goto generic;
|
||||||
|
switch (BUILTIN_TYPE(obj)) {
|
||||||
|
case T_OBJECT:
|
||||||
|
len = ROBJECT_NUMIV(obj);
|
||||||
|
ptr = ROBJECT_IVPTR(obj);
|
||||||
|
iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
|
||||||
|
if (!iv_index_tbl) break;
|
||||||
|
if (!st_lookup(iv_index_tbl, (st_data_t)id, &index)) break;
|
||||||
|
if (len <= (long)index) break;
|
||||||
|
val = ptr[index];
|
||||||
|
ptr[index] = Qundef;
|
||||||
|
if (val != Qundef)
|
||||||
|
return val;
|
||||||
|
break;
|
||||||
|
case T_CLASS:
|
||||||
|
case T_MODULE:
|
||||||
|
if (RCLASS_IV_TBL(obj) && st_delete(RCLASS_IV_TBL(obj), (st_data_t *)&id, &index))
|
||||||
|
return (VALUE)index;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
generic:
|
||||||
|
if (FL_TEST(obj, FL_EXIVAR) || rb_special_const_p(obj))
|
||||||
|
return generic_ivar_delete(obj, id, undef);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
VALUE
|
||||||
|
rb_attr_delete(VALUE obj, ID id)
|
||||||
|
{
|
||||||
|
return rb_ivar_delete(obj, id, Qnil);
|
||||||
|
}
|
||||||
|
|
||||||
static st_table *
|
static st_table *
|
||||||
iv_index_tbl_make(VALUE obj)
|
iv_index_tbl_make(VALUE obj)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user