1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

marshal.c: refine special instance variables

* marshal.c (w_obj_each, obj_count_ivars): count instance
  variables accurately.

* marshal.c (encoding_name, w_encoding): separate getting encoding
  values and writing them.

* marshal.c (w_symbol, w_ivar, w_objivar, w_object): refine
  special instance variables.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@44838 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nobu 2014-02-05 08:32:11 +00:00
parent 17a47a3358
commit 5ba39a12d9

126
marshal.c
View file

@ -219,7 +219,8 @@ class2path(VALUE klass)
} }
static void w_long(long, struct dump_arg*); static void w_long(long, struct dump_arg*);
static void w_encoding(VALUE obj, long num, struct dump_call_arg *arg); static void w_encoding(VALUE encname, struct dump_call_arg *arg);
static VALUE encoding_name(VALUE obj, struct dump_arg *arg);
static void static void
w_nbyte(const char *s, long n, struct dump_arg *arg) w_nbyte(const char *s, long n, struct dump_arg *arg)
@ -410,7 +411,7 @@ w_symbol(ID id, struct dump_arg *arg)
{ {
VALUE sym; VALUE sym;
st_data_t num; st_data_t num;
int encidx = -1; VALUE encname;
if (st_lookup(arg->symbols, id, &num)) { if (st_lookup(arg->symbols, id, &num)) {
w_byte(TYPE_SYMLINK, arg); w_byte(TYPE_SYMLINK, arg);
@ -421,10 +422,10 @@ w_symbol(ID id, struct dump_arg *arg)
if (!sym) { if (!sym) {
rb_raise(rb_eTypeError, "can't dump anonymous ID %"PRIdVALUE, id); rb_raise(rb_eTypeError, "can't dump anonymous ID %"PRIdVALUE, id);
} }
encidx = rb_enc_get_index(sym); encname = encoding_name(sym, arg);
if (encidx == rb_usascii_encindex() || if (NIL_P(encname) ||
rb_enc_str_coderange(sym) == ENC_CODERANGE_7BIT) { rb_enc_str_coderange(sym) == ENC_CODERANGE_7BIT) {
encidx = -1; encname = Qnil;
} }
else { else {
w_byte(TYPE_IVAR, arg); w_byte(TYPE_IVAR, arg);
@ -432,11 +433,12 @@ w_symbol(ID id, struct dump_arg *arg)
w_byte(TYPE_SYMBOL, arg); w_byte(TYPE_SYMBOL, arg);
w_bytes(RSTRING_PTR(sym), RSTRING_LEN(sym), arg); w_bytes(RSTRING_PTR(sym), RSTRING_LEN(sym), arg);
st_add_direct(arg->symbols, id, arg->symbols->num_entries); st_add_direct(arg->symbols, id, arg->symbols->num_entries);
if (encidx != -1) { if (!NIL_P(encname)) {
struct dump_call_arg c_arg; struct dump_call_arg c_arg;
c_arg.limit = 1; c_arg.limit = 1;
c_arg.arg = arg; c_arg.arg = arg;
w_encoding(sym, 0, &c_arg); w_long(1L, arg);
w_encoding(encname, &c_arg);
} }
} }
} }
@ -511,6 +513,8 @@ w_uclass(VALUE obj, VALUE super, struct dump_arg *arg)
} }
} }
#define to_be_skipped_id(id) (id == rb_id_encoding() || id == rb_intern("E"))
static int static int
w_obj_each(st_data_t key, st_data_t val, st_data_t a) w_obj_each(st_data_t key, st_data_t val, st_data_t a)
{ {
@ -518,56 +522,80 @@ w_obj_each(st_data_t key, st_data_t val, st_data_t a)
VALUE value = (VALUE)val; VALUE value = (VALUE)val;
struct dump_call_arg *arg = (struct dump_call_arg *)a; struct dump_call_arg *arg = (struct dump_call_arg *)a;
if (id == rb_id_encoding()) return ST_CONTINUE; if (to_be_skipped_id(id)) return ST_CONTINUE;
if (id == rb_intern("E")) return ST_CONTINUE;
w_symbol(id, arg->arg); w_symbol(id, arg->arg);
w_object(value, arg->arg, arg->limit); w_object(value, arg->arg, arg->limit);
return ST_CONTINUE; return ST_CONTINUE;
} }
static void static int
w_encoding(VALUE obj, long num, struct dump_call_arg *arg) obj_count_ivars(st_data_t key, st_data_t val, st_data_t a)
{
ID id = (ID)key;
if (!to_be_skipped_id(id)) ++*(st_index_t *)a;
return ST_CONTINUE;
}
static VALUE
encoding_name(VALUE obj, struct dump_arg *arg)
{ {
int encidx = rb_enc_get_index(obj); int encidx = rb_enc_get_index(obj);
rb_encoding *enc = 0; rb_encoding *enc = 0;
st_data_t name; st_data_t name;
if (encidx <= 0 || !(enc = rb_enc_from_index(encidx))) { if (encidx <= 0 || !(enc = rb_enc_from_index(encidx))) {
w_long(num, arg->arg); return Qnil;
return;
} }
w_long(num + 1, arg->arg);
/* special treatment for US-ASCII and UTF-8 */ /* special treatment for US-ASCII and UTF-8 */
if (encidx == rb_usascii_encindex()) { if (encidx == rb_usascii_encindex()) {
w_symbol(rb_intern("E"), arg->arg); return Qfalse;
w_object(Qfalse, arg->arg, arg->limit + 1);
return;
} }
else if (encidx == rb_utf8_encindex()) { else if (encidx == rb_utf8_encindex()) {
w_symbol(rb_intern("E"), arg->arg); return Qtrue;
w_object(Qtrue, arg->arg, arg->limit + 1);
return;
} }
w_symbol(rb_id_encoding(), arg->arg); if (arg->encodings ?
do { !st_lookup(arg->encodings, (st_data_t)rb_enc_name(enc), &name) :
if (!arg->arg->encodings) (arg->encodings = st_init_strcasetable(), 1)) {
arg->arg->encodings = st_init_strcasetable(); name = (st_data_t)rb_str_new_cstr(rb_enc_name(enc));
else if (st_lookup(arg->arg->encodings, (st_data_t)rb_enc_name(enc), &name)) st_insert(arg->encodings, (st_data_t)rb_enc_name(enc), name);
break; }
name = (st_data_t)rb_str_new2(rb_enc_name(enc)); return (VALUE)name;
st_insert(arg->arg->encodings, (st_data_t)rb_enc_name(enc), name);
} while (0);
w_object(name, arg->arg, arg->limit + 1);
} }
static void static void
w_ivar(VALUE obj, st_table *tbl, struct dump_call_arg *arg) w_encoding(VALUE encname, struct dump_call_arg *arg)
{ {
long num = tbl ? tbl->num_entries : 0; switch (encname) {
case Qfalse:
case Qtrue:
w_symbol(rb_intern("E"), arg->arg);
w_object(encname, arg->arg, arg->limit + 1);
case Qnil:
return;
}
w_symbol(rb_id_encoding(), arg->arg);
w_object(encname, arg->arg, arg->limit + 1);
}
w_encoding(obj, num, arg); static st_index_t
has_ivars(VALUE obj, VALUE encname, st_table **ivtbl)
{
st_index_t num = !NIL_P(encname);
*ivtbl = rb_generic_ivar_table(obj);
if (*ivtbl) {
st_foreach_safe(*ivtbl, obj_count_ivars, (st_data_t)&num);
}
return num;
}
static void
w_ivar(st_index_t num, st_table *tbl, VALUE encname, struct dump_call_arg *arg)
{
w_long(num, arg->arg);
w_encoding(encname, arg);
if (tbl) { if (tbl) {
st_foreach_safe(tbl, w_obj_each, (st_data_t)arg); st_foreach_safe(tbl, w_obj_each, (st_data_t)arg);
} }
@ -586,7 +614,7 @@ w_objivar(VALUE obj, struct dump_call_arg *arg)
if (ptr[i] != Qundef) if (ptr[i] != Qundef)
num += 1; num += 1;
w_encoding(obj, num, arg); w_long(num, arg->arg);
if (num != 0) { if (num != 0) {
rb_ivar_foreach(obj, w_obj_each, (st_data_t)arg); rb_ivar_foreach(obj, w_obj_each, (st_data_t)arg);
} }
@ -598,9 +626,8 @@ 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; st_table *ivtbl = 0;
st_data_t num; st_data_t num;
int hasiv = 0; st_index_t hasiv = 0;
#define has_ivars(obj, ivtbl) ((((ivtbl) = rb_generic_ivar_table(obj)) != 0) || \ VALUE encname = Qnil;
(!SPECIAL_CONST_P(obj) && !ENCODING_IS_ASCII8BIT(obj)))
if (limit == 0) { if (limit == 0) {
rb_raise(rb_eArgError, "exceed depth limit"); rb_raise(rb_eArgError, "exceed depth limit");
@ -663,7 +690,8 @@ w_object(VALUE obj, struct dump_arg *arg, int limit)
} }
if (rb_obj_respond_to(obj, s_dump, TRUE)) { if (rb_obj_respond_to(obj, s_dump, TRUE)) {
st_table *ivtbl2 = 0; st_table *ivtbl2 = 0;
int hasiv2; st_index_t hasiv2;
VALUE encname2;
v = INT2NUM(limit); v = INT2NUM(limit);
v = rb_funcall2(obj, s_dump, 1, &v); v = rb_funcall2(obj, s_dump, 1, &v);
@ -671,18 +699,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, ivtbl); hasiv = has_ivars(obj, (encname = encoding_name(obj, arg)), &ivtbl);
if (hasiv) w_byte(TYPE_IVAR, arg); hasiv2 = has_ivars(v, (encname2 = encoding_name(v, arg)), &ivtbl2);
if ((hasiv2 = has_ivars(v, ivtbl2)) != 0 && !hasiv) { if (hasiv2) {
w_byte(TYPE_IVAR, arg); hasiv = hasiv2;
ivtbl = ivtbl2;
encname = encname2;
} }
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 (hasiv2) { if (hasiv) {
w_ivar(v, ivtbl2, &c_arg); w_ivar(hasiv, ivtbl, encname, &c_arg);
}
else if (hasiv) {
w_ivar(obj, ivtbl, &c_arg);
} }
st_add_direct(arg->data, obj, arg->data->num_entries); st_add_direct(arg->data, obj, arg->data->num_entries);
return; return;
@ -690,7 +718,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, ivtbl); hasiv = has_ivars(obj, (encname = encoding_name(obj, arg)), &ivtbl);
{ {
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);
@ -855,7 +883,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(obj, ivtbl, &c_arg); w_ivar(hasiv, ivtbl, encname, &c_arg);
} }
} }