From fa4476907f92bbfed5868fb33305b4d78bb42607 Mon Sep 17 00:00:00 2001 From: akr Date: Sat, 8 Sep 2007 15:07:18 +0000 Subject: * eval_method.ci (rb_get_alloc_func): new function to get allocation function. * include/ruby/intern.h (rb_alloc_func_t): declared. (rb_define_alloc_func): declared. (rb_marshal_define_compat): declared. * range.c: use T_STRUCT for Range. * inits.c: move Init_marshal() prior to Init_Range() because Init_Range calls rb_marshal_define_compat which needs marshal's compat_allocator_tbl initialized. * marshal.c: support marshal format compatibility layer designed for marshaling T_STRUCT Range using T_OBJECT format. (rb_marshal_define_compat): defined. [ruby-dev:31710] git-svn-id: http://svn.ruby-lang.org/repos/ruby/trunk@13413 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- marshal.c | 145 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 132 insertions(+), 13 deletions(-) (limited to 'marshal.c') diff --git a/marshal.c b/marshal.c index 5df52ae27..5f97e69d6 100644 --- a/marshal.c +++ b/marshal.c @@ -82,12 +82,45 @@ static ID s_dump, s_load, s_mdump, s_mload; static ID s_dump_data, s_load_data, s_alloc; static ID s_getc, s_read, s_write, s_binmode; +typedef struct { + VALUE newclass; + VALUE oldclass; + VALUE (*dumper)(VALUE); + VALUE (*loader)(VALUE, VALUE); +} marshal_compat_t; + +static st_table *compat_allocator_tbl; + +void +rb_marshal_define_compat(VALUE newclass, VALUE oldclass, VALUE (*dumper)(VALUE), VALUE (*loader)(VALUE, VALUE)) +{ + marshal_compat_t *compat; + rb_alloc_func_t allocator = rb_get_alloc_func(newclass); + + if (!allocator) { + rb_raise(rb_eTypeError, "no allocator"); + } + + compat = ALLOC(marshal_compat_t); + compat->newclass = Qnil; + compat->oldclass = Qnil; + rb_gc_register_address(&compat->newclass); + rb_gc_register_address(&compat->oldclass); + compat->newclass = newclass; + compat->oldclass = oldclass; + compat->dumper = dumper; + compat->loader = loader; + + st_insert(compat_allocator_tbl, (st_data_t)allocator, (st_data_t)compat); +} + struct dump_arg { VALUE obj; VALUE str, dest; st_table *symbols; st_table *data; int taint; + st_table *compat_tbl; }; struct dump_call_arg { @@ -363,8 +396,13 @@ w_class(char type, VALUE obj, struct dump_arg *arg, int check) { volatile VALUE p; char *path; + VALUE real_obj; + VALUE klass; - VALUE klass = CLASS_OF(obj); + if (st_lookup(arg->compat_tbl, (st_data_t)obj, (st_data_t*)&real_obj)) { + obj = real_obj; + } + klass = CLASS_OF(obj); w_extended(klass, arg, check); w_byte(type, arg); p = class2path(rb_class_real(klass)); @@ -459,6 +497,19 @@ w_object(VALUE obj, struct dump_arg *arg, int limit) if (OBJ_TAINTED(obj)) arg->taint = Qtrue; st_add_direct(arg->data, obj, arg->data->num_entries); + + { + marshal_compat_t *compat; + rb_alloc_func_t allocator = rb_get_alloc_func(RBASIC(obj)->klass); + if (st_lookup(compat_allocator_tbl, + (st_data_t)allocator, + (st_data_t*)&compat)) { + VALUE real_obj = obj; + obj = compat->dumper(real_obj); + st_insert(arg->compat_tbl, (st_data_t)obj, (st_data_t)real_obj); + } + } + if (rb_respond_to(obj, s_mdump)) { VALUE v; @@ -720,6 +771,7 @@ marshal_dump(int argc, VALUE *argv) arg.symbols = st_init_numtable(); arg.data = st_init_numtable(); arg.taint = Qfalse; + arg.compat_tbl = st_init_numtable(); c_arg.obj = obj; c_arg.arg = &arg; c_arg.limit = limit; @@ -739,6 +791,7 @@ struct load_arg { VALUE data; VALUE proc; int taint; + st_table *compat_tbl; }; static VALUE r_entry(VALUE v, struct load_arg *arg); @@ -899,14 +952,41 @@ r_string(struct load_arg *arg) static VALUE r_entry(VALUE v, struct load_arg *arg) { - rb_hash_aset(arg->data, INT2FIX(RHASH_SIZE(arg->data)), v); - if (arg->taint) OBJ_TAINT(v); + VALUE real_obj = Qundef; + if (st_lookup(arg->compat_tbl, v, (st_data_t*)&real_obj)) { + rb_hash_aset(arg->data, INT2FIX(RHASH_SIZE(arg->data)), real_obj); + } + else { + rb_hash_aset(arg->data, INT2FIX(RHASH_SIZE(arg->data)), v); + } + if (arg->taint) { + OBJ_TAINT(v); + if (real_obj != Qundef) + OBJ_TAINT(real_obj); + } if (arg->proc) { v = rb_funcall(arg->proc, rb_intern("call"), 1, v); } return v; } +static VALUE +r_leave(VALUE v, struct load_arg *arg) +{ + VALUE real_obj; + marshal_compat_t *compat; + if (st_lookup(arg->compat_tbl, v, &real_obj)) { + rb_alloc_func_t allocator = rb_get_alloc_func(CLASS_OF(real_obj)); + st_data_t key = v; + if (st_lookup(compat_allocator_tbl, (st_data_t)allocator, (st_data_t*)&compat)) { + compat->loader(real_obj, v); + } + st_delete(arg->compat_tbl, &key, 0); + return real_obj; + } + return v; +} + static void r_ivar(VALUE obj, struct load_arg *arg) { @@ -944,6 +1024,26 @@ path2module(const char *path) return v; } +static VALUE +obj_alloc_by_path(const char *path, struct load_arg *arg) +{ + VALUE klass; + marshal_compat_t *compat; + rb_alloc_func_t allocator; + + klass = path2class(path); + + allocator = rb_get_alloc_func(klass); + if (st_lookup(compat_allocator_tbl, (st_data_t)allocator, (st_data_t*)&compat)) { + VALUE real_obj = rb_obj_alloc(klass); + VALUE obj = rb_obj_alloc(compat->oldclass); + st_insert(arg->compat_tbl, (st_data_t)obj, (st_data_t)real_obj); + return obj; + } + + return rb_obj_alloc(klass); +} + static VALUE r_object0(struct load_arg *arg, int *ivp, VALUE extmod) { @@ -1049,6 +1149,7 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod) } v = rb_float_new(d); v = r_entry(v, arg); + v = r_leave(v, arg); } break; @@ -1094,11 +1195,13 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod) } v = rb_big_norm((VALUE)big); v = r_entry(v, arg); + v = r_leave(v, arg); } break; case TYPE_STRING: v = r_entry(r_string(arg), arg); + v = r_leave(v, arg); break; case TYPE_REGEXP: @@ -1106,6 +1209,7 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod) volatile VALUE str = r_bytes(arg); int options = r_byte(arg); v = r_entry(rb_reg_new(str, options), arg); + v = r_leave(v, arg); } break; @@ -1118,6 +1222,7 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod) while (len--) { rb_ary_push(v, r_object(arg)); } + v = r_leave(v, arg); } break; @@ -1136,12 +1241,14 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod) if (type == TYPE_HASH_DEF) { RHASH(v)->ifnone = r_object(arg); } + v = r_leave(v, arg); } break; case TYPE_STRUCT: { - VALUE klass, mem, values; + VALUE klass, mem; + volatile VALUE values; volatile long i; /* gcc 2.7.2.3 -O2 bug?? */ long len; ID slot; @@ -1150,12 +1257,14 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod) mem = rb_struct_s_members(klass); len = r_long(arg); - values = rb_ary_new2(len); - for (i=0; i