Re: [1.8] terminated object / invalid inspect_tbl
From:
ts <decoux@...>
Date:
2003-05-27 09:18:26 UTC
List:
ruby-core #1092
>>>>> "Y" == Yukihiro Matsumoto <matz@ruby-lang.org> writes:
Y> Yeah, I'd like to see the code.
It's a toy actually : it don't work yet with alias and it need some other
modifications
Guy Decoux
diff -u ../ruby/env.h ruby/env.h
--- ../ruby/env.h 2003-01-16 08:34:01.000000000 +0100
+++ ruby/env.h 2003-05-25 16:32:33.000000000 +0200
@@ -19,6 +19,8 @@
VALUE *argv;
ID last_func;
ID orig_func;
+ ID orig_id;
+ VALUE orig_class;
VALUE last_class;
VALUE cbase;
struct FRAME *prev;
diff -u ../ruby/eval.c ruby/eval.c
--- ../ruby/eval.c 2003-05-26 17:16:33.000000000 +0200
+++ ruby/eval.c 2003-05-26 18:26:34.000000000 +0200
@@ -106,6 +106,7 @@
static VALUE rb_cUnboundMethod;
static VALUE umethod_bind _((VALUE, VALUE));
static VALUE rb_mod_define_method _((int, VALUE*, VALUE));
+static VALUE rb_mod_define_hook _((int, VALUE*, VALUE));
static int scope_vmode;
#define SCOPE_PUBLIC 0
@@ -198,6 +199,7 @@
VALUE origin; /* where method defined */
NODE *method;
int noex;
+ int hook;
};
static struct cache_entry cache[CACHE_SIZE];
@@ -344,6 +346,7 @@
ent->mid = ent->mid0 = id;
ent->noex = 0;
ent->method = 0;
+ ent->hook = 0;
return 0;
}
@@ -432,6 +435,14 @@
return mod;
}
+static VALUE
+rb_mod_remove_hook(mod, name)
+ VALUE mod, name;
+{
+ remove_method(mod, rb_id_hook(rb_to_id(name)));
+ return mod;
+}
+
void
rb_disable_super(klass, name)
VALUE klass;
@@ -591,16 +602,18 @@
static struct FRAME *top_frame;
static struct SCOPE *top_scope;
-#define PUSH_FRAME() do { \
- struct FRAME _frame; \
- _frame.prev = ruby_frame; \
- _frame.tmp = 0; \
- _frame.node = ruby_current_node; \
- _frame.iter = ruby_iter->iter; \
- _frame.cbase = ruby_frame->cbase; \
- _frame.argc = 0; \
- _frame.argv = 0; \
- _frame.flags = FRAME_ALLOCA; \
+#define PUSH_FRAME() do { \
+ struct FRAME _frame; \
+ _frame.prev = ruby_frame; \
+ _frame.tmp = 0; \
+ _frame.node = ruby_current_node; \
+ _frame.iter = ruby_iter->iter; \
+ _frame.cbase = ruby_frame->cbase; \
+ _frame.orig_class = ruby_frame->orig_class; \
+ _frame.orig_id = ruby_frame->orig_id; \
+ _frame.argc = 0; \
+ _frame.argv = 0; \
+ _frame.flags = FRAME_ALLOCA; \
ruby_frame = &_frame
#define POP_FRAME() \
@@ -954,6 +967,8 @@
static VALUE rb_call _((VALUE,VALUE,ID,int,const VALUE*,int));
static VALUE module_setup _((VALUE,NODE*));
+static VALUE rb_call_hook _((VALUE,VALUE,ID,ID,int,const VALUE*));
+
static VALUE massign _((VALUE,NODE*,VALUE,int));
static void assign _((VALUE,NODE*,VALUE,int));
@@ -1810,6 +1825,14 @@
return mod;
}
+static VALUE
+rb_mod_undef_hook(mod, name)
+ VALUE mod, name;
+{
+ rb_undef(mod, rb_id_hook(rb_to_id(name)));
+ return mod;
+}
+
void
rb_alias(klass, name, def)
VALUE klass;
@@ -3015,9 +3038,23 @@
PUSH_ITER(ruby_iter->iter?ITER_PRE:ITER_NOT);
SET_CURRENT_SOURCE();
- result = rb_call(RCLASS(ruby_frame->last_class)->super,
- ruby_frame->self, ruby_frame->orig_func,
- argc, argv, 3);
+ result = Qundef;
+ if (rb_is_hook_id(ruby_frame->orig_func)) {
+ result = rb_call_hook(RCLASS(ruby_frame->last_class)->super,
+ ruby_frame->self, 0,
+ ruby_frame->orig_func,
+ argc, argv);
+ if (result == Qundef) {
+ result = rb_call(ruby_frame->orig_class,
+ ruby_frame->self,
+ ruby_frame->orig_id, argc, argv, 3);
+ }
+ }
+ if (result == Qundef) {
+ result = rb_call(RCLASS(ruby_frame->last_class)->super,
+ ruby_frame->self,
+ ruby_frame->orig_func, argc, argv, 3);
+ }
POP_ITER();
}
break;
@@ -4015,6 +4052,8 @@
struct BLOCK * volatile block;
struct SCOPE * volatile old_scope;
struct FRAME frame;
+ VALUE orig_class;
+ ID orig_id;
NODE *cnode = ruby_current_node;
int state;
static unsigned serial = 1;
@@ -4028,7 +4067,11 @@
block = ruby_block;
frame = block->frame;
frame.prev = ruby_frame;
+ orig_class = ruby_frame->orig_class;
+ orig_id = ruby_frame->orig_id;
ruby_frame = &(frame);
+ ruby_frame->orig_class = orig_class;
+ ruby_frame->orig_id = orig_id;
old_cref = (VALUE)ruby_cref;
ruby_cref = (NODE*)ruby_frame->cbase;
old_wrapper = ruby_wrapper;
@@ -5028,6 +5071,56 @@
}
static VALUE
+rb_call_hook(klass, recv, oid, mid, argc, argv)
+ VALUE klass, recv;
+ ID oid, mid;
+ int argc; /* OK */
+ const VALUE *argv; /* OK */
+{
+ NODE *body; /* OK */
+ int noex;
+ VALUE res = Qnil;
+ ID id = mid;
+ VALUE oklass = klass;
+ struct cache_entry *ent, *ent_orig;
+
+ ent = cache + EXPR1(klass, mid);
+ if (oid) {
+ ent_orig = cache + EXPR1(klass, oid);
+ }
+ if (ent->mid == mid && ent->klass == klass) {
+ if (!ent->method) {
+ if (oid) {
+ ent_orig->hook = 2;
+ }
+ return Qundef;
+ }
+ klass = ent->origin;
+ id = ent->mid0;
+ noex = ent->noex;
+ body = ent->method;
+ }
+ else if ((body = rb_get_method_body(&klass, &id, &noex)) == 0) {
+ if (oid) {
+ ent_orig->hook = 2;
+ }
+ return Qundef;
+ }
+ if (oid) {
+ ruby_frame->orig_class = oklass;
+ ruby_frame->orig_id = oid;
+ }
+ else {
+ ruby_frame->orig_class = ruby_frame->prev->orig_class;
+ ruby_frame->orig_id = ruby_frame->prev->orig_id;
+ }
+ if (oid) {
+ ent_orig->hook = 1;
+ }
+ return rb_call0(klass, recv, mid, id, argc, argv, body, noex & NOEX_NOSUPER);
+}
+
+static VALUE
rb_call(klass, recv, mid, argc, argv, scope)
VALUE klass, recv;
ID mid;
@@ -5037,6 +5130,7 @@
{
NODE *body; /* OK */
int noex;
+ VALUE oklass = klass, res;
ID id = mid;
struct cache_entry *ent;
@@ -5078,7 +5172,15 @@
}
}
- return rb_call0(klass, recv, mid, id, argc, argv, body, noex & NOEX_NOSUPER);
+ res = Qundef;
+ ent = cache + EXPR1(oklass, mid);
+ if (ent->hook < 2 && scope != 3 && rb_has_hook()) {
+ res = rb_call_hook(oklass, recv, mid, rb_id_hook(id), argc, argv);
+ }
+ if (res == Qundef) {
+ res = rb_call0(klass, recv, mid, id, argc, argv, body, noex & NOEX_NOSUPER);
+ }
+ return res;
}
VALUE
@@ -6501,6 +6603,9 @@
rb_define_private_method(rb_cModule, "undef_method", rb_mod_undef_method, 1);
rb_define_private_method(rb_cModule, "alias_method", rb_mod_alias_method, 2);
rb_define_private_method(rb_cModule, "define_method", rb_mod_define_method, -1);
+ rb_define_private_method(rb_cModule, "remove_hook", rb_mod_remove_hook, 1);
+ rb_define_private_method(rb_cModule, "define_hook", rb_mod_define_hook, -1);
+ rb_define_private_method(rb_cModule, "undef_hook", rb_mod_undef_hook, 2);
rb_define_singleton_method(rb_cModule, "nesting", rb_mod_nesting, 0);
rb_define_singleton_method(rb_cModule, "constants", rb_mod_s_constants, 0);
@@ -7591,6 +7696,22 @@
return body;
}
+static VALUE
+rb_mod_define_hook(argc, argv, mod)
+ int argc;
+ VALUE *argv;
+ VALUE mod;
+{
+ ID id;
+
+ if (!argc) {
+ rb_raise(rb_eArgError, "invalid number of arguments");
+ }
+ id = rb_to_id(argv[0]);
+ argv[0] = ID2SYM(rb_id_hook(id));
+ return rb_mod_define_method(argc, argv, mod);
+}
+
void
Init_Proc()
{
diff -u ../ruby/intern.h ruby/intern.h
--- ../ruby/intern.h 2003-05-26 15:47:05.000000000 +0200
+++ ruby/intern.h 2003-05-26 15:49:25.000000000 +0200
@@ -321,6 +321,9 @@
VALUE rb_lastline_get _((void));
void rb_lastline_set _((VALUE));
VALUE rb_sym_all_symbols _((void));
+ID rb_id_hook _((ID));
+int rb_has_hook _((void));
+int rb_is_hook_id _((ID));
/* process.c */
int rb_proc_exec _((const char*));
VALUE rb_f_exec _((int,VALUE*));
diff -u ../ruby/keywords ruby/keywords
--- ../ruby/keywords 2002-09-28 13:08:59.000000000 +0200
+++ ruby/keywords 2003-05-25 14:24:30.000000000 +0200
@@ -19,6 +19,7 @@
ensure, {kENSURE, kENSURE}, EXPR_BEG
false, {kFALSE, kFALSE}, EXPR_END
for, {kFOR, kFOR}, EXPR_BEG
+hook, {kHOOK, kHOOK}, EXPR_END
if, {kIF, kIF_MOD}, EXPR_BEG
in, {kIN, kIN}, EXPR_BEG
module, {kMODULE, kMODULE}, EXPR_BEG
diff -u ../ruby/parse.y ruby/parse.y
--- ../ruby/parse.y 2003-05-26 15:47:07.000000000 +0200
+++ ruby/parse.y 2003-05-26 17:32:31.000000000 +0200
@@ -32,6 +32,7 @@
#define ID_SCOPE_SHIFT 3
#define ID_SCOPE_MASK 0x07
+#define ID_HOOK 0x00
#define ID_LOCAL 0x01
#define ID_INSTANCE 0x02
#define ID_GLOBAL 0x03
@@ -42,6 +43,7 @@
#define ID_INTERNAL ID_JUNK
#define is_notop_id(id) ((id)>tLAST_TOKEN)
+#define is_hook_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_HOOK)
#define is_local_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_LOCAL)
#define is_global_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_GLOBAL)
#define is_instance_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_INSTANCE)
@@ -74,6 +76,7 @@
EXPR_FNAME, /* ignore newline, no reserved words. */
EXPR_DOT, /* right after `.' or `::', no reserved words. */
EXPR_CLASS, /* immediate after `class', no here document. */
+ EXPR_COLON, /* right after ':' expect 'hook' */
} lex_state;
static NODE *lex_strterm;
static int lex_strnest;
@@ -233,6 +236,7 @@
klEND
k__LINE__
k__FILE__
+ kHOOK
%token <id> tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR
%token <node> tINTEGER tFLOAT tSTRING_CONTENT
@@ -254,7 +258,7 @@
%type <node> block_var opt_block_var brace_block cmd_brace_block do_block lhs none
%type <node> mlhs mlhs_head mlhs_basic mlhs_entry mlhs_item mlhs_node
%type <id> fitem variable sym symbol operation operation2 operation3
-%type <id> cname fname op f_rest_arg
+%type <id> cname fname hname hitem op f_rest_arg
%type <num> f_norm_arg f_arg term_push
%token tUPLUS /* unary+ */
%token tUMINUS /* unary- */
@@ -862,6 +866,13 @@
}
;
+hname : fname
+ | fname ':' kHOOK
+ {
+ $$ = rb_id_hook($1);
+ }
+ ;
+
fname : tIDENTIFIER
| tCONSTANT
| tFID
@@ -881,11 +892,15 @@
| symbol
;
-undef_list : fitem
+hitem : hname
+ | symbol
+ ;
+
+undef_list : hitem
{
$$ = NEW_UNDEF($1);
}
- | undef_list ',' {lex_state = EXPR_FNAME;} fitem
+ | undef_list ',' {lex_state = EXPR_FNAME;} hitem
{
$$ = block_append($1, NEW_UNDEF($4));
}
@@ -1605,7 +1620,7 @@
local_pop();
class_nest--;
}
- | kDEF fname
+ | kDEF hname
{
$<id>$ = cur_mid;
cur_mid = $2;
@@ -1622,11 +1637,10 @@
in_def--;
cur_mid = $<id>3;
}
- | kDEF singleton dot_or_colon {lex_state = EXPR_FNAME;} fname
+ | kDEF singleton dot_or_colon {lex_state = EXPR_FNAME;} hname
{
in_single++;
local_push(0);
- lex_state = EXPR_END; /* force for args */
}
f_arglist
bodystmt
@@ -3944,6 +3958,10 @@
lex_state = EXPR_BEG;
return ':';
}
+ if (lex_state == EXPR_COLON) {
+ pushback(c);
+ return ':';
+ }
switch (c) {
case '\'':
lex_strterm = NEW_STRTERM(str_ssym, c, 0);
@@ -4324,6 +4342,7 @@
{
int result = 0;
+ int found_colon = 0;
switch (tok()[0]) {
case '$':
@@ -4351,6 +4370,7 @@
tokfix();
}
else {
+ found_colon = c == ':';
pushback(c);
}
}
@@ -4373,6 +4393,10 @@
if (state == EXPR_FNAME) {
yylval.id = rb_intern(kw->name);
}
+ if (state == EXPR_COLON && kw->id[0] == kHOOK) {
+ yylval.id = rb_intern(kw->name);
+ return kw->id[0];
+ }
if (kw->id[0] == kDO) {
if (COND_P()) return kDO_COND;
if (CMDARG_P() && state != EXPR_CMDARG)
@@ -4381,12 +4405,14 @@
return kDO_BLOCK;
return kDO;
}
- if (state == EXPR_BEG)
- return kw->id[0];
- else {
- if (kw->id[0] != kw->id[1])
- lex_state = EXPR_BEG;
- return kw->id[1];
+ if (kw->id[0] != kHOOK) {
+ if (state == EXPR_BEG)
+ return kw->id[0];
+ else {
+ if (kw->id[0] != kw->id[1])
+ lex_state = EXPR_BEG;
+ return kw->id[1];
+ }
}
}
}
@@ -4408,8 +4434,11 @@
}
}
yylval.id = rb_intern(tok());
- if (is_local_id(yylval.id) &&
- ((dyna_in_block() && rb_dvar_defined(yylval.id)) || local_id(yylval.id))) {
+ if (found_colon) {
+ lex_state = EXPR_COLON;
+ }
+ else if (is_local_id(yylval.id) &&
+ ((dyna_in_block() && rb_dvar_defined(yylval.id)) || local_id(yylval.id))) {
lex_state = EXPR_END;
}
return result;
@@ -5755,11 +5784,14 @@
static st_table *sym_tbl;
static st_table *sym_rev_tbl;
+static ID id_allocate;
+
void
Init_sym()
{
sym_tbl = st_init_strtable_with_size(200);
sym_rev_tbl = st_init_numtable_with_size(200);
+ id_allocate = rb_intern("allocate");
}
static ID last_id = tLAST_TOKEN;
@@ -5837,7 +5869,14 @@
while (*m && is_identchar(*m)) {
m++;
}
- if (*m) id = ID_JUNK;
+ if (*m) {
+ if (*m == ':') {
+ id = ID_HOOK;
+ }
+ else {
+ id = ID_JUNK;
+ }
+ }
id |= ++last_id << ID_SCOPE_SHIFT;
id_regist:
name = strdup(name);
@@ -5861,6 +5900,9 @@
}
}
+ if (rb_is_hook_id(id)) {
+ return "hooked method";
+ }
if (st_lookup(sym_rev_tbl, id, (st_data_t *)&name))
return name;
@@ -6002,3 +6044,33 @@
special_local_set('_', val);
}
}
+
+static int has_hook = 0;
+
+ID
+rb_id_hook(id)
+ ID id;
+{
+ has_hook = Qtrue;
+ if (id == ID_ALLOCATOR) {
+ id = id_allocate;
+ }
+ return (id & ~ID_SCOPE_MASK);
+}
+
+int
+rb_has_hook()
+{
+ return has_hook;
+}
+
+int
+rb_is_hook_id(id)
+ ID id;
+{
+ if (is_hook_id(id)) return Qtrue;
+ return Qfalse;
+}
+
+
+