refinements-r29944-20101127.diff
| b/class.c | ||
|---|---|---|
| 617 | 617 |
return module; |
| 618 | 618 |
} |
| 619 | 619 | |
| 620 |
static VALUE
|
|
| 621 |
include_class_new(VALUE module, VALUE super) |
|
| 620 |
VALUE |
|
| 621 |
rb_include_class_new(VALUE module, VALUE super)
|
|
| 622 | 622 |
{
|
| 623 | 623 |
VALUE klass = class_alloc(T_ICLASS, rb_cClass); |
| 624 | 624 | |
| ... | ... | |
| 685 | 685 |
break; |
| 686 | 686 |
} |
| 687 | 687 |
} |
| 688 |
c = RCLASS_SUPER(c) = include_class_new(module, RCLASS_SUPER(c)); |
|
| 688 |
c = RCLASS_SUPER(c) = rb_include_class_new(module, RCLASS_SUPER(c));
|
|
| 689 | 689 |
if (RMODULE_M_TBL(module) && RMODULE_M_TBL(module)->num_entries) |
| 690 | 690 |
changed = 1; |
| 691 | 691 |
skip: |
| b/eval.c | ||
|---|---|---|
| 23 | 23 |
VALUE rb_binding_new(void); |
| 24 | 24 |
NORETURN(void rb_raise_jump(VALUE)); |
| 25 | 25 | |
| 26 |
NODE *rb_vm_get_cref(const rb_iseq_t *, const VALUE *, const VALUE *); |
|
| 27 | ||
| 26 | 28 |
ID rb_frame_callee(void); |
| 27 | 29 |
VALUE rb_eLocalJumpError; |
| 28 | 30 |
VALUE rb_eSysStackError; |
| ... | ... | |
| 858 | 860 |
} |
| 859 | 861 | |
| 860 | 862 |
void |
| 863 |
rb_overlay_module(NODE *cref, VALUE klass, VALUE module) |
|
| 864 |
{
|
|
| 865 |
VALUE iclass, c, superclass = klass; |
|
| 866 | ||
| 867 |
Check_Type(klass, T_CLASS); |
|
| 868 |
Check_Type(module, T_MODULE); |
|
| 869 |
if (NIL_P(cref->nd_omod)) {
|
|
| 870 |
cref->nd_omod = rb_hash_new(); |
|
| 871 |
rb_funcall(cref->nd_omod, rb_intern("compare_by_identity"), 0);
|
|
| 872 |
} |
|
| 873 |
else {
|
|
| 874 |
if (cref->flags & NODE_FL_CREF_OMOD_SHARED) {
|
|
| 875 |
cref->nd_omod = rb_hash_dup(cref->nd_omod); |
|
| 876 |
cref->flags &= ~NODE_FL_CREF_OMOD_SHARED; |
|
| 877 |
} |
|
| 878 |
if (!NIL_P(c = rb_hash_lookup(cref->nd_omod, klass))) {
|
|
| 879 |
superclass = c; |
|
| 880 |
while (c && TYPE(c) == T_ICLASS) {
|
|
| 881 |
if (RBASIC(c)->klass == module) {
|
|
| 882 |
/* already overlayed module */ |
|
| 883 |
return; |
|
| 884 |
} |
|
| 885 |
c = RCLASS_SUPER(c); |
|
| 886 |
} |
|
| 887 |
} |
|
| 888 |
} |
|
| 889 |
FL_SET(module, RMODULE_IS_OVERLAYED); |
|
| 890 |
c = iclass = rb_include_class_new(module, superclass); |
|
| 891 |
module = RCLASS_SUPER(module); |
|
| 892 |
while (module) {
|
|
| 893 |
FL_SET(module, RMODULE_IS_OVERLAYED); |
|
| 894 |
c = RCLASS_SUPER(c) = rb_include_class_new(module, RCLASS_SUPER(c)); |
|
| 895 |
module = RCLASS_SUPER(module); |
|
| 896 |
} |
|
| 897 |
rb_hash_aset(cref->nd_omod, klass, iclass); |
|
| 898 |
rb_clear_cache_by_class(klass); |
|
| 899 |
} |
|
| 900 | ||
| 901 |
static int |
|
| 902 |
using_module_i(VALUE klass, VALUE module, VALUE arg) |
|
| 903 |
{
|
|
| 904 |
NODE *cref = (NODE *) arg; |
|
| 905 |
int i; |
|
| 906 | ||
| 907 |
rb_overlay_module(cref, klass, module); |
|
| 908 |
return ST_CONTINUE; |
|
| 909 |
} |
|
| 910 | ||
| 911 |
void |
|
| 912 |
rb_using_module(NODE *cref, VALUE module) |
|
| 913 |
{
|
|
| 914 |
ID id_overlayed_modules; |
|
| 915 |
VALUE overlayed_modules; |
|
| 916 | ||
| 917 |
Check_Type(module, T_MODULE); |
|
| 918 |
CONST_ID(id_overlayed_modules, "__overlayed_modules__"); |
|
| 919 |
overlayed_modules = rb_attr_get(module, id_overlayed_modules); |
|
| 920 |
if (NIL_P(overlayed_modules)) return; |
|
| 921 |
rb_hash_foreach(overlayed_modules, using_module_i, (VALUE) cref); |
|
| 922 |
} |
|
| 923 | ||
| 924 |
/* |
|
| 925 |
* call-seq: |
|
| 926 |
* using(module) -> self |
|
| 927 |
* |
|
| 928 |
* Import class refinements from <i>module</i> into the receiver. |
|
| 929 |
*/ |
|
| 930 | ||
| 931 |
static VALUE |
|
| 932 |
rb_mod_using(VALUE self, VALUE module) |
|
| 933 |
{
|
|
| 934 |
NODE *cref = rb_vm_cref(); |
|
| 935 |
ID id_using_modules; |
|
| 936 |
VALUE using_modules; |
|
| 937 | ||
| 938 |
CONST_ID(id_using_modules, "__using_modules__"); |
|
| 939 |
using_modules = rb_attr_get(self, id_using_modules); |
|
| 940 |
if (NIL_P(using_modules)) {
|
|
| 941 |
using_modules = rb_hash_new(); |
|
| 942 |
rb_funcall(using_modules, rb_intern("compare_by_identity"), 0);
|
|
| 943 |
rb_ivar_set(self, id_using_modules, using_modules); |
|
| 944 |
} |
|
| 945 |
rb_hash_aset(using_modules, module, Qtrue); |
|
| 946 |
rb_using_module(cref, module); |
|
| 947 |
rb_funcall(module, rb_intern("used"), 1, self);
|
|
| 948 |
return self; |
|
| 949 |
} |
|
| 950 | ||
| 951 |
void rb_redefine_opt_method(VALUE, ID); |
|
| 952 | ||
| 953 |
static VALUE |
|
| 954 |
refinement_module_method_added(VALUE mod, VALUE mid) |
|
| 955 |
{
|
|
| 956 |
ID id = SYM2ID(mid); |
|
| 957 |
ID id_refined_class; |
|
| 958 |
VALUE klass; |
|
| 959 | ||
| 960 |
CONST_ID(id_refined_class, "__refined_class__"); |
|
| 961 |
klass = rb_ivar_get(mod, id_refined_class); |
|
| 962 |
rb_redefine_opt_method(klass, id); |
|
| 963 |
} |
|
| 964 | ||
| 965 |
static VALUE |
|
| 966 |
refinement_module_include(int argc, VALUE *argv, VALUE module) |
|
| 967 |
{
|
|
| 968 |
rb_thread_t *th = GET_THREAD(); |
|
| 969 |
rb_control_frame_t *cfp = th->cfp; |
|
| 970 |
rb_control_frame_t *end_cfp = RUBY_VM_END_CONTROL_FRAME(th); |
|
| 971 |
VALUE result = rb_mod_include(argc, argv, module); |
|
| 972 |
NODE *cref; |
|
| 973 |
ID id_refined_class; |
|
| 974 |
VALUE klass, c; |
|
| 975 | ||
| 976 |
CONST_ID(id_refined_class, "__refined_class__"); |
|
| 977 |
klass = rb_attr_get(module, id_refined_class); |
|
| 978 |
while (RUBY_VM_VALID_CONTROL_FRAME_P(cfp, end_cfp)) {
|
|
| 979 |
if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq) && |
|
| 980 |
(cref = rb_vm_get_cref(cfp->iseq, cfp->lfp, cfp->dfp)) && |
|
| 981 |
!NIL_P(cref->nd_omod) && |
|
| 982 |
!NIL_P(c = rb_hash_lookup(cref->nd_omod, klass))) {
|
|
| 983 |
while (argc--) {
|
|
| 984 |
VALUE mod = argv[argc]; |
|
| 985 |
if (rb_class_inherited_p(module, mod)) {
|
|
| 986 |
RCLASS_SUPER(c) = |
|
| 987 |
rb_include_class_new(mod, RCLASS_SUPER(c)); |
|
| 988 |
} |
|
| 989 |
} |
|
| 990 |
break; |
|
| 991 |
} |
|
| 992 |
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); |
|
| 993 |
} |
|
| 994 |
return result; |
|
| 995 |
} |
|
| 996 | ||
| 997 |
/* |
|
| 998 |
* call-seq: |
|
| 999 |
* refine(klass) { block } -> self
|
|
| 1000 |
* |
|
| 1001 |
* Refine <i>klass</i> in the receiver. |
|
| 1002 |
*/ |
|
| 1003 | ||
| 1004 |
static VALUE |
|
| 1005 |
rb_mod_refine(VALUE module, VALUE klass) |
|
| 1006 |
{
|
|
| 1007 |
NODE *cref = rb_vm_cref(); |
|
| 1008 |
VALUE mod; |
|
| 1009 |
ID id_overlayed_modules, id_refined_class; |
|
| 1010 |
VALUE overlayed_modules, modules; |
|
| 1011 | ||
| 1012 |
Check_Type(klass, T_CLASS); |
|
| 1013 |
CONST_ID(id_overlayed_modules, "__overlayed_modules__"); |
|
| 1014 |
overlayed_modules = rb_attr_get(module, id_overlayed_modules); |
|
| 1015 |
if (NIL_P(overlayed_modules)) {
|
|
| 1016 |
overlayed_modules = rb_hash_new(); |
|
| 1017 |
rb_funcall(overlayed_modules, rb_intern("compare_by_identity"), 0);
|
|
| 1018 |
rb_ivar_set(module, id_overlayed_modules, overlayed_modules); |
|
| 1019 |
} |
|
| 1020 |
mod = rb_hash_aref(overlayed_modules, klass); |
|
| 1021 |
if (NIL_P(mod)) {
|
|
| 1022 |
mod = rb_module_new(); |
|
| 1023 |
CONST_ID(id_refined_class, "__refined_class__"); |
|
| 1024 |
rb_ivar_set(mod, id_refined_class, klass); |
|
| 1025 |
rb_define_singleton_method(mod, "method_added", |
|
| 1026 |
refinement_module_method_added, 1); |
|
| 1027 |
rb_define_singleton_method(mod, "include", |
|
| 1028 |
refinement_module_include, -1); |
|
| 1029 |
rb_overlay_module(cref, klass, mod); |
|
| 1030 |
rb_hash_aset(overlayed_modules, klass, mod); |
|
| 1031 |
} |
|
| 1032 |
rb_mod_module_eval(0, NULL, mod); |
|
| 1033 |
return mod; |
|
| 1034 |
} |
|
| 1035 | ||
| 1036 |
void |
|
| 861 | 1037 |
rb_obj_call_init(VALUE obj, int argc, VALUE *argv) |
| 862 | 1038 |
{
|
| 863 | 1039 |
PASS_PASSED_BLOCK(); |
| ... | ... | |
| 969 | 1145 |
return rb_mod_include(argc, argv, rb_cObject); |
| 970 | 1146 |
} |
| 971 | 1147 | |
| 1148 |
/* |
|
| 1149 |
* call-seq: |
|
| 1150 |
* using(module) -> self |
|
| 1151 |
* |
|
| 1152 |
* Import class refinements from <i>module</i> into the scope where <code>use</code> is called. |
|
| 1153 |
*/ |
|
| 1154 | ||
| 1155 |
static VALUE |
|
| 1156 |
f_using(VALUE self, VALUE module) |
|
| 1157 |
{
|
|
| 1158 |
NODE *cref = rb_vm_cref(); |
|
| 1159 | ||
| 1160 |
rb_using_module(cref, module); |
|
| 1161 |
return self; |
|
| 1162 |
} |
|
| 1163 | ||
| 972 | 1164 |
VALUE rb_f_trace_var(); |
| 973 | 1165 |
VALUE rb_f_untrace_var(); |
| 974 | 1166 | |
| ... | ... | |
| 1121 | 1313 |
rb_define_private_method(rb_cModule, "append_features", rb_mod_append_features, 1); |
| 1122 | 1314 |
rb_define_private_method(rb_cModule, "extend_object", rb_mod_extend_object, 1); |
| 1123 | 1315 |
rb_define_private_method(rb_cModule, "include", rb_mod_include, -1); |
| 1316 |
rb_define_private_method(rb_cModule, "using", rb_mod_using, 1); |
|
| 1317 |
rb_define_private_method(rb_cModule, "refine", rb_mod_refine, 1); |
|
| 1124 | 1318 | |
| 1125 | 1319 |
rb_undef_method(rb_cClass, "module_function"); |
| 1126 | 1320 | |
| ... | ... | |
| 1136 | 1330 | |
| 1137 | 1331 |
rb_define_singleton_method(rb_vm_top_self(), "include", top_include, -1); |
| 1138 | 1332 | |
| 1333 |
rb_define_global_function("using", f_using, 1);
|
|
| 1334 | ||
| 1139 | 1335 |
rb_define_method(rb_mKernel, "extend", rb_obj_extend, -1); |
| 1140 | 1336 | |
| 1141 | 1337 |
rb_define_global_function("trace_var", rb_f_trace_var, -1); /* in variable.c */
|
| b/gc.c | ||
|---|---|---|
| 1684 | 1684 |
ptr = (VALUE)obj->as.node.u2.node; |
| 1685 | 1685 |
goto again; |
| 1686 | 1686 | |
| 1687 |
case NODE_CREF: |
|
| 1688 |
gc_mark(objspace, obj->as.node.u0.value, lev); |
|
| 1689 |
gc_mark(objspace, (VALUE)obj->as.node.u1.node, lev); |
|
| 1690 |
ptr = (VALUE)obj->as.node.u3.node; |
|
| 1691 |
goto again; |
|
| 1692 | ||
| 1687 | 1693 |
default: /* unlisted NODE */ |
| 1688 | 1694 |
if (is_pointer_to_heap(objspace, obj->as.node.u1.node)) {
|
| 1689 | 1695 |
gc_mark(objspace, (VALUE)obj->as.node.u1.node, lev); |
| b/include/ruby/intern.h | ||
|---|---|---|
| 169 | 169 |
VALUE rb_module_new(void); |
| 170 | 170 |
VALUE rb_define_module_id(ID); |
| 171 | 171 |
VALUE rb_define_module_id_under(VALUE, ID); |
| 172 |
VALUE rb_include_class_new(VALUE, VALUE); |
|
| 172 | 173 |
VALUE rb_mod_included_modules(VALUE); |
| 173 | 174 |
VALUE rb_mod_include_p(VALUE, VALUE); |
| 174 | 175 |
VALUE rb_mod_ancestors(VALUE); |
| b/include/ruby/ruby.h | ||
|---|---|---|
| 629 | 629 |
#define RMODULE_CONST_TBL(m) RCLASS_CONST_TBL(m) |
| 630 | 630 |
#define RMODULE_M_TBL(m) RCLASS_M_TBL(m) |
| 631 | 631 |
#define RMODULE_SUPER(m) RCLASS_SUPER(m) |
| 632 |
#define RMODULE_IS_OVERLAYED FL_USER2 |
|
| 632 | 633 | |
| 633 | 634 |
struct RFloat {
|
| 634 | 635 |
struct RBasic basic; |
| b/insns.def | ||
|---|---|---|
| 183 | 183 |
() |
| 184 | 184 |
(VALUE val) |
| 185 | 185 |
{
|
| 186 |
NODE * const cref = vm_get_cref(GET_ISEQ(), GET_LFP(), GET_DFP()); |
|
| 187 |
val = rb_cvar_get(vm_get_cvar_base(cref), id); |
|
| 186 |
NODE * const cref = rb_vm_get_cref(GET_ISEQ(), GET_LFP(), GET_DFP());
|
|
| 187 |
val = rb_cvar_get(vm_get_cvar_base(cref, GET_CFP()), id);
|
|
| 188 | 188 |
} |
| 189 | 189 | |
| 190 | 190 |
/** |
| ... | ... | |
| 198 | 198 |
(VALUE val) |
| 199 | 199 |
() |
| 200 | 200 |
{
|
| 201 |
NODE * const cref = vm_get_cref(GET_ISEQ(), GET_LFP(), GET_DFP()); |
|
| 202 |
rb_cvar_set(vm_get_cvar_base(cref), id, val); |
|
| 201 |
NODE * const cref = rb_vm_get_cref(GET_ISEQ(), GET_LFP(), GET_DFP());
|
|
| 202 |
rb_cvar_set(vm_get_cvar_base(cref, GET_CFP()), id, val);
|
|
| 203 | 203 |
} |
| 204 | 204 | |
| 205 | 205 |
/** |
| ... | ... | |
| 967 | 967 |
VM_FRAME_MAGIC_CLASS, klass, 0, (VALUE) GET_BLOCK_PTR(), |
| 968 | 968 |
class_iseq->iseq_encoded, GET_SP(), 0, |
| 969 | 969 |
class_iseq->local_size); |
| 970 |
rb_vm_using_modules(class_iseq->cref_stack, klass); |
|
| 970 | 971 |
RESTORE_REGS(); |
| 971 | 972 | |
| 972 | 973 |
INC_VM_STATE_VERSION(); |
| ... | ... | |
| 1041 | 1042 |
while (ip && !ip->klass) {
|
| 1042 | 1043 |
ip = ip->parent_iseq; |
| 1043 | 1044 |
} |
| 1044 |
again: |
|
| 1045 | 1045 |
me = rb_method_entry(klass, id, &klass); |
| 1046 | 1046 |
if (me && me->def->type == VM_METHOD_TYPE_ISEQ && |
| 1047 | 1047 |
me->def->body.iseq == ip) {
|
| 1048 | 1048 |
klass = RCLASS_SUPER(klass); |
| 1049 |
goto again;
|
|
| 1049 |
me = rb_method_entry_get_with_omod(Qnil, klass, id, &klass);
|
|
| 1050 | 1050 |
} |
| 1051 | 1051 | |
| 1052 | 1052 |
CALL_METHOD(num, blockptr, flag, id, me, recv, klass); |
| b/iseq.c | ||
|---|---|---|
| 182 | 182 |
/* set class nest stack */ |
| 183 | 183 |
if (type == ISEQ_TYPE_TOP) {
|
| 184 | 184 |
/* toplevel is private */ |
| 185 |
iseq->cref_stack = NEW_BLOCK(rb_cObject);
|
|
| 186 |
iseq->cref_stack->nd_file = 0;
|
|
| 185 |
iseq->cref_stack = NEW_CREF(rb_cObject);
|
|
| 186 |
iseq->cref_stack->nd_omod = Qnil;
|
|
| 187 | 187 |
iseq->cref_stack->nd_visi = NOEX_PRIVATE; |
| 188 | 188 |
if (th->top_wrapper) {
|
| 189 |
NODE *cref = NEW_BLOCK(th->top_wrapper);
|
|
| 190 |
cref->nd_file = 0;
|
|
| 189 |
NODE *cref = NEW_CREF(th->top_wrapper);
|
|
| 190 |
cref->nd_omod = Qnil;
|
|
| 191 | 191 |
cref->nd_visi = NOEX_PRIVATE; |
| 192 | 192 |
cref->nd_next = iseq->cref_stack; |
| 193 | 193 |
iseq->cref_stack = cref; |
| 194 | 194 |
} |
| 195 | 195 |
} |
| 196 | 196 |
else if (type == ISEQ_TYPE_METHOD || type == ISEQ_TYPE_CLASS) {
|
| 197 |
iseq->cref_stack = NEW_BLOCK(0); /* place holder */
|
|
| 198 |
iseq->cref_stack->nd_file = 0;
|
|
| 197 |
iseq->cref_stack = NEW_CREF(0); /* place holder */
|
|
| 198 |
iseq->cref_stack->nd_omod = Qnil;
|
|
| 199 | 199 |
} |
| 200 | 200 |
else if (RTEST(parent)) {
|
| 201 | 201 |
rb_iseq_t *piseq; |
| ... | ... | |
| 1368 | 1368 |
iseq1->local_iseq = iseq1; |
| 1369 | 1369 |
} |
| 1370 | 1370 |
if (newcbase) {
|
| 1371 |
iseq1->cref_stack = NEW_BLOCK(newcbase); |
|
| 1371 |
iseq1->cref_stack = NEW_CREF(newcbase); |
|
| 1372 |
iseq1->cref_stack->nd_omod = iseq0->cref_stack->nd_omod; |
|
| 1373 |
iseq1->cref_stack->nd_visi = iseq0->cref_stack->nd_visi; |
|
| 1372 | 1374 |
if (iseq0->cref_stack->nd_next) {
|
| 1373 | 1375 |
iseq1->cref_stack->nd_next = iseq0->cref_stack->nd_next; |
| 1374 | 1376 |
} |
| b/method.h | ||
|---|---|---|
| 91 | 91 |
rb_method_entry_t *rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *option, rb_method_flag_t noex); |
| 92 | 92 |
rb_method_entry_t *rb_method_entry(VALUE klass, ID id, VALUE *define_class_ptr); |
| 93 | 93 | |
| 94 |
rb_method_entry_t *rb_method_entry_get_without_cache(VALUE klass, ID id, VALUE *define_class_ptr); |
|
| 94 |
rb_method_entry_t *rb_method_entry_get_with_omod(VALUE omod, VALUE klass, ID id, VALUE *define_class_ptr); |
|
| 95 |
rb_method_entry_t *rb_method_entry_get_without_cache(VALUE klass, VALUE omod, ID id, VALUE *define_class_ptr); |
|
| 95 | 96 |
rb_method_entry_t *rb_method_entry_set(VALUE klass, ID mid, const rb_method_entry_t *, rb_method_flag_t noex); |
| 96 | 97 | |
| 97 | 98 |
int rb_method_entry_arity(const rb_method_entry_t *me); |
| b/node.h | ||
|---|---|---|
| 188 | 188 |
#define NODE_COLON2 NODE_COLON2 |
| 189 | 189 |
NODE_COLON3, |
| 190 | 190 |
#define NODE_COLON3 NODE_COLON3 |
| 191 |
NODE_CREF, |
|
| 192 |
#define NODE_CREF NODE_CREF |
|
| 191 | 193 |
NODE_DOT2, |
| 192 | 194 |
#define NODE_DOT2 NODE_DOT2 |
| 193 | 195 |
NODE_DOT3, |
| ... | ... | |
| 234 | 236 | |
| 235 | 237 |
typedef struct RNode {
|
| 236 | 238 |
unsigned long flags; |
| 237 |
char *nd_file; |
|
| 239 |
union {
|
|
| 240 |
char *file; |
|
| 241 |
VALUE value; |
|
| 242 |
} u0; |
|
| 238 | 243 |
union {
|
| 239 | 244 |
struct RNode *node; |
| 240 | 245 |
ID id; |
| ... | ... | |
| 260 | 265 | |
| 261 | 266 |
#define RNODE(obj) (R_CAST(RNode)(obj)) |
| 262 | 267 | |
| 263 |
/* 0..4:T_TYPES, 5:FL_MARK, 6:reserved, 7:NODE_FL_NEWLINE */
|
|
| 268 |
/* 0..4:T_TYPES, 5:FL_MARK, 6:NODE_FL_CREF_OMOD_SHARED, 7:NODE_FL_NEWLINE */
|
|
| 264 | 269 |
#define NODE_FL_NEWLINE (((VALUE)1)<<7) |
| 265 | 270 |
#define NODE_FL_CREF_PUSHED_BY_EVAL NODE_FL_NEWLINE |
| 271 |
#define NODE_FL_CREF_OMOD_SHARED (((VALUE)1)<<6) |
|
| 266 | 272 | |
| 267 | 273 |
#define NODE_TYPESHIFT 8 |
| 268 | 274 |
#define NODE_TYPEMASK (((VALUE)0x7f)<<NODE_TYPESHIFT) |
| ... | ... | |
| 277 | 283 |
#define nd_set_line(n,l) \ |
| 278 | 284 |
RNODE(n)->flags=((RNODE(n)->flags&~(-1<<NODE_LSHIFT))|(((l)&NODE_LMASK)<<NODE_LSHIFT)) |
| 279 | 285 | |
| 286 |
#define nd_file u0.file |
|
| 287 |
#define nd_omod u0.value |
|
| 288 | ||
| 280 | 289 |
#define nd_head u1.node |
| 281 | 290 |
#define nd_alen u2.argc |
| 282 | 291 |
#define nd_next u3.node |
| ... | ... | |
| 433 | 442 |
#define NEW_MODULE(n,b) NEW_NODE(NODE_MODULE,n,NEW_SCOPE(0,b),0) |
| 434 | 443 |
#define NEW_COLON2(c,i) NEW_NODE(NODE_COLON2,c,i,0) |
| 435 | 444 |
#define NEW_COLON3(i) NEW_NODE(NODE_COLON3,0,i,0) |
| 445 |
#define NEW_CREF(a) NEW_NODE(NODE_CREF,a,0,0) |
|
| 436 | 446 |
#define NEW_DOT2(b,e) NEW_NODE(NODE_DOT2,b,e,0) |
| 437 | 447 |
#define NEW_DOT3(b,e) NEW_NODE(NODE_DOT3,b,e,0) |
| 438 | 448 |
#define NEW_SELF() NEW_NODE(NODE_SELF,0,0,0) |
| b/object.c | ||
|---|---|---|
| 2531 | 2531 |
rb_define_private_method(rb_cClass, "inherited", rb_obj_dummy, 1); |
| 2532 | 2532 |
rb_define_private_method(rb_cModule, "included", rb_obj_dummy, 1); |
| 2533 | 2533 |
rb_define_private_method(rb_cModule, "extended", rb_obj_dummy, 1); |
| 2534 |
rb_define_private_method(rb_cModule, "used", rb_obj_dummy, 1); |
|
| 2534 | 2535 |
rb_define_private_method(rb_cModule, "method_added", rb_obj_dummy, 1); |
| 2535 | 2536 |
rb_define_private_method(rb_cModule, "method_removed", rb_obj_dummy, 1); |
| 2536 | 2537 |
rb_define_private_method(rb_cModule, "method_undefined", rb_obj_dummy, 1); |
| b/test/ruby/test_refinement.rb | ||
|---|---|---|
| 1 |
require 'test/unit' |
|
| 2 | ||
| 3 |
class TestRefinement < Test::Unit::TestCase |
|
| 4 |
class Foo |
|
| 5 |
def x |
|
| 6 |
return "Foo#x" |
|
| 7 |
end |
|
| 8 | ||
| 9 |
def y |
|
| 10 |
return "Foo#y" |
|
| 11 |
end |
|
| 12 | ||
| 13 |
def call_x |
|
| 14 |
return x |
|
| 15 |
end |
|
| 16 |
end |
|
| 17 | ||
| 18 |
module FooExt |
|
| 19 |
refine Foo do |
|
| 20 |
def x |
|
| 21 |
return "FooExt#x" |
|
| 22 |
end |
|
| 23 | ||
| 24 |
def y |
|
| 25 |
return "FooExt#y " + super |
|
| 26 |
end |
|
| 27 | ||
| 28 |
def z |
|
| 29 |
return "FooExt#z" |
|
| 30 |
end |
|
| 31 |
end |
|
| 32 |
end |
|
| 33 | ||
| 34 |
module FooExt2 |
|
| 35 |
refine Foo do |
|
| 36 |
def x |
|
| 37 |
return "FooExt2#x" |
|
| 38 |
end |
|
| 39 | ||
| 40 |
def y |
|
| 41 |
return "FooExt2#y " + super |
|
| 42 |
end |
|
| 43 | ||
| 44 |
def z |
|
| 45 |
return "FooExt2#z" |
|
| 46 |
end |
|
| 47 |
end |
|
| 48 |
end |
|
| 49 | ||
| 50 |
class FooSub < Foo |
|
| 51 |
def x |
|
| 52 |
return "FooSub#x" |
|
| 53 |
end |
|
| 54 | ||
| 55 |
def y |
|
| 56 |
return "FooSub#y " + super |
|
| 57 |
end |
|
| 58 |
end |
|
| 59 | ||
| 60 |
class FooExtClient |
|
| 61 |
using FooExt |
|
| 62 | ||
| 63 |
def self.invoke_x_on(foo) |
|
| 64 |
return foo.x |
|
| 65 |
end |
|
| 66 | ||
| 67 |
def self.invoke_y_on(foo) |
|
| 68 |
return foo.y |
|
| 69 |
end |
|
| 70 | ||
| 71 |
def self.invoke_z_on(foo) |
|
| 72 |
return foo.z |
|
| 73 |
end |
|
| 74 | ||
| 75 |
def self.invoke_call_x_on(foo) |
|
| 76 |
return foo.call_x |
|
| 77 |
end |
|
| 78 |
end |
|
| 79 | ||
| 80 |
class FooExtClient2 |
|
| 81 |
using FooExt |
|
| 82 |
using FooExt2 |
|
| 83 | ||
| 84 |
def self.invoke_y_on(foo) |
|
| 85 |
return foo.y |
|
| 86 |
end |
|
| 87 |
end |
|
| 88 | ||
| 89 |
def test_override |
|
| 90 |
foo = Foo.new |
|
| 91 |
assert_equal("Foo#x", foo.x)
|
|
| 92 |
assert_equal("FooExt#x", FooExtClient.invoke_x_on(foo))
|
|
| 93 |
assert_equal("Foo#x", foo.x)
|
|
| 94 |
end |
|
| 95 | ||
| 96 |
def test_super |
|
| 97 |
foo = Foo.new |
|
| 98 |
assert_equal("Foo#y", foo.y)
|
|
| 99 |
assert_equal("FooExt#y Foo#y", FooExtClient.invoke_y_on(foo))
|
|
| 100 |
assert_equal("Foo#y", foo.y)
|
|
| 101 |
end |
|
| 102 | ||
| 103 |
def test_super_chain |
|
| 104 |
foo = Foo.new |
|
| 105 |
assert_equal("Foo#y", foo.y)
|
|
| 106 |
assert_equal("FooExt2#y FooExt#y Foo#y", FooExtClient2.invoke_y_on(foo))
|
|
| 107 |
assert_equal("Foo#y", foo.y)
|
|
| 108 |
end |
|
| 109 | ||
| 110 |
def test_new_method |
|
| 111 |
foo = Foo.new |
|
| 112 |
assert_raise(NoMethodError) { foo.z }
|
|
| 113 |
assert_equal("FooExt#z", FooExtClient.invoke_z_on(foo))
|
|
| 114 |
assert_raise(NoMethodError) { foo.z }
|
|
| 115 |
end |
|
| 116 | ||
| 117 |
def test_no_local_rebinding |
|
| 118 |
foo = Foo.new |
|
| 119 |
assert_equal("Foo#x", foo.call_x)
|
|
| 120 |
assert_equal("Foo#x", FooExtClient.invoke_call_x_on(foo))
|
|
| 121 |
assert_equal("Foo#x", foo.call_x)
|
|
| 122 |
end |
|
| 123 | ||
| 124 |
def test_subclass_is_prior |
|
| 125 |
sub = FooSub.new |
|
| 126 |
assert_equal("FooSub#x", sub.x)
|
|
| 127 |
assert_equal("FooSub#x", FooExtClient.invoke_x_on(sub))
|
|
| 128 |
assert_equal("FooSub#x", sub.x)
|
|
| 129 |
end |
|
| 130 | ||
| 131 |
def test_subclass_is_prior |
|
| 132 |
sub = FooSub.new |
|
| 133 |
assert_equal("FooSub#x", sub.x)
|
|
| 134 |
assert_equal("FooSub#x", FooExtClient.invoke_x_on(sub))
|
|
| 135 |
assert_equal("FooSub#x", sub.x)
|
|
| 136 |
end |
|
| 137 | ||
| 138 |
def test_super_in_subclass |
|
| 139 |
sub = FooSub.new |
|
| 140 |
assert_equal("FooSub#y Foo#y", sub.y)
|
|
| 141 |
# not "FooSub#y FooExt#y Foo#y" |
|
| 142 |
assert_equal("FooSub#y Foo#y", FooExtClient.invoke_y_on(sub))
|
|
| 143 |
assert_equal("FooSub#y Foo#y", sub.y)
|
|
| 144 |
end |
|
| 145 | ||
| 146 |
def test_new_method_on_subclass |
|
| 147 |
sub = FooSub.new |
|
| 148 |
assert_raise(NoMethodError) { sub.z }
|
|
| 149 |
assert_equal("FooExt#z", FooExtClient.invoke_z_on(sub))
|
|
| 150 |
assert_raise(NoMethodError) { sub.z }
|
|
| 151 |
end |
|
| 152 | ||
| 153 |
def test_module_eval |
|
| 154 |
foo = Foo.new |
|
| 155 |
assert_equal("Foo#x", foo.x)
|
|
| 156 |
assert_equal("FooExt#x", FooExt.module_eval { foo.x })
|
|
| 157 |
assert_equal("Foo#x", foo.x)
|
|
| 158 |
end |
|
| 159 | ||
| 160 |
def test_instance_eval |
|
| 161 |
foo = Foo.new |
|
| 162 |
ext_client = FooExtClient.new |
|
| 163 |
assert_equal("Foo#x", foo.x)
|
|
| 164 |
assert_equal("FooExt#x", ext_client.instance_eval { foo.x })
|
|
| 165 |
assert_equal("Foo#x", foo.x)
|
|
| 166 |
end |
|
| 167 | ||
| 168 |
def test_override_builtin_method |
|
| 169 |
m = Module.new {
|
|
| 170 |
refine Fixnum do |
|
| 171 |
def /(other) quo(other) end |
|
| 172 |
end |
|
| 173 |
} |
|
| 174 |
assert_equal(0, 1 / 2) |
|
| 175 |
assert_equal(Rational(1, 2), m.module_eval { 1 / 2 })
|
|
| 176 |
assert_equal(0, 1 / 2) |
|
| 177 |
end |
|
| 178 | ||
| 179 |
def test_return_value_of_refine |
|
| 180 |
mod = nil |
|
| 181 |
result = nil |
|
| 182 |
m = Module.new {
|
|
| 183 |
result = refine(Object) {
|
|
| 184 |
mod = self |
|
| 185 |
} |
|
| 186 |
} |
|
| 187 |
assert_equal mod, result |
|
| 188 |
end |
|
| 189 | ||
| 190 |
def test_refine_same_class_twice |
|
| 191 |
result1 = nil |
|
| 192 |
result2 = nil |
|
| 193 |
result3 = nil |
|
| 194 |
m = Module.new {
|
|
| 195 |
result1 = refine(Fixnum) {
|
|
| 196 |
def foo; return "foo" end |
|
| 197 |
} |
|
| 198 |
result2 = refine(Fixnum) {
|
|
| 199 |
def bar; return "bar" end |
|
| 200 |
} |
|
| 201 |
result3 = refine(String) {
|
|
| 202 |
def baz; return "baz" end |
|
| 203 |
} |
|
| 204 |
} |
|
| 205 |
assert_equal("foo", m.module_eval { 1.foo })
|
|
| 206 |
assert_equal("bar", m.module_eval { 1.bar })
|
|
| 207 |
assert_equal(result1, result2) |
|
| 208 |
assert_not_equal(result1, result3) |
|
| 209 |
end |
|
| 210 | ||
| 211 |
def test_respond_to? |
|
| 212 |
m = Module.new {
|
|
| 213 |
refine Fixnum do |
|
| 214 |
def foo; "foo"; end |
|
| 215 |
end |
|
| 216 |
} |
|
| 217 |
assert_equal(false, 1.respond_to?(:foo)) |
|
| 218 |
assert_equal(true, m.module_eval { 1.respond_to?(:foo) })
|
|
| 219 |
assert_equal(false, 1.respond_to?(:foo)) |
|
| 220 |
end |
|
| 221 | ||
| 222 |
def test_builtin_method_no_local_rebinding |
|
| 223 |
m = Module.new {
|
|
| 224 |
refine String do |
|
| 225 |
def <=>(other) return 0 end |
|
| 226 |
end |
|
| 227 |
} |
|
| 228 |
assert_equal(false, m.module_eval { "1" >= "2" })
|
|
| 229 | ||
| 230 |
m2 = Module.new {
|
|
| 231 |
refine Array do |
|
| 232 |
def each |
|
| 233 |
super do |i| |
|
| 234 |
yield 2 * i |
|
| 235 |
end |
|
| 236 |
end |
|
| 237 |
end |
|
| 238 |
} |
|
| 239 |
a = [1, 2, 3] |
|
| 240 |
assert_equal(1, m2.module_eval { a.min })
|
|
| 241 |
end |
|
| 242 | ||
| 243 |
def test_module_inclusion |
|
| 244 |
m1 = Module.new {
|
|
| 245 |
def foo |
|
| 246 |
"m1#foo" |
|
| 247 |
end |
|
| 248 | ||
| 249 |
def bar |
|
| 250 |
"m1#bar" |
|
| 251 |
end |
|
| 252 |
} |
|
| 253 |
m2 = Module.new {
|
|
| 254 |
def bar |
|
| 255 |
"m2#bar" |
|
| 256 |
end |
|
| 257 | ||
| 258 |
def baz |
|
| 259 |
"m2#baz" |
|
| 260 |
end |
|
| 261 |
} |
|
| 262 |
m3 = Module.new {
|
|
| 263 |
def baz |
|
| 264 |
"m3#baz" |
|
| 265 |
end |
|
| 266 |
} |
|
| 267 |
include_proc = Proc.new {
|
|
| 268 |
include m3, m2 |
|
| 269 |
} |
|
| 270 |
m = Module.new {
|
|
| 271 |
refine String do |
|
| 272 |
include m1 |
|
| 273 |
module_eval(&include_proc) |
|
| 274 | ||
| 275 |
def call_foo |
|
| 276 |
foo |
|
| 277 |
end |
|
| 278 | ||
| 279 |
def call_bar |
|
| 280 |
bar |
|
| 281 |
end |
|
| 282 | ||
| 283 |
def call_baz |
|
| 284 |
baz |
|
| 285 |
end |
|
| 286 |
end |
|
| 287 | ||
| 288 |
def self.call_foo(s) |
|
| 289 |
s.foo |
|
| 290 |
end |
|
| 291 | ||
| 292 |
def self.call_bar(s) |
|
| 293 |
s.bar |
|
| 294 |
end |
|
| 295 | ||
| 296 |
def self.call_baz(s) |
|
| 297 |
s.baz |
|
| 298 |
end |
|
| 299 |
} |
|
| 300 |
assert_equal("m1#foo", m.module_eval { "abc".foo })
|
|
| 301 |
assert_equal("m2#bar", m.module_eval { "abc".bar })
|
|
| 302 |
assert_equal("m3#baz", m.module_eval { "abc".baz })
|
|
| 303 |
assert_equal("m1#foo", m.module_eval { "abc".call_foo })
|
|
| 304 |
assert_equal("m2#bar", m.module_eval { "abc".call_bar })
|
|
| 305 |
assert_equal("m3#baz", m.module_eval { "abc".call_baz })
|
|
| 306 |
assert_equal("m1#foo", m.call_foo("abc"))
|
|
| 307 |
assert_equal("m2#bar", m.call_bar("abc"))
|
|
| 308 |
assert_equal("m3#baz", m.call_baz("abc"))
|
|
| 309 |
end |
|
| 310 |
end |
|
| 311 | ||
| b/vm.c | ||
|---|---|---|
| 819 | 819 |
{
|
| 820 | 820 |
rb_thread_t *th = GET_THREAD(); |
| 821 | 821 |
rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(th, th->cfp); |
| 822 |
return vm_get_cref(cfp->iseq, cfp->lfp, cfp->dfp); |
|
| 822 |
if (!cfp) return NULL; |
|
| 823 |
return rb_vm_get_cref(cfp->iseq, cfp->lfp, cfp->dfp); |
|
| 823 | 824 |
} |
| 824 | 825 | |
| 825 | 826 |
#if 0 |
| b/vm_eval.c | ||
|---|---|---|
| 372 | 372 |
rb_id2name(mid), type, (void *)recv, flags, klass); |
| 373 | 373 |
} |
| 374 | 374 |
} |
| 375 |
return rb_method_entry(klass, mid, defined_class_ptr);
|
|
| 375 |
return rb_method_entry_get_with_omod(Qnil, klass, mid, defined_class_ptr);
|
|
| 376 | 376 |
} |
| 377 | 377 | |
| 378 | 378 |
static inline int |
| ... | ... | |
| 1213 | 1213 |
} |
| 1214 | 1214 |
cref = vm_cref_push(th, under, NOEX_PUBLIC, blockptr); |
| 1215 | 1215 |
cref->flags |= NODE_FL_CREF_PUSHED_BY_EVAL; |
| 1216 |
rb_vm_using_modules(cref, under); |
|
| 1216 | 1217 | |
| 1217 | 1218 |
if (values == Qundef) {
|
| 1218 | 1219 |
return vm_yield_with_cref(th, 1, &self, cref); |
| ... | ... | |
| 1234 | 1235 |
else {
|
| 1235 | 1236 |
SafeStringValue(src); |
| 1236 | 1237 |
} |
| 1238 |
rb_vm_using_modules(cref, under); |
|
| 1237 | 1239 | |
| 1238 | 1240 |
return eval_string_with_cref(self, src, Qnil, cref, file, line); |
| 1239 | 1241 |
} |
| b/vm_insnhelper.c | ||
|---|---|---|
| 1091 | 1091 |
} |
| 1092 | 1092 |
} |
| 1093 | 1093 | |
| 1094 |
static NODE *
|
|
| 1095 |
vm_get_cref(const rb_iseq_t *iseq, const VALUE *lfp, const VALUE *dfp) |
|
| 1094 |
NODE * |
|
| 1095 |
rb_vm_get_cref(const rb_iseq_t *iseq, const VALUE *lfp, const VALUE *dfp)
|
|
| 1096 | 1096 |
{
|
| 1097 | 1097 |
NODE *cref = vm_get_cref0(iseq, lfp, dfp); |
| 1098 | 1098 | |
| 1099 | 1099 |
if (cref == 0) {
|
| 1100 |
rb_bug("vm_get_cref: unreachable");
|
|
| 1100 |
rb_bug("rb_vm_get_cref: unreachable");
|
|
| 1101 | 1101 |
} |
| 1102 | 1102 |
return cref; |
| 1103 | 1103 |
} |
| ... | ... | |
| 1106 | 1106 |
vm_cref_push(rb_thread_t *th, VALUE klass, int noex, rb_block_t *blockptr) |
| 1107 | 1107 |
{
|
| 1108 | 1108 |
rb_control_frame_t *cfp = vm_get_ruby_level_caller_cfp(th, th->cfp); |
| 1109 |
NODE *cref = NEW_BLOCK(klass);
|
|
| 1110 |
cref->nd_file = 0;
|
|
| 1109 |
NODE *cref = NEW_CREF(klass);
|
|
| 1110 |
cref->nd_omod = Qnil;
|
|
| 1111 | 1111 |
cref->nd_visi = noex; |
| 1112 | 1112 | |
| 1113 | 1113 |
if (blockptr) {
|
| ... | ... | |
| 1116 | 1116 |
else if (cfp) {
|
| 1117 | 1117 |
cref->nd_next = vm_get_cref0(cfp->iseq, cfp->lfp, cfp->dfp); |
| 1118 | 1118 |
} |
| 1119 |
/* TODO: why cref->nd_next is 1? */ |
|
| 1120 |
if (cref->nd_next && cref->nd_next != (void *) 1 && |
|
| 1121 |
!NIL_P(cref->nd_next->nd_omod)) {
|
|
| 1122 |
COPY_CREF_OMOD(cref, cref->nd_next); |
|
| 1123 |
} |
|
| 1119 | 1124 | |
| 1120 | 1125 |
return cref; |
| 1121 | 1126 |
} |
| ... | ... | |
| 1123 | 1128 |
static inline VALUE |
| 1124 | 1129 |
vm_get_cbase(const rb_iseq_t *iseq, const VALUE *lfp, const VALUE *dfp) |
| 1125 | 1130 |
{
|
| 1126 |
NODE *cref = vm_get_cref(iseq, lfp, dfp); |
|
| 1131 |
NODE *cref = rb_vm_get_cref(iseq, lfp, dfp);
|
|
| 1127 | 1132 |
VALUE klass = Qundef; |
| 1128 | 1133 | |
| 1129 | 1134 |
while (cref) {
|
| ... | ... | |
| 1139 | 1144 |
static inline VALUE |
| 1140 | 1145 |
vm_get_const_base(const rb_iseq_t *iseq, const VALUE *lfp, const VALUE *dfp) |
| 1141 | 1146 |
{
|
| 1142 |
NODE *cref = vm_get_cref(iseq, lfp, dfp); |
|
| 1147 |
NODE *cref = rb_vm_get_cref(iseq, lfp, dfp);
|
|
| 1143 | 1148 |
VALUE klass = Qundef; |
| 1144 | 1149 | |
| 1145 | 1150 |
while (cref) {
|
| ... | ... | |
| 1167 | 1172 |
} |
| 1168 | 1173 | |
| 1169 | 1174 |
static inline VALUE |
| 1175 |
vm_get_iclass(rb_control_frame_t *cfp, VALUE klass) |
|
| 1176 |
{
|
|
| 1177 |
if (TYPE(klass) == T_MODULE && |
|
| 1178 |
FL_TEST(klass, RMODULE_IS_OVERLAYED) && |
|
| 1179 |
TYPE(cfp->klass) == T_ICLASS && |
|
| 1180 |
RBASIC(cfp->klass)->klass == klass) {
|
|
| 1181 |
return cfp->klass; |
|
| 1182 |
} |
|
| 1183 |
else {
|
|
| 1184 |
return klass; |
|
| 1185 |
} |
|
| 1186 |
} |
|
| 1187 | ||
| 1188 |
static inline VALUE |
|
| 1170 | 1189 |
vm_get_ev_const(rb_thread_t *th, const rb_iseq_t *iseq, |
| 1171 | 1190 |
VALUE orig_klass, ID id, int is_defined) |
| 1172 | 1191 |
{
|
| ... | ... | |
| 1174 | 1193 | |
| 1175 | 1194 |
if (orig_klass == Qnil) {
|
| 1176 | 1195 |
/* in current lexical scope */ |
| 1177 |
const NODE *cref = vm_get_cref(iseq, th->cfp->lfp, th->cfp->dfp); |
|
| 1196 |
const NODE *cref = rb_vm_get_cref(iseq, th->cfp->lfp, th->cfp->dfp);
|
|
| 1178 | 1197 |
const NODE *root_cref = NULL; |
| 1179 | 1198 |
VALUE klass = orig_klass; |
| 1180 | 1199 | |
| ... | ... | |
| 1213 | 1232 | |
| 1214 | 1233 |
/* search self */ |
| 1215 | 1234 |
if (root_cref && !NIL_P(root_cref->nd_clss)) {
|
| 1216 |
klass = root_cref->nd_clss;
|
|
| 1235 |
klass = vm_get_iclass(th->cfp, root_cref->nd_clss);
|
|
| 1217 | 1236 |
} |
| 1218 | 1237 |
else {
|
| 1219 | 1238 |
klass = CLASS_OF(th->cfp->self); |
| ... | ... | |
| 1238 | 1257 |
} |
| 1239 | 1258 | |
| 1240 | 1259 |
static inline VALUE |
| 1241 |
vm_get_cvar_base(NODE *cref) |
|
| 1260 |
vm_get_cvar_base(NODE *cref, rb_control_frame_t *cfp)
|
|
| 1242 | 1261 |
{
|
| 1243 | 1262 |
VALUE klass; |
| 1244 | 1263 | |
| ... | ... | |
| 1252 | 1271 |
} |
| 1253 | 1272 |
} |
| 1254 | 1273 | |
| 1255 |
klass = cref->nd_clss;
|
|
| 1274 |
klass = vm_get_iclass(cfp, cref->nd_clss);
|
|
| 1256 | 1275 | |
| 1257 | 1276 |
if (NIL_P(klass)) {
|
| 1258 | 1277 |
rb_raise(rb_eTypeError, "no class variables available"); |
| ... | ... | |
| 1727 | 1746 |
return Qundef; |
| 1728 | 1747 |
} |
| 1729 | 1748 | |
| 1749 |
void rb_using_module(NODE *cref, VALUE module); |
|
| 1750 | ||
| 1751 |
static int |
|
| 1752 |
vm_using_module_i(VALUE module, VALUE value, VALUE arg) |
|
| 1753 |
{
|
|
| 1754 |
NODE *cref = (NODE *) arg; |
|
| 1755 | ||
| 1756 |
rb_using_module(cref, module); |
|
| 1757 |
return ST_CONTINUE; |
|
| 1758 |
} |
|
| 1759 | ||
| 1760 |
static void |
|
| 1761 |
rb_vm_using_modules(NODE *cref, VALUE klass) |
|
| 1762 |
{
|
|
| 1763 |
ID id_using_modules; |
|
| 1764 |
VALUE using_modules; |
|
| 1765 | ||
| 1766 |
CONST_ID(id_using_modules, "__using_modules__"); |
|
| 1767 |
using_modules = rb_attr_get(klass, id_using_modules); |
|
| 1768 |
switch (TYPE(klass)) {
|
|
| 1769 |
case T_CLASS: |
|
| 1770 |
if (NIL_P(using_modules)) {
|
|
| 1771 |
VALUE super = rb_class_real(RCLASS_SUPER(klass)); |
|
| 1772 |
using_modules = rb_attr_get(super, id_using_modules); |
|
| 1773 |
if (!NIL_P(using_modules)) {
|
|
| 1774 |
using_modules = rb_hash_dup(using_modules); |
|
| 1775 |
rb_ivar_set(klass, id_using_modules, using_modules); |
|
| 1776 |
} |
|
| 1777 |
} |
|
| 1778 |
break; |
|
| 1779 |
case T_MODULE: |
|
| 1780 |
rb_using_module(cref, klass); |
|
| 1781 |
break; |
|
| 1782 |
} |
|
| 1783 |
if (!NIL_P(using_modules)) {
|
|
| 1784 |
rb_hash_foreach(using_modules, vm_using_module_i, |
|
| 1785 |
(VALUE) cref); |
|
| 1786 |
} |
|
| 1787 |
} |
|
| 1788 | ||
| b/vm_insnhelper.h | ||
|---|---|---|
| 149 | 149 |
/* deal with control flow 2: method/iterator */ |
| 150 | 150 |
/**********************************************************/ |
| 151 | 151 | |
| 152 |
#define COPY_CREF_OMOD(c1, c2) do { \
|
|
| 153 |
c1->nd_omod = c2->nd_omod; \ |
|
| 154 |
if (!NIL_P(c2->nd_omod)) { \
|
|
| 155 |
c1->flags |= NODE_FL_CREF_OMOD_SHARED; \ |
|
| 156 |
c2->flags |= NODE_FL_CREF_OMOD_SHARED; \ |
|
| 157 |
} \ |
|
| 158 |
} while (0) |
|
| 159 | ||
| 152 | 160 |
#define COPY_CREF(c1, c2) do { \
|
| 153 | 161 |
NODE *__tmp_c2 = (c2); \ |
| 162 |
COPY_CREF_OMOD(c1, __tmp_c2); \ |
|
| 154 | 163 |
c1->nd_clss = __tmp_c2->nd_clss; \ |
| 155 | 164 |
c1->nd_visi = __tmp_c2->nd_visi;\ |
| 156 | 165 |
c1->nd_next = __tmp_c2->nd_next; \ |
| b/vm_method.c | ||
|---|---|---|
| 4 | 4 | |
| 5 | 5 |
#define CACHE_SIZE 0x800 |
| 6 | 6 |
#define CACHE_MASK 0x7ff |
| 7 |
#define EXPR1(c,m) ((((c)>>3)^(m))&CACHE_MASK)
|
|
| 7 |
#define EXPR1(c,o,m) ((((c)>>3)^((o)>>3)^(m))&CACHE_MASK)
|
|
| 8 | 8 | |
| 9 | 9 |
static void rb_vm_check_redefinition_opt_method(const rb_method_entry_t *me); |
| 10 | 10 | |
| ... | ... | |
| 15 | 15 |
struct cache_entry { /* method hash table. */
|
| 16 | 16 |
ID mid; /* method's id */ |
| 17 | 17 |
VALUE klass; /* receiver's class */ |
| 18 |
VALUE omod; /* overlay modules */ |
|
| 18 | 19 |
rb_method_entry_t *me; |
| 19 | 20 |
VALUE defined_class; |
| 20 | 21 |
}; |
| ... | ... | |
| 393 | 394 |
} |
| 394 | 395 | |
| 395 | 396 |
static rb_method_entry_t* |
| 396 |
search_method(VALUE klass, ID id, VALUE *defined_class_ptr) |
|
| 397 |
search_method(VALUE klass, ID id, VALUE omod, VALUE *defined_class_ptr)
|
|
| 397 | 398 |
{
|
| 398 | 399 |
st_data_t body; |
| 400 |
VALUE iclass, skipped_class = Qnil; |
|
| 401 | ||
| 399 | 402 |
if (!klass) {
|
| 400 | 403 |
return 0; |
| 401 | 404 |
} |
| 402 | 405 | |
| 406 |
if (!NIL_P(omod) && !NIL_P(iclass = rb_hash_lookup(omod, klass))) {
|
|
| 407 |
klass = iclass; |
|
| 408 |
} |
|
| 403 | 409 |
while (!st_lookup(RCLASS_M_TBL(klass), id, &body)) {
|
| 404 | 410 |
klass = RCLASS_SUPER(klass); |
| 411 |
if (!NIL_P(omod) && klass != skipped_class && |
|
| 412 |
!NIL_P(iclass = rb_hash_lookup(omod, klass))) {
|
|
| 413 |
skipped_class = klass; |
|
| 414 |
klass = iclass; |
|
| 415 |
} |
|
| 405 | 416 |
if (!klass) {
|
| 406 | 417 |
return 0; |
| 407 | 418 |
} |
| ... | ... | |
| 419 | 430 |
* rb_method_entry() simply. |
| 420 | 431 |
*/ |
| 421 | 432 |
rb_method_entry_t * |
| 422 |
rb_method_entry_get_without_cache(VALUE klass, ID id, VALUE *defined_class_ptr) |
|
| 433 |
rb_method_entry_get_without_cache(VALUE klass, VALUE omod, ID id, VALUE *defined_class_ptr)
|
|
| 423 | 434 |
{
|
| 424 |
VALUE defined_class; |
|
| 435 |
VALUE iclass, defined_class;
|
|
| 425 | 436 |
rb_method_entry_t *me; |
| 426 | 437 | |
| 427 |
me = search_method(klass, id, &defined_class); |
|
| 438 |
me = search_method(klass, id, omod, &defined_class);
|
|
| 428 | 439 | |
| 429 | 440 |
if (ruby_running) {
|
| 430 | 441 |
struct cache_entry *ent; |
| 431 |
ent = cache + EXPR1(klass, id); |
|
| 442 |
ent = cache + EXPR1(klass, omod, id);
|
|
| 432 | 443 |
ent->klass = klass; |
| 444 |
ent->omod = omod; |
|
| 433 | 445 |
ent->defined_class = defined_class; |
| 434 | 446 | |
| 435 | 447 |
if (UNDEFINED_METHOD_ENTRY_P(me)) {
|
| ... | ... | |
| 449 | 461 |
} |
| 450 | 462 | |
| 451 | 463 |
rb_method_entry_t * |
| 452 |
rb_method_entry(VALUE klass, ID id, VALUE *defined_class_ptr) |
|
| 464 |
rb_method_entry_get_with_omod(VALUE omod, VALUE klass, ID id, |
|
| 465 |
VALUE *defined_class_ptr) |
|
| 453 | 466 |
{
|
| 454 | 467 |
struct cache_entry *ent; |
| 455 | 468 | |
| 456 |
ent = cache + EXPR1(klass, id); |
|
| 457 |
if (ent->mid == id && ent->klass == klass) {
|
|
| 469 |
ent = cache + EXPR1(klass, omod, id);
|
|
| 470 |
if (ent->mid == id && ent->klass == klass && ent->omod == omod) {
|
|
| 458 | 471 |
if (defined_class_ptr) |
| 459 | 472 |
*defined_class_ptr = ent->defined_class; |
| 460 | 473 |
return ent->me; |
| 461 | 474 |
} |
| 462 | 475 | |
| 463 |
return rb_method_entry_get_without_cache(klass, id, defined_class_ptr); |
|
| 476 |
return rb_method_entry_get_without_cache(klass, omod, id, |
|
| 477 |
defined_class_ptr); |
|
| 478 |
} |
|
| 479 | ||
| 480 |
rb_method_entry_t * |
|
| 481 |
rb_method_entry(VALUE klass, ID id, VALUE *defined_class_ptr) |
|
| 482 |
{
|
|
| 483 |
struct cache_entry *ent; |
|
| 484 |
NODE *cref = rb_vm_cref(); |
|
| 485 |
VALUE omod = Qnil; |
|
| 486 | ||
| 487 |
if (cref && !NIL_P(cref->nd_omod)) {
|
|
| 488 |
omod = cref->nd_omod; |
|
| 489 |
} |
|
| 490 |
return rb_method_entry_get_with_omod(omod, klass, id, defined_class_ptr); |
|
| 464 | 491 |
} |
| 465 | 492 | |
| 466 | 493 |
static void |
| ... | ... | |
| 552 | 579 |
rb_secure(4); |
| 553 | 580 |
} |
| 554 | 581 | |
| 555 |
me = search_method(klass, name, &defined_class); |
|
| 582 |
me = search_method(klass, name, Qnil, &defined_class);
|
|
| 556 | 583 |
if (!me && TYPE(klass) == T_MODULE) {
|
| 557 |
me = search_method(rb_cObject, name, &defined_class); |
|
| 584 |
me = search_method(rb_cObject, name, Qnil, &defined_class);
|
|
| 558 | 585 |
} |
| 559 | 586 | |
| 560 | 587 |
if (UNDEFINED_METHOD_ENTRY_P(me)) {
|
| ... | ... | |
| 640 | 667 |
rb_undef(VALUE klass, ID id) |
| 641 | 668 |
{
|
| 642 | 669 |
rb_method_entry_t *me; |
| 670 |
NODE *cref = rb_vm_cref(); |
|
| 671 |
VALUE omod = Qnil; |
|
| 643 | 672 | |
| 644 | 673 |
if (NIL_P(klass)) {
|
| 645 | 674 |
rb_raise(rb_eTypeError, "no class to undef method"); |
| ... | ... | |
| 655 | 684 |
rb_warn("undefining `%s' may cause serious problems", rb_id2name(id));
|
| 656 | 685 |
} |
| 657 | 686 | |
| 658 |
me = search_method(klass, id, 0); |
|
| 687 |
if (cref && !NIL_P(cref->nd_omod)) {
|
|
| 688 |
omod = cref->nd_omod; |
|
| 689 |
} |
|
| 690 |
me = search_method(klass, id, omod, 0); |
|
| 659 | 691 | |
| 660 | 692 |
if (UNDEFINED_METHOD_ENTRY_P(me)) {
|
| 661 | 693 |
const char *s0 = " class"; |
| ... | ... | |
| 678 | 710 |
rb_id2name(id), s0, rb_class2name(c)); |
| 679 | 711 |
} |
| 680 | 712 | |
| 713 |
if (!RTEST(rb_class_inherited_p(klass, me->klass))) {
|
|
| 714 |
VALUE mod = rb_module_new(); |
|
| 715 |
rb_overlay_module(cref, klass, mod); |
|
| 716 |
klass = mod; |
|
| 717 |
} |
|
| 681 | 718 |
rb_add_method(klass, id, VM_METHOD_TYPE_UNDEF, 0, NOEX_PUBLIC); |
| 682 | 719 | |
| 683 | 720 |
CALL_METHOD_HOOK(klass, undefined, id); |
| ... | ... | |
| 939 | 976 |
} |
| 940 | 977 | |
| 941 | 978 |
again: |
| 942 |
orig_me = search_method(klass, def, 0); |
|
| 979 |
orig_me = search_method(klass, def, Qnil, 0);
|
|
| 943 | 980 | |
| 944 | 981 |
if (UNDEFINED_METHOD_ENTRY_P(orig_me)) {
|
| 945 | 982 |
if ((TYPE(klass) != T_MODULE) || |
| 946 |
(orig_me = search_method(rb_cObject, def, 0), |
|
| 983 |
(orig_me = search_method(rb_cObject, def, Qnil, 0),
|
|
| 947 | 984 |
UNDEFINED_METHOD_ENTRY_P(orig_me))) {
|
| 948 | 985 |
rb_print_undef(klass, def, 0); |
| 949 | 986 |
} |
| ... | ... | |
| 1205 | 1242 | |
| 1206 | 1243 |
id = rb_to_id(argv[i]); |
| 1207 | 1244 |
for (;;) {
|
| 1208 |
me = search_method(m, id, 0); |
|
| 1245 |
me = search_method(m, id, Qnil, 0);
|
|
| 1209 | 1246 |
if (me == 0) {
|
| 1210 |
me = search_method(rb_cObject, id, 0); |
|
| 1247 |
me = search_method(rb_cObject, id, Qnil, 0);
|
|
| 1211 | 1248 |
} |
| 1212 | 1249 |
if (UNDEFINED_METHOD_ENTRY_P(me)) {
|
| 1213 | 1250 |
rb_print_undef(module, id, 0); |
| ... | ... | |
| 1313 | 1350 |
} |
| 1314 | 1351 | |
| 1315 | 1352 |
void |
| 1353 |
rb_redefine_opt_method(VALUE klass, ID mid) |
|
| 1354 |
{
|
|
| 1355 |
st_data_t key, data; |
|
| 1356 |
rb_method_entry_t *me = 0; |
|
| 1357 | ||
| 1358 |
if (!st_lookup(RCLASS_M_TBL(klass), mid, &data) || |
|
| 1359 |
!(me = (rb_method_entry_t *)data) || |
|
| 1360 |
(!me->def || me->def->type == VM_METHOD_TYPE_UNDEF)) {
|
|
| 1361 |
return; |
|
| 1362 |
} |
|
| 1363 |
rb_vm_check_redefinition_opt_method(me); |
|
| 1364 |
} |
|
| 1365 | ||
| 1366 |
void |
|
| 1316 | 1367 |
Init_eval_method(void) |
| 1317 | 1368 |
{
|
| 1318 | 1369 |
#undef rb_intern |