[macruby-changes] [3007] MacRuby/trunk

source_changes at macosforge.org source_changes at macosforge.org
Fri Nov 13 17:42:22 PST 2009


Revision: 3007
          http://trac.macosforge.org/projects/ruby/changeset/3007
Author:   lsansonetti at apple.com
Date:     2009-11-13 17:42:22 -0800 (Fri, 13 Nov 2009)
Log Message:
-----------
when including a module that defines a special method (currently -initialize), make sure to copy it to the original class too if the later doesn't define it

Modified Paths:
--------------
    MacRuby/trunk/class.c
    MacRuby/trunk/eval.c
    MacRuby/trunk/include/ruby/ruby.h
    MacRuby/trunk/object.c
    MacRuby/trunk/vm.cpp
    MacRuby/trunk/vm.h

Modified: MacRuby/trunk/class.c
===================================================================
--- MacRuby/trunk/class.c	2009-11-14 00:47:15 UTC (rev 3006)
+++ MacRuby/trunk/class.c	2009-11-14 01:42:22 UTC (rev 3007)
@@ -575,7 +575,8 @@
 }
 
 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 @@
 	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,9 +599,11 @@
     }
     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();
@@ -607,20 +611,34 @@
     }
     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);
 }
 
 

Modified: MacRuby/trunk/eval.c
===================================================================
--- MacRuby/trunk/eval.c	2009-11-14 00:47:15 UTC (rev 3006)
+++ MacRuby/trunk/eval.c	2009-11-14 01:42:22 UTC (rev 3007)
@@ -511,6 +511,7 @@
 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 @@
 	RCLASS_SET_SUPER(include, sinclude);
 	include = sinclude;
     }	
-    rb_include_module(include, module);
+    rb_include_module2(include, orig, module, true, true);
 
     VALUE m = module;
     do {

Modified: MacRuby/trunk/include/ruby/ruby.h
===================================================================
--- MacRuby/trunk/include/ruby/ruby.h	2009-11-14 00:47:15 UTC (rev 3006)
+++ MacRuby/trunk/include/ruby/ruby.h	2009-11-14 01:42:22 UTC (rev 3007)
@@ -920,6 +920,8 @@
 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*);

Modified: MacRuby/trunk/object.c
===================================================================
--- MacRuby/trunk/object.c	2009-11-14 00:47:15 UTC (rev 3006)
+++ MacRuby/trunk/object.c	2009-11-14 01:42:22 UTC (rev 3007)
@@ -2895,12 +2895,10 @@
     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);
 

Modified: MacRuby/trunk/vm.cpp
===================================================================
--- MacRuby/trunk/vm.cpp	2009-11-14 00:47:15 UTC (rev 3006)
+++ MacRuby/trunk/vm.cpp	2009-11-14 01:42:22 UTC (rev 3007)
@@ -804,6 +804,15 @@
 
 }
 
+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 @@
     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 @@
     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 @@
     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));
-
 	    std::map<Class, rb_vm_method_source_t *> *map =
 		method_sources_for_sel(sel, false);
 	    if (map != NULL) {

Modified: MacRuby/trunk/vm.h
===================================================================
--- MacRuby/trunk/vm.h	2009-11-14 00:47:15 UTC (rev 3006)
+++ MacRuby/trunk/vm.h	2009-11-14 01:42:22 UTC (rev 3007)
@@ -291,6 +291,7 @@
 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 @@
 		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 @@
 	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));
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20091113/95fb3ee1/attachment-0001.html>


More information about the macruby-changes mailing list