diff --git a/ChangeLog b/ChangeLog index 5cea64c20052f1..ec4e9acdce6c64 100644 --- a/ChangeLog +++ b/ChangeLog @@ -14,6 +14,25 @@ Sun Feb 4 02:22:59 2007 Akinori MUSHA * lib/cgi.rb (CGI::QueryExtension::read_multipart): Remove a debug print. +Sat Feb 3 23:51:58 2007 Yukihiro Matsumoto + + * parse.y (rb_compose_ivar2): function to create a new ivar2 + symbol from a symbol and a class. back-ported from matzruby. + + * parse.y (rb_decompose_ivar2): reverse function of + rb_compose_ivar2(). + + * marshal.c (w_symbol): support class local instance variables. + + * marshal.c (r_object0): ditto. + + * compile.c (defined_expr): ditto. + + * compile.c (iseq_compile_each): ditto. + + * insns.def: add two new instructions: getinstancevariable2 and + setinstancevariable2. + Sat Feb 3 23:21:13 2007 Yukihiro Matsumoto * insns.def (setclassvariable): remove unnecessary operand. diff --git a/compile.c b/compile.c index 5455bd70343e13..54a806ed994ff0 100644 --- a/compile.c +++ b/compile.c @@ -2345,6 +2345,11 @@ defined_expr(yarv_iseq_t *iseq, LINK_ANCHOR *ret, ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_IVAR), ID2SYM(node->nd_vid), needstr); return 1; + case NODE_IVAR2: + ADD_INSN(ret, nd_line(node), putnil); + ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_IVAR2), + ID2SYM(node->nd_vid), needstr); + return 1; case NODE_GVAR: ADD_INSN(ret, nd_line(node), putnil); @@ -3327,6 +3332,15 @@ iseq_compile_each(yarv_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped) ID2SYM(node->nd_vid)); break; } + case NODE_IASGN2:{ + COMPILE(ret, "lvalue", node->nd_value); + if (!poped) { + ADD_INSN(ret, nd_line(node), dup); + } + ADD_INSN1(ret, nd_line(node), setinstancevariable2, + ID2SYM(node->nd_vid)); + break; + } case NODE_CDECL:{ COMPILE(ret, "lvalue", node->nd_value); @@ -3903,6 +3917,14 @@ iseq_compile_each(yarv_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped) } break; } + case NODE_IVAR2:{ + debugi("nd_vid", node->nd_vid); + if (!poped) { + ADD_INSN1(ret, nd_line(node), getinstancevariable2, + ID2SYM(node->nd_vid)); + } + break; + } case NODE_CONST:{ debugi("nd_vid", node->nd_vid); diff --git a/gc.c b/gc.c index 6174d2f420db70..bf8e29def26f64 100644 --- a/gc.c +++ b/gc.c @@ -896,6 +896,7 @@ gc_mark_children(VALUE ptr, int lev) case NODE_DASGN: case NODE_DASGN_CURR: case NODE_IASGN: + case NODE_IASGN2: case NODE_CVASGN: case NODE_COLON3: case NODE_OPT_N: @@ -935,6 +936,7 @@ gc_mark_children(VALUE ptr, int lev) case NODE_LVAR: case NODE_DVAR: case NODE_IVAR: + case NODE_IVAR2: case NODE_CVAR: case NODE_NTH_REF: case NODE_BACK_REF: diff --git a/insns.def b/insns.def index 99401cc3951cf5..b84d07f2902f87 100644 --- a/insns.def +++ b/insns.def @@ -186,6 +186,22 @@ getinstancevariable val = rb_ivar_get(GET_SELF(), id); } +/** + @c variable + @e get class local instance variable id of obj. + @j obj のクラスローカルインスタンス変数 id を得る。 + */ +DEFINE_INSN +getinstancevariable2 +(ID id) +() +(VALUE val) +{ + /* need to cache composed id */ + id = rb_compose_ivar2(id, eval_get_cvar_base(th, GET_ISEQ())); + val = rb_ivar_get(GET_SELF(), id); +} + /** @c variable @e set instance variable id of obj as val. @@ -200,6 +216,22 @@ setinstancevariable rb_ivar_set(GET_SELF(), id, val); } +/** + @c variable + @e set class local instance variable id of obj as val. + @j obj のクラスローカルインスタンス変数を val にする。 + */ +DEFINE_INSN +setinstancevariable2 +(ID id) +(VALUE val) +() +{ + /* need to cache composed id */ + id = rb_compose_ivar2(id, eval_get_cvar_base(th, GET_ISEQ())); + rb_ivar_set(GET_SELF(), id, val); +} + /** @c variable @e get class variable id of klass as val. @@ -901,6 +933,12 @@ defined expr_type = "instance-variable"; } break; + case DEFINED_IVAR2: + klass = get_cref(GET_ISEQ(), GET_LFP())->nd_clss; + if (rb_ivar_defined(GET_SELF(), rb_compose_ivar2(SYM2ID(obj), klass))) { + expr_type = "class local instance-variable"; + } + break; case DEFINED_GVAR: if (rb_gvar_defined((struct global_entry *)(obj & ~1))) { expr_type = "global-variable"; diff --git a/intern.h b/intern.h index ad8c6b42d65961..b3fd3cb0ce9d70 100644 --- a/intern.h +++ b/intern.h @@ -398,6 +398,7 @@ ID rb_id_attrset(ID); void rb_gc_mark_parser(void); int rb_is_const_id(ID); int rb_is_instance_id(ID); +int rb_is_instance2_id(ID); int rb_is_class_id(ID); int rb_is_local_id(ID); int rb_is_junk_id(ID); @@ -409,6 +410,8 @@ void rb_backref_set(VALUE); VALUE rb_lastline_get(void); void rb_lastline_set(VALUE); VALUE rb_sym_all_symbols(void); +ID rb_compose_ivar2(ID, VALUE); +ID rb_decompose_ivar2(ID, VALUE*); /* process.c */ struct rb_exec_arg { int argc; diff --git a/iseq.c b/iseq.c index 0b53f0b830ae3e..9932491d1ccf29 100644 --- a/iseq.c +++ b/iseq.c @@ -863,6 +863,8 @@ node_name(int node) return "NODE_GASGN"; case NODE_IASGN: return "NODE_IASGN"; + case NODE_IASGN2: + return "NODE_IASGN2"; case NODE_CDECL: return "NODE_CDECL"; case NODE_CVASGN: @@ -905,6 +907,8 @@ node_name(int node) return "NODE_GVAR"; case NODE_IVAR: return "NODE_IVAR"; + case NODE_IVAR2: + return "NODE_IVAR2"; case NODE_CONST: return "NODE_CONST"; case NODE_CVAR: diff --git a/marshal.c b/marshal.c index 950a1b31d1a9c0..1d8b5afa8074d9 100644 --- a/marshal.c +++ b/marshal.c @@ -47,7 +47,7 @@ shortlen(long len, BDIGIT *ds) #endif #define MARSHAL_MAJOR 4 -#define MARSHAL_MINOR 8 +#define MARSHAL_MINOR 9 #define TYPE_NIL '0' #define TYPE_TRUE 'T' @@ -73,6 +73,7 @@ shortlen(long len, BDIGIT *ds) #define TYPE_MODULE 'm' #define TYPE_SYMBOL ':' +#define TYPE_SYMBOL2 ',' #define TYPE_SYMLINK ';' #define TYPE_IVAR 'I' @@ -304,7 +305,7 @@ w_float(double d, struct dump_arg *arg) static void w_symbol(ID id, struct dump_arg *arg) { - const char *sym = rb_id2name(id); + const char *sym; st_data_t num; if (st_lookup(arg->symbols, id, &num)) { @@ -312,8 +313,22 @@ w_symbol(ID id, struct dump_arg *arg) w_long((long)num, arg); } else { - w_byte(TYPE_SYMBOL, arg); - w_bytes(sym, strlen(sym), arg); + if (rb_is_instance2_id(id)) { + VALUE klass; + volatile VALUE path; + + id = rb_decompose_ivar2(id, &klass); + path = class2path(klass); + w_byte(TYPE_SYMBOL2, arg); + sym = rb_id2name(id); + w_bytes(sym, strlen(sym), arg); + w_bytes(RSTRING_PTR(path), RSTRING_LEN(path), arg); + } + else { + sym = rb_id2name(id); + w_byte(TYPE_SYMBOL, arg); + w_bytes(sym, strlen(sym), arg); + } st_add_direct(arg->symbols, id, arg->symbols->num_entries); } } @@ -360,12 +375,14 @@ w_extended(VALUE klass, struct dump_arg *arg, int check) static void w_class(char type, VALUE obj, struct dump_arg *arg, int check) { + volatile VALUE p; char *path; VALUE klass = CLASS_OF(obj); w_extended(klass, arg, check); w_byte(type, arg); - path = RSTRING_PTR(class2path(rb_class_real(klass))); + p = class2path(rb_class_real(klass)); + path = RSTRING_PTR(p); w_unique(path, arg); } @@ -490,7 +507,7 @@ w_object(VALUE obj, struct dump_arg *arg, int limit) } w_byte(TYPE_CLASS, arg); { - VALUE path = class2path(obj); + volatile VALUE path = class2path(obj); w_bytes(RSTRING_PTR(path), RSTRING_LEN(path), arg); } break; @@ -738,7 +755,9 @@ struct load_arg { int taint; }; +static VALUE r_entry(VALUE v, struct load_arg *arg); static VALUE r_object(struct load_arg *arg); +static VALUE path2class(const char *path); static int r_byte(struct load_arg *arg) @@ -855,10 +874,24 @@ r_symlink(struct load_arg *arg) static ID r_symreal(struct load_arg *arg) { - ID id; volatile VALUE s = r_bytes(arg); + ID id = rb_intern(RSTRING_PTR(s)); + + st_insert(arg->symbols, arg->symbols->num_entries, id); + + return id; +} + +static ID +r_symivar2(struct load_arg *arg) +{ + volatile VALUE s = r_bytes(arg); + ID id = rb_intern(RSTRING_PTR(s)); + VALUE klass; - id = rb_intern(RSTRING_PTR(s)); + s = r_bytes(arg); + klass = r_entry(path2class(RSTRING_PTR(s)), arg); + id = rb_compose_ivar2(id, klass); st_insert(arg->symbols, arg->symbols->num_entries, id); return id; @@ -867,10 +900,19 @@ r_symreal(struct load_arg *arg) static ID r_symbol(struct load_arg *arg) { - if (r_byte(arg) == TYPE_SYMLINK) { + int type; + + switch ((type = r_byte(arg))) { + case TYPE_SYMBOL: + return r_symreal(arg); + case TYPE_SYMBOL2: + return r_symivar2(arg); + case TYPE_SYMLINK: return r_symlink(arg); + default: + rb_raise(rb_eArgError, "dump format error(0x%x)", type); + break; } - return r_symreal(arg); } static const char* @@ -1274,6 +1316,10 @@ r_object0(struct load_arg *arg, int *ivp, VALUE extmod) v = ID2SYM(r_symreal(arg)); break; + case TYPE_SYMBOL2: + v = ID2SYM(r_symivar2(arg)); + break; + case TYPE_SYMLINK: v = ID2SYM(r_symlink(arg)); break; diff --git a/node.h b/node.h index 7deab9646d86a3..453f59f47ae36b 100644 --- a/node.h +++ b/node.h @@ -48,6 +48,7 @@ enum node_type { NODE_DASGN_CURR, NODE_GASGN, NODE_IASGN, + NODE_IASGN2, NODE_CDECL, NODE_CVASGN, NODE_CVDECL, @@ -70,6 +71,7 @@ enum node_type { NODE_DVAR, NODE_GVAR, NODE_IVAR, + NODE_IVAR2, NODE_CONST, NODE_CVAR, NODE_NTH_REF, @@ -282,6 +284,7 @@ typedef struct RNode { #define NEW_DASGN(v,val) NEW_NODE(NODE_DASGN,v,val,0) #define NEW_DASGN_CURR(v,val) NEW_NODE(NODE_DASGN_CURR,v,val,0) #define NEW_IASGN(v,val) NEW_NODE(NODE_IASGN,v,val,0) +#define NEW_IASGN2(v,val) NEW_NODE(NODE_IASGN2,v,val,0) #define NEW_CDECL(v,val,path) NEW_NODE(NODE_CDECL,v,val,path) #define NEW_CVASGN(v,val) NEW_NODE(NODE_CVASGN,v,val,0) #define NEW_CVDECL(v,val) NEW_NODE(NODE_CVDECL,v,val,0) @@ -294,6 +297,7 @@ typedef struct RNode { #define NEW_LVAR(v) NEW_NODE(NODE_LVAR,v,0,local_cnt(v)) #define NEW_DVAR(v) NEW_NODE(NODE_DVAR,v,0,0) #define NEW_IVAR(v) NEW_NODE(NODE_IVAR,v,0,0) +#define NEW_IVAR2(v) NEW_NODE(NODE_IVAR2,v,0,0) #define NEW_CONST(v) NEW_NODE(NODE_CONST,v,0,0) #define NEW_CVAR(v) NEW_NODE(NODE_CVAR,v,0,0) #define NEW_NTH_REF(n) NEW_NODE(NODE_NTH_REF,0,n,local_cnt('~')) diff --git a/parse.y b/parse.y index 49094f92ef97e0..3f783af35260a9 100644 --- a/parse.y +++ b/parse.y @@ -35,19 +35,21 @@ #define ID_SCOPE_SHIFT 3 #define ID_SCOPE_MASK 0x07 -#define ID_LOCAL 0x01 -#define ID_INSTANCE 0x02 -#define ID_GLOBAL 0x03 -#define ID_ATTRSET 0x04 -#define ID_CONST 0x05 -#define ID_CLASS 0x06 -#define ID_JUNK 0x07 -#define ID_INTERNAL ID_JUNK +#define ID_LOCAL 0x00 +#define ID_INSTANCE 0x01 +#define ID_INSTANCE2 0x02 +#define ID_GLOBAL 0x03 +#define ID_ATTRSET 0x04 +#define ID_CONST 0x05 +#define ID_CLASS 0x06 +#define ID_JUNK 0x07 +#define ID_INTERNAL ID_JUNK #define is_notop_id(id) ((id)>tLAST_TOKEN) #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) +#define is_instance2_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_INSTANCE2) #define is_attrset_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_ATTRSET) #define is_const_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_CONST) #define is_class_id(id) (is_notop_id(id)&&((id)&ID_SCOPE_MASK)==ID_CLASS) @@ -7245,6 +7247,9 @@ gettable_gen(struct parser_params *parser, ID id) else if (is_instance_id(id)) { return NEW_IVAR(id); } + else if (is_instance2_id(id)) { + return NEW_IVAR2(id); + } else if (is_const_id(id)) { return NEW_CONST(id); } @@ -7298,6 +7303,9 @@ assignable_gen(struct parser_params *parser, ID id, NODE *val) else if (is_instance_id(id)) { return NEW_IASGN(id, val); } + else if (is_instance2_id(id)) { + return NEW_IASGN2(id, val); + } else if (is_const_id(id)) { if (in_def || in_single) yyerror("dynamic constant assignment"); @@ -7432,6 +7440,7 @@ node_assign_gen(struct parser_params *parser, NODE *lhs, NODE *rhs) switch (nd_type(lhs)) { case NODE_GASGN: case NODE_IASGN: + case NODE_IASGN2: case NODE_LASGN: case NODE_DASGN: case NODE_DASGN_CURR: @@ -8319,6 +8328,8 @@ static struct symbols { ID last_id; st_table *sym_id; st_table *id_str; + st_table *ivar2_id; + st_table *id_ivar2; VALUE op_sym[tLAST_TOKEN]; } global_symbols = {tLAST_TOKEN}; @@ -8327,11 +8338,38 @@ static struct st_hash_type symhash = { rb_str_hash, }; +struct ivar2_key { + ID id; + VALUE klass; +}; + +static int +ivar2_cmp(struct ivar2_key *key1, struct ivar2_key *key2) +{ + if (key1->id == key2->id && key1->klass == key2->klass) { + return 0; + } + return 1; +} + +static int +ivar2_hash(struct ivar2_key *key) +{ + return (key->id << 8) ^ (key->klass >> 2); +} + +static struct st_hash_type ivar2_hash_type = { + ivar2_cmp, + ivar2_hash, +}; + void Init_sym(void) { global_symbols.sym_id = st_init_table_with_size(&symhash, 1000); global_symbols.id_str = st_init_numtable_with_size(1000); + global_symbols.ivar2_id = st_init_table_with_size(&ivar2_hash_type, 1000); + global_symbols.id_ivar2 = st_init_numtable_with_size(1000); } void @@ -8466,6 +8504,9 @@ rb_intern2(const char *name, long len) m++; id |= ID_CLASS; } + else if (name[1] == '_') { + id |= ID_INSTANCE2; + } else { id |= ID_INSTANCE; } @@ -8527,6 +8568,39 @@ rb_intern(const char *name) return rb_intern2(name, strlen(name)); } +ID +rb_compose_ivar2(ID oid, VALUE klass) +{ + struct ivar2_key key, *kp; + ID id; + + key.id = oid; + key.klass = klass; + if (st_lookup(global_symbols.ivar2_id, (st_data_t)&key, (st_data_t *)&id)) + return id; + + kp = ALLOC_N(struct ivar2_key, 1); + kp->id = oid; kp->klass = klass; + id = ID_INSTANCE2; + id |= ++global_symbols.last_id << ID_SCOPE_SHIFT; + st_add_direct(global_symbols.ivar2_id, (st_data_t)kp, (st_data_t)id); + st_add_direct(global_symbols.id_ivar2, (st_data_t)id, (st_data_t)kp); + return id; +} + +ID +rb_decompose_ivar2(ID id, VALUE *klassp) +{ + struct ivar2_key *kp; + ID oid; + + if (!st_lookup(global_symbols.id_ivar2, (st_data_t)id, (st_data_t *)&kp)) { + return id; + } + if (klassp) *klassp = kp->klass; + return kp->id; +} + VALUE rb_id2str(ID id) { @@ -8635,6 +8709,13 @@ rb_is_instance_id(ID id) return Qfalse; } +int +rb_is_instance2_id(ID id) +{ + if (is_instance2_id(id)) return Qtrue; + return Qfalse; +} + int rb_is_local_id(ID id) { diff --git a/string.c b/string.c index faacf954280142..89e88544c95f4a 100644 --- a/string.c +++ b/string.c @@ -4690,6 +4690,9 @@ sym_inspect(VALUE sym) VALUE str, klass = Qundef; ID id = SYM2ID(sym); + if (rb_is_instance2_id(id)) { + id = rb_decompose_ivar2(id, &klass); + } sym = rb_id2str(id); str = rb_str_new(0, RSTRING_LEN(sym)+1); RSTRING_PTR(str)[0] = ':'; @@ -4723,6 +4726,9 @@ rb_sym_to_s(VALUE sym) { ID id = SYM2ID(sym); + if (rb_is_instance2_id(id)) { + id = rb_decompose_ivar2(id, 0); + } return str_new3(rb_cString, rb_id2str(id)); } @@ -4868,6 +4874,27 @@ rb_to_id(VALUE name) return id; } +static VALUE +sym_div(VALUE sym, VALUE klass) +{ + ID id = SYM2ID(sym); + + if (!rb_is_instance2_id(id)) { + rb_raise(rb_eArgError, "symbol %s should be local instance variable", + rb_id2name(id)); + } + switch (TYPE(klass)) { + case T_CLASS: + case T_MODULE: + break; + default: + rb_check_type(klass, T_CLASS); + break; + } + id = rb_compose_ivar2(id, klass); + return ID2SYM(id); +} + /* * A String object holds and manipulates an arbitrary sequence of * bytes, typically representing characters. String objects may be created @@ -5008,6 +5035,7 @@ Init_String(void) rb_define_singleton_method(rb_cSymbol, "all_symbols", rb_sym_all_symbols, 0); /* in parse.y */ rb_define_singleton_method(rb_cSymbol, "intern", rb_sym_s_intern, 1); + rb_define_method(rb_cSymbol, "/", sym_div, 1); rb_define_method(rb_cSymbol, "==", sym_equal, 1); rb_define_method(rb_cSymbol, "to_i", sym_to_i, 0); rb_define_method(rb_cSymbol, "inspect", sym_inspect, 0); diff --git a/vm.c b/vm.c index 3da1f534864e44..720aefe79b3315 100644 --- a/vm.c +++ b/vm.c @@ -504,7 +504,7 @@ th_call0(yarv_thread_t *th, VALUE klass, VALUE recv, val = rb_ivar_set(recv, body->nd_vid, argv[0]); break; } - case NODE_IVAR:{ + case NODE_IVAR: { if (argc != 0) { rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc); diff --git a/vm_macro.def b/vm_macro.def index 8a2eb83dbb31f0..e08fb1493887f0 100644 --- a/vm_macro.def +++ b/vm_macro.def @@ -293,6 +293,12 @@ MACRO macro_eval_invoke_method(recv, klass, id, num, mn, blockptr) POP(); break; } + case NODE_IVAR2:{ + ID vid = rb_compose_ivar2(node->nd_vid, mn->nd_clss); + val = rb_ivar_get(recv, vid); + POP(); + break; + } case NODE_BMETHOD:{ VALUE *argv = GET_SP() - num; val = th_invoke_bmethod(th, id, node->nd_cval, diff --git a/yarvcore.h b/yarvcore.h index 8db6b8a7ab13f4..f2c76b2f6860d4 100644 --- a/yarvcore.h +++ b/yarvcore.h @@ -585,14 +585,15 @@ typedef VALUE CDHASH; /* defined? */ #define DEFINED_IVAR INT2FIX(1) -#define DEFINED_GVAR INT2FIX(2) -#define DEFINED_CVAR INT2FIX(3) -#define DEFINED_CONST INT2FIX(4) -#define DEFINED_METHOD INT2FIX(5) -#define DEFINED_YIELD INT2FIX(6) -#define DEFINED_REF INT2FIX(7) -#define DEFINED_ZSUPER INT2FIX(8) -#define DEFINED_FUNC INT2FIX(9) +#define DEFINED_IVAR2 INT2FIX(2) +#define DEFINED_GVAR INT2FIX(3) +#define DEFINED_CVAR INT2FIX(4) +#define DEFINED_CONST INT2FIX(5) +#define DEFINED_METHOD INT2FIX(6) +#define DEFINED_YIELD INT2FIX(7) +#define DEFINED_REF INT2FIX(8) +#define DEFINED_ZSUPER INT2FIX(9) +#define DEFINED_FUNC INT2FIX(10) /* VM related object allocate functions */ /* TODO: should be static functions */