[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