Permalink
Browse files

when including a module that defines a special method (currently -ini…

…tialize), make sure to copy it to the original class too if the later doesn't define it

git-svn-id: http://svn.macosforge.org/repository/ruby/MacRuby/trunk@3007 23306eb0-4c56-4727-a40e-e92c0eb68959
  • Loading branch information...
1 parent e81f2af commit 86da8898c9f5e6848001c41784f8be08bbbfd1ab @lrz lrz committed Nov 14, 2009
Showing with 79 additions and 34 deletions.
  1. +20 −2 class.c
  2. +2 −1 eval.c
  3. +2 −0 include/ruby/ruby.h
  4. +2 −4 object.c
  5. +50 −27 vm.cpp
  6. +3 −0 vm.h
View
22 class.c
@@ -575,7 +575,8 @@ rb_define_module_under(VALUE outer, const char *name)
}
void
-rb_include_module2(VALUE klass, VALUE module, int check, int add_methods)
+rb_include_module2(VALUE klass, VALUE orig_klass, VALUE module, bool check,
+ bool add_methods)
{
if (check) {
rb_frozen_class_p(klass);
@@ -585,6 +586,7 @@ rb_include_module2(VALUE klass, VALUE module, int check, int add_methods)
Check_Type(module, T_MODULE);
}
+ // Register the module as included in the class.
VALUE ary = rb_attr_get(klass, idIncludedModules);
if (ary == Qnil) {
ary = rb_ary_new();
@@ -597,30 +599,46 @@ rb_include_module2(VALUE klass, VALUE module, int check, int add_methods)
}
rb_ary_insert(ary, 0, module);
+ // Mark the module as included somewhere.
const long v = RCLASS_VERSION(module) | RCLASS_IS_INCLUDED;
RCLASS_SET_VERSION(module, v);
+ // Register the class as included in the module.
ary = rb_attr_get(module, idIncludedInClasses);
if (ary == Qnil) {
ary = rb_ary_new();
rb_ivar_set(module, idIncludedInClasses, ary);
}
rb_ary_push(ary, klass);
+ // Delete the ancestors array if it exists, since we just changed it.
CFMutableDictionaryRef iv_dict = rb_class_ivar_dict(klass);
if (iv_dict != NULL) {
CFDictionaryRemoveValue(iv_dict, (const void *)idAncestors);
}
if (add_methods) {
+ // Copy methods. If original class has the basic -initialize and if the
+ // module has a customized -initialize, we must copy the customized version
+ // to the original class too.
rb_vm_copy_methods((Class)module, (Class)klass);
+
+ if (orig_klass != 0 && orig_klass != klass) {
+ Method m = class_getInstanceMethod((Class)orig_klass, selInitialize);
+ Method m2 = class_getInstanceMethod((Class)klass, selInitialize);
+ if (m != NULL && m2 != NULL
+ && method_getImplementation(m) == (IMP)rb_objc_init
+ && method_getImplementation(m2) != (IMP)rb_objc_init) {
+ rb_vm_copy_method((Class)orig_klass, m2);
+ }
+ }
}
}
void
rb_include_module(VALUE klass, VALUE module)
{
- rb_include_module2(klass, module, 1, 1);
+ rb_include_module2(klass, 0, module, true, true);
}
View
3 eval.c
@@ -511,6 +511,7 @@ VALUE rb_make_singleton_class(VALUE super);
static VALUE
rb_mod_append_features(VALUE module, SEL sel, VALUE include)
{
+ VALUE orig = include;
switch (TYPE(include)) {
case T_CLASS:
case T_MODULE:
@@ -524,7 +525,7 @@ rb_mod_append_features(VALUE module, SEL sel, VALUE include)
RCLASS_SET_SUPER(include, sinclude);
include = sinclude;
}
- rb_include_module(include, module);
+ rb_include_module2(include, orig, module, true, true);
VALUE m = module;
do {
View
@@ -920,6 +920,8 @@ VALUE rb_define_class_under(VALUE, const char*, VALUE);
VALUE rb_define_module_under(VALUE, const char*);
void rb_include_module(VALUE,VALUE);
+void rb_include_module2(VALUE klass, VALUE orig_klass, VALUE module, bool check,
+ bool add_methods);
void rb_extend_object(VALUE,VALUE);
void rb_define_variable(const char*,VALUE*);
View
@@ -2895,12 +2895,10 @@ Init_Object(void)
rb_objc_define_method(*(VALUE *)rb_cClass, "alloc", rb_class_s_alloc, 0);
rb_objc_define_method(rb_cClass, "new", rb_class_new_instance_imp, -1);
- void rb_include_module2(VALUE klass, VALUE module, int check, int add_methods);
-
// At this point, methods defined on Class or Module will be automatically
// added to NSObject's metaclass.
- rb_include_module2(*(VALUE *)rb_cNSObject, rb_cClass, 0, 0);
- rb_include_module2(*(VALUE *)rb_cNSObject, rb_cModule, 0, 0);
+ rb_include_module2(*(VALUE *)rb_cNSObject, 0, rb_cClass, false, false);
+ rb_include_module2(*(VALUE *)rb_cNSObject, 0, rb_cModule, false, false);
rb_objc_define_direct_method(*(VALUE *)rb_cNSObject, "new:", rb_class_new_instance_imp, -1);
View
77 vm.cpp
@@ -804,6 +804,15 @@ RoxorCore::method_added(Class klass, SEL sel)
}
+void
+RoxorCore::invalidate_method_cache(SEL sel)
+{
+ std::map<SEL, struct mcache *>::iterator iter = mcache.find(sel);
+ if (iter != mcache.end()) {
+ iter->second->flag = 0;
+ }
+}
+
rb_vm_method_node_t *
RoxorCore::add_method(Class klass, SEL sel, IMP imp, IMP ruby_imp,
const rb_vm_arity_t &arity, int flags, const char *types)
@@ -866,10 +875,7 @@ RoxorCore::add_method(Class klass, SEL sel, IMP imp, IMP ruby_imp,
invalidate_respond_to_cache();
// Invalidate dispatch cache.
- std::map<SEL, struct mcache *>::iterator iter3 = mcache.find(sel);
- if (iter3 != mcache.end()) {
- iter3->second->flag = 0;
- }
+ invalidate_method_cache(sel);
// Invalidate inline operations.
if (running) {
@@ -2055,6 +2061,44 @@ rb_vm_copy_methods(Class from_class, Class to_class)
GET_CORE()->copy_methods(from_class, to_class);
}
+extern "C"
+bool
+rb_vm_copy_method(Class klass, Method m)
+{
+ return GET_CORE()->copy_method(klass, m);
+}
+
+bool
+RoxorCore::copy_method(Class klass, Method m)
+{
+ rb_vm_method_node_t *node = method_node_get(m);
+ if (node == NULL) {
+ // Only copy pure-Ruby methods.
+ return false;
+ }
+ SEL sel = method_getName(m);
+
+#if ROXOR_VM_DEBUG
+ printf("copy %c[%s %s] from method %p imp %p\n",
+ class_isMetaClass(klass) ? '+' : '-',
+ class_getName(klass),
+ sel_getName(sel),
+ m,
+ method_getImplementation(m));
+#endif
+
+ class_replaceMethod(klass, sel, method_getImplementation(m),
+ method_getTypeEncoding(m));
+
+ Method m2 = class_getInstanceMethod(klass, sel);
+ assert(m2 != NULL);
+ assert(method_getImplementation(m2) == method_getImplementation(m));
+ rb_vm_method_node_t *node2 = method_node_get(m2, true);
+ memcpy(node2, node, sizeof(rb_vm_method_node_t));
+
+ return true;
+}
+
void
RoxorCore::copy_methods(Class from_class, Class to_class)
{
@@ -2066,32 +2110,11 @@ RoxorCore::copy_methods(Class from_class, Class to_class)
if (methods != NULL) {
for (i = 0; i < methods_count; i++) {
Method m = methods[i];
- rb_vm_method_node_t *node = method_node_get(m);
- if (node == NULL) {
- // Only copy pure-Ruby methods.
+ if (!copy_method(to_class, m)) {
continue;
}
- SEL sel = method_getName(m);
-
-#if ROXOR_VM_DEBUG
- printf("copy %c[%s %s] to %s\n",
- class_isMetaClass(from_class) ? '+' : '-',
- class_getName(from_class),
- sel_getName(sel),
- class_getName(to_class));
-#endif
-
- class_replaceMethod(to_class,
- sel,
- method_getImplementation(m),
- method_getTypeEncoding(m));
-
- Method m2 = class_getInstanceMethod(to_class, sel);
- assert(m2 != NULL);
- assert(method_getImplementation(m2) == method_getImplementation(m));
- rb_vm_method_node_t *node2 = method_node_get(m2, true);
- memcpy(node2, node, sizeof(rb_vm_method_node_t));
+ SEL sel = method_getName(m);
std::map<Class, rb_vm_method_source_t *> *map =
method_sources_for_sel(sel, false);
if (map != NULL) {
View
3 vm.h
@@ -291,6 +291,7 @@ void rb_vm_define_attr(Class klass, const char *name, bool read, bool write);
void rb_vm_undef_method(Class klass, ID name, bool must_exist);
void rb_vm_remove_method(Class klass, ID name);
void rb_vm_alias(VALUE klass, ID name, ID def);
+bool rb_vm_copy_method(Class klass, Method method);
void rb_vm_copy_methods(Class from_class, Class to_class);
VALUE rb_vm_call(VALUE self, SEL sel, int argc, const VALUE *args, bool super);
VALUE rb_vm_call_with_cache(void *cache, VALUE self, SEL sel, int argc,
@@ -729,6 +730,7 @@ class RoxorCore {
char *name, size_t name_len);
struct mcache *method_cache_get(SEL sel, bool super);
+ void invalidate_method_cache(SEL sel);
rb_vm_method_node_t *method_node_get(IMP imp, bool create=false);
rb_vm_method_node_t *method_node_get(Method m, bool create=false);
@@ -748,6 +750,7 @@ class RoxorCore {
void remove_method(Class klass, SEL sel);
bool resolve_methods(std::map<Class, rb_vm_method_source_t *> *map,
Class klass, SEL sel);
+ bool copy_method(Class klass, Method m);
void copy_methods(Class from_class, Class to_class);
void get_methods(VALUE ary, Class klass, bool include_objc_methods,
int (*filter) (VALUE, ID, VALUE));

0 comments on commit 86da889

Please sign in to comment.