[macruby-changes] [2357] MacRuby/trunk

source_changes at macosforge.org source_changes at macosforge.org
Sat Aug 22 12:05:32 PDT 2009


Revision: 2357
          http://trac.macosforge.org/projects/ruby/changeset/2357
Author:   lsansonetti at apple.com
Date:     2009-08-22 12:05:28 -0700 (Sat, 22 Aug 2009)
Log Message:
-----------
fixing and adding several missing ruby method features

Modified Paths:
--------------
    MacRuby/trunk/array.c
    MacRuby/trunk/class.c
    MacRuby/trunk/compiler.cpp
    MacRuby/trunk/compiler.h
    MacRuby/trunk/id.c
    MacRuby/trunk/id.h
    MacRuby/trunk/include/ruby/ruby.h
    MacRuby/trunk/lib/yaml/rubytypes.rb
    MacRuby/trunk/object.c
    MacRuby/trunk/proc.c
    MacRuby/trunk/spec/frozen/language/def_spec.rb
    MacRuby/trunk/spec/frozen/library/date/conversions_spec.rb
    MacRuby/trunk/spec/frozen/tags/macruby/core/array/initialize_copy_tags.txt
    MacRuby/trunk/spec/frozen/tags/macruby/core/array/initialize_tags.txt
    MacRuby/trunk/spec/frozen/tags/macruby/core/basicobject/method_missing_tags.txt
    MacRuby/trunk/spec/frozen/tags/macruby/core/module/alias_method_tags.txt
    MacRuby/trunk/spec/frozen/tags/macruby/core/module/method_added_tags.txt
    MacRuby/trunk/spec/frozen/tags/macruby/core/module/remove_const_tags.txt
    MacRuby/trunk/spec/frozen/tags/macruby/core/string/initialize_tags.txt
    MacRuby/trunk/spec/frozen/tags/macruby/language/def_tags.txt
    MacRuby/trunk/spec/frozen/tags/macruby/language/method_tags.txt
    MacRuby/trunk/spec/frozen/tags/macruby/library/net/ftp/initialize_tags.txt
    MacRuby/trunk/vm.cpp
    MacRuby/trunk/vm.h
    MacRuby/trunk/vm_eval.c
    MacRuby/trunk/vm_method.c

Removed Paths:
-------------
    MacRuby/trunk/spec/frozen/tags/macruby/core/kernel/respond_to_tags.txt
    MacRuby/trunk/spec/frozen/tags/macruby/core/kernel/singleton_method_added_tags.txt
    MacRuby/trunk/spec/frozen/tags/macruby/core/kernel/singleton_method_removed_tags.txt
    MacRuby/trunk/spec/frozen/tags/macruby/core/kernel/singleton_method_undefined_tags.txt
    MacRuby/trunk/spec/frozen/tags/macruby/core/module/extended_tags.txt
    MacRuby/trunk/spec/frozen/tags/macruby/core/module/included_tags.txt
    MacRuby/trunk/spec/frozen/tags/macruby/core/module/private_class_method_tags.txt
    MacRuby/trunk/spec/frozen/tags/macruby/core/module/private_instance_methods_tags.txt
    MacRuby/trunk/spec/frozen/tags/macruby/core/module/private_method_defined_tags.txt
    MacRuby/trunk/spec/frozen/tags/macruby/core/module/private_tags.txt
    MacRuby/trunk/spec/frozen/tags/macruby/core/range/initialize_tags.txt
    MacRuby/trunk/spec/frozen/tags/macruby/core/struct/initialize_tags.txt
    MacRuby/trunk/spec/frozen/tags/macruby/language/private_tags.txt
    MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/initialize_tags.txt
    MacRuby/trunk/spec/frozen/tags/macruby/library/net/http/http/initialize_tags.txt
    MacRuby/trunk/spec/frozen/tags/macruby/library/set/initialize_copy_tags.txt
    MacRuby/trunk/spec/frozen/tags/macruby/library/set/initialize_tags.txt
    MacRuby/trunk/spec/frozen/tags/macruby/library/set/sortedset/initialize_copy_tags.txt
    MacRuby/trunk/spec/frozen/tags/macruby/library/set/sortedset/initialize_tags.txt
    MacRuby/trunk/spec/frozen/tags/macruby/library/stringio/initialize_copy_tags.txt
    MacRuby/trunk/spec/frozen/tags/macruby/library/stringscanner/initialize_copy_tags.txt
    MacRuby/trunk/spec/frozen/tags/macruby/library/stringscanner/initialize_tags.txt

Modified: MacRuby/trunk/array.c
===================================================================
--- MacRuby/trunk/array.c	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/array.c	2009-08-22 19:05:28 UTC (rev 2357)
@@ -213,6 +213,9 @@
     if (SPECIAL_CONST_P(x) && SPECIAL_CONST_P(y) && TYPE(x) == TYPE(y)) {
 	return Qfalse;
     }
+    if (SYMBOL_P(x)) {
+	return x == y ? Qtrue : Qfalse;
+    }
     return rb_equal(x, y);
 }
 

Modified: MacRuby/trunk/class.c
===================================================================
--- MacRuby/trunk/class.c	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/class.c	2009-08-22 19:05:28 UTC (rev 2357)
@@ -121,8 +121,8 @@
     rb_objc_define_method(*(VALUE *)klass, "__new__",
 	    rb_class_new_instance_imp, -1);
     rb_objc_define_method(klass, "dup", rb_obj_dup, 0);
-    rb_objc_define_method(klass, "initialize", rb_objc_init, 0);
-    rb_objc_define_method(klass, "initialize_copy", rb_obj_init_copy, 1);
+    rb_objc_define_private_method(klass, "initialize", rb_objc_init, 0);
+    rb_objc_define_private_method(klass, "initialize_copy", rb_obj_init_copy, 1);
 
     rb_objc_install_method(*(Class *)klass, selAllocWithZone,
 	    (IMP)rb_obj_imp_allocWithZone);
@@ -400,20 +400,20 @@
 VALUE
 rb_define_class_id(ID id, VALUE super)
 {
-    VALUE klass;
-
-    if (!super) super = rb_cObject;
-    klass = rb_objc_create_class(rb_id2name(id), super);
-
-    return klass;
+    if (super == 0) {
+	super = rb_cObject;
+    }
+    return rb_objc_create_class(rb_id2name(id), super);
 }
 
 VALUE
 rb_class_inherited(VALUE super, VALUE klass)
 {
     if (rb_vm_running()) {
-	if (!super) super = rb_cObject;
-	return rb_funcall(super, rb_intern("inherited"), 1, klass);
+	if (super == 0) {
+	    super = rb_cObject;
+	}
+	return rb_vm_call(super, selInherited, 1, &klass, false);
     }
     return Qnil;
 }
@@ -717,21 +717,22 @@
 static int
 ins_methods_push(VALUE name, long type, VALUE ary, long visi)
 {
-    if (type == -1) return ST_CONTINUE;
-
-    switch (visi) {
-      case NOEX_PRIVATE:
-      case NOEX_PROTECTED:
-      case NOEX_PUBLIC:
-	visi = (type == visi);
-	break;
-      default:
-	visi = (type != NOEX_PRIVATE);
-	break;
+    if (type != -1) {
+	bool visible;
+	switch (visi) {
+	    case NOEX_PRIVATE:
+	    case NOEX_PROTECTED:
+	    case NOEX_PUBLIC:
+		visible = (type == visi);
+		break;
+	    default:
+		visible = (type != NOEX_PRIVATE);
+		break;
+	}
+	if (visible) {
+	    rb_ary_push(ary, name);
+	}
     }
-    if (visi) {
-	rb_ary_push(ary, name);
-    }
     return ST_CONTINUE;
 }
 
@@ -1010,7 +1011,7 @@
 void
 rb_undef_method(VALUE klass, const char *name)
 {
-    rb_vm_undef_method((Class)klass, name, false);
+    rb_vm_undef_method((Class)klass, rb_intern(name), false);
 }
 
 #define SPECIAL_SINGLETON(x,c) do {\

Modified: MacRuby/trunk/compiler.cpp
===================================================================
--- MacRuby/trunk/compiler.cpp	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/compiler.cpp	2009-08-22 19:05:28 UTC (rev 2357)
@@ -121,6 +121,8 @@
     longjmpFunc = NULL;
     setjmpFunc = NULL;
     popBrokenValue = NULL;
+    setScopeFunc = NULL;
+    setCurrentClassFunc = NULL;
 
 #if __LP64__
     RubyObjTy = IntTy = Type::Int64Ty;
@@ -133,6 +135,9 @@
     twoVal = ConstantInt::get(IntTy, 2);
     threeVal = ConstantInt::get(IntTy, 3);
 
+    defaultScope = ConstantInt::get(Type::Int32Ty, SCOPE_DEFAULT);
+    publicScope = ConstantInt::get(Type::Int32Ty, SCOPE_PUBLIC);
+
     RubyObjPtrTy = PointerType::getUnqual(RubyObjTy);
     RubyObjPtrPtrTy = PointerType::getUnqual(RubyObjPtrTy);
     nilVal = ConstantInt::get(RubyObjTy, Qnil);
@@ -622,22 +627,23 @@
 }
 
 void
-RoxorCompiler::compile_prepare_method(Value *classVal, Value *sel,
-	Function *new_function, rb_vm_arity_t &arity, NODE *body)
+RoxorCompiler::compile_prepare_method(Value *classVal, bool singleton,
+	Value *sel, Function *new_function, rb_vm_arity_t &arity, NODE *body)
 {
     if (prepareMethodFunc == NULL) {
-	// void rb_vm_prepare_method(Class klass, SEL sel,
-	//	Function *func, rb_vm_arity_t arity, int flags)
+	// void rb_vm_prepare_method(Class klass, unsigned char singleton,
+	//	SEL sel, Function *func, rb_vm_arity_t arity, int flags)
 	prepareMethodFunc = 
 	    cast<Function>(module->getOrInsertFunction(
 			"rb_vm_prepare_method",
-			Type::VoidTy, RubyObjTy, PtrTy, PtrTy,
+			Type::VoidTy, RubyObjTy, Type::Int8Ty, PtrTy, PtrTy,
 			Type::Int64Ty, Type::Int32Ty, NULL));
     }
 
     std::vector<Value *> params;
 
     params.push_back(classVal);
+    params.push_back(ConstantInt::get(Type::Int8Ty, singleton));
     params.push_back(sel);
 
     params.push_back(compile_const_pointer(new_function));
@@ -650,22 +656,23 @@
 }
 
 void
-RoxorAOTCompiler::compile_prepare_method(Value *classVal, Value *sel,
-	Function *new_function, rb_vm_arity_t &arity, NODE *body)
+RoxorAOTCompiler::compile_prepare_method(Value *classVal, bool singleton,
+	Value *sel, Function *new_function, rb_vm_arity_t &arity, NODE *body)
 {
     if (prepareMethodFunc == NULL) {
-	// void rb_vm_prepare_method2(Class klass, SEL sel,
-	//	IMP ruby_imp, rb_vm_arity_t arity, int flags)
+	// void rb_vm_prepare_method2(Class klass, unsigned char singleton,
+	//	SEL sel, IMP ruby_imp, rb_vm_arity_t arity, int flags)
 	prepareMethodFunc = 
 	    cast<Function>(module->getOrInsertFunction(
 			"rb_vm_prepare_method2",
-			Type::VoidTy, RubyObjTy, PtrTy, PtrTy,
+			Type::VoidTy, RubyObjTy, Type::Int8Ty, PtrTy, PtrTy,
 			Type::Int64Ty, Type::Int32Ty, NULL));
     }
 
     std::vector<Value *> params;
 
     params.push_back(classVal);
+    params.push_back(ConstantInt::get(Type::Int8Ty, singleton));
     params.push_back(sel);
 
     // Make sure the function is compiled before use, this way LLVM won't use
@@ -674,6 +681,7 @@
     params.push_back(new BitCastInst(new_function, PtrTy, "", bb));
 
     params.push_back(compile_arity(arity));
+
     params.push_back(ConstantInt::get(Type::Int32Ty, rb_vm_node_flags(body)));
 
     CallInst::Create(prepareMethodFunc, params.begin(),
@@ -733,7 +741,11 @@
     params.push_back(recv);
     params.push_back(compile_sel(sel));
     params.push_back(compile_const_pointer(NULL));
-    params.push_back(ConstantInt::get(Type::Int8Ty, 0));
+    unsigned char opt = 0;
+    if (recv == current_self) {
+	opt = DISPATCH_SELF_ATTRASGN;
+    }
+    params.push_back(ConstantInt::get(Type::Int8Ty, opt));
     params.push_back(ConstantInt::get(Type::Int32Ty, argc));
     for (std::vector<Value *>::iterator i = args.begin();
 	 i != args.end();
@@ -2469,7 +2481,7 @@
 	new_params.push_back(params[1]);
 	new_params.push_back(compile_sel(new_sel));
 	new_params.push_back(params[3]);
-	new_params.push_back(params[4]);
+	new_params.push_back(ConstantInt::get(Type::Int8Ty, DISPATCH_FCALL));
 	new_params.push_back(ConstantInt::get(Type::Int32Ty, argc - 1));
 	for (int i = 0; i < argc - 1; i++) {
 	    new_params.push_back(params[7 + i]);
@@ -2727,7 +2739,41 @@
     return new LoadInst(gvar, "", bb);
 }
 
+Value *
+RoxorCompiler::compile_set_current_class(Value *klass)
+{
+    if (setCurrentClassFunc == NULL) {
+	// Class rb_vm_set_current_class(Class klass)
+	setCurrentClassFunc = cast<Function>(
+		module->getOrInsertFunction("rb_vm_set_current_class",
+		    RubyObjTy, RubyObjTy, NULL));
+    }
+
+    std::vector<Value *> params;
+    params.push_back(klass);
+
+    return CallInst::Create(setCurrentClassFunc, params.begin(), params.end(),
+	    "", bb);
+}
+
 void
+RoxorCompiler::compile_set_current_scope(Value *klass, Value *scope)
+{
+    if (setScopeFunc == NULL) {
+	// void rb_vm_set_current_scope(VALUE mod, int scope)
+	setScopeFunc = cast<Function>(
+		module->getOrInsertFunction("rb_vm_set_current_scope",
+		    Type::VoidTy, RubyObjTy, Type::Int32Ty, NULL));
+    }
+
+    std::vector<Value *> params;
+    params.push_back(klass);
+    params.push_back(scope);
+
+    CallInst::Create(setScopeFunc, params.begin(), params.end(), "", bb);
+}
+
+void
 RoxorCompiler::compile_ivar_slots(Value *klass,
 	BasicBlock::InstListType &list, 
 	BasicBlock::InstListType::iterator list_iter)
@@ -3692,8 +3738,16 @@
 
 			current_module = nd_type(node) == NODE_MODULE;
 
+			compile_set_current_scope(classVal, publicScope);
+			Value *old_current_class = 
+			    compile_set_current_class(
+				    ConstantInt::get(RubyObjTy, 0));
+
 			Value *val = compile_node(body->nd_body);
 
+			compile_set_current_class(old_current_class);
+			compile_set_current_scope(classVal, defaultScope);
+
 			BasicBlock::InstListType &list = bb->getInstList();
 			compile_ivar_slots(classVal, list, list.end());
 
@@ -3844,7 +3898,8 @@
 		    ? DISPATCH_SUPER
 		    : (nd_type(node) == NODE_VCALL)
 			? DISPATCH_VCALL
-			: 0;
+			: (nd_type(node) == NODE_FCALL)
+			    ? DISPATCH_FCALL : 0;	
 		params.push_back(ConstantInt::get(Type::Int8Ty, call_opt));
 
 		// Arguments.
@@ -4271,7 +4326,7 @@
 		rb_vm_arity_t arity = rb_vm_node_arity(body);
 		const SEL sel = mid_to_sel(mid, arity.real);
 
-		compile_prepare_method(classVal, compile_sel(sel),
+		compile_prepare_method(classVal, singleton_method, compile_sel(sel),
 			new_function, arity, body);
 
 		return nilVal;

Modified: MacRuby/trunk/compiler.h
===================================================================
--- MacRuby/trunk/compiler.h	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/compiler.h	2009-08-22 19:05:28 UTC (rev 2357)
@@ -12,9 +12,11 @@
 #if defined(__cplusplus)
 
 // For the dispatcher.
-#define DISPATCH_VCALL 		1
-#define DISPATCH_SUPER 		2
-#define SPLAT_ARG_FOLLOWS 	0xdeadbeef
+#define DISPATCH_VCALL		1  // no receiver, no argument
+#define DISPATCH_FCALL		2  // no receiver, one or more arguments
+#define DISPATCH_SUPER		3  // super call
+#define DISPATCH_SELF_ATTRASGN	4  // self attribute assignment
+#define SPLAT_ARG_FOLLOWS	0xdeadbeef
 
 // For defined?
 #define DEFINED_IVAR 	1
@@ -172,6 +174,8 @@
 	Function *longjmpFunc;
 	Function *setjmpFunc;
 	Function *popBrokenValue;
+	Function *setScopeFunc;
+	Function *setCurrentClassFunc;
 
 	Constant *zeroVal;
 	Constant *oneVal;
@@ -183,6 +187,8 @@
 	Constant *undefVal;
 	Constant *splatArgFollowsVal;
 	Constant *cObject;
+	Constant *defaultScope;
+	Constant *publicScope;
 	const Type *RubyObjTy; 
 	const Type *RubyObjPtrTy;
 	const Type *RubyObjPtrPtrTy;
@@ -222,8 +228,9 @@
 		BasicBlock *thenBB);
 	void compile_single_when_argument(NODE *arg, Value *comparedToVal,
 		BasicBlock *thenBB);
-	virtual void compile_prepare_method(Value *classVal, Value *sel,
-		Function *new_function, rb_vm_arity_t &arity, NODE *body);
+	virtual void compile_prepare_method(Value *classVal, bool singleton,
+		Value *sel, Function *new_function, rb_vm_arity_t &arity,
+		NODE *body);
 	Value *compile_dispatch_call(std::vector<Value *> &params);
 	Value *compile_when_splat(Value *comparedToVal, Value *splatVal);
 	Value *compile_fast_op_call(SEL sel, Value *selfVal, Value *comparedToVal);
@@ -273,6 +280,9 @@
 	virtual Value *compile_immutable_literal(VALUE val);
 	virtual Value *compile_global_entry(NODE *node);
 
+	void compile_set_current_scope(Value *klass, Value *scope);
+	Value *compile_set_current_class(Value *klass);
+
 	Value *compile_landing_pad_header(void);
 	Value *compile_landing_pad_header(const std::type_info &eh_type);
 	void compile_landing_pad_footer(bool pop_exception=true);
@@ -333,8 +343,9 @@
 	Value *compile_mcache(SEL sel, bool super);
 	Value *compile_ccache(ID id);
 	Instruction *compile_sel(SEL sel, bool add_to_bb=true);
-	void compile_prepare_method(Value *classVal, Value *sel,
-		Function *new_function, rb_vm_arity_t &arity, NODE *body);
+	void compile_prepare_method(Value *classVal, bool singleton,
+		Value *sel, Function *new_function, rb_vm_arity_t &arity,
+		NODE *body);
 	Value *compile_prepare_block_args(Function *func, int *flags);
 	Value *compile_nsobject(void);
 	Value *compile_id(ID id);

Modified: MacRuby/trunk/id.c
===================================================================
--- MacRuby/trunk/id.c	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/id.c	2009-08-22 19:05:28 UTC (rev 2357)
@@ -65,6 +65,7 @@
     selInit = sel_registerName("init");
     selInitialize = sel_registerName("initialize");
     selInitialize2 = sel_registerName("initialize:");
+    selInitializeCopy = sel_registerName("initialize_copy:");
     selDescription = sel_registerName("description");
     selInspect = sel_registerName("inspect");
     selNew = sel_registerName("new");
@@ -95,6 +96,7 @@
     selSingletonMethodAdded = sel_registerName("singleton_method_added:");
     selIsEqual = sel_registerName("isEqual:");
     selWrite = sel_registerName("write:");
+    selInherited = sel_registerName("inherited:");
 
     cacheEach = rb_vm_get_call_cache(selEach);
 #endif

Modified: MacRuby/trunk/id.h
===================================================================
--- MacRuby/trunk/id.h	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/id.h	2009-08-22 19:05:28 UTC (rev 2357)
@@ -75,6 +75,7 @@
 extern SEL selInit;
 extern SEL selInitialize;
 extern SEL selInitialize2;
+extern SEL selInitializeCopy;
 extern SEL selDescription;
 extern SEL selInspect;
 extern SEL selNew;
@@ -104,6 +105,7 @@
 extern SEL selSingletonMethodAdded;
 extern SEL selIsEqual;
 extern SEL selWrite;
+extern SEL selInherited;
 extern ID idIncludedModules;
 extern ID idIncludedInClasses;
 extern ID idAncestors;

Modified: MacRuby/trunk/include/ruby/ruby.h
===================================================================
--- MacRuby/trunk/include/ruby/ruby.h	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/include/ruby/ruby.h	2009-08-22 19:05:28 UTC (rev 2357)
@@ -542,18 +542,21 @@
 # define RMODULE_M_TBL(m) RCLASS_M_TBL(m)
 # define RMODULE_SUPER(m) RCLASS_SUPER(m)
 #else
-# define RCLASS_IS_OBJECT_SUBCLASS    0x1000   /* class is a true RBObject subclass */
-# define RCLASS_IS_RUBY_CLASS         0x2000   /* class was created from Ruby */
-# define RCLASS_IS_MODULE             0x4000   /* class represents a Ruby Module */
-# define RCLASS_IS_SINGLETON	      0x8000   /* class represents a singleton */
-# define RCLASS_IS_FROZEN	      0x10000  /* class is frozen */
-# define RCLASS_IS_TAINTED	      0x20000  /* class is tainted */
-# define RCLASS_IS_STRING_SUBCLASS    0x40000  /* class is a subclass of NSCFString */
-# define RCLASS_IS_ARRAY_SUBCLASS     0x80000  /* class is a subclass of NSCFArray */
-# define RCLASS_IS_HASH_SUBCLASS      0x100000 /* class is a subclass of NSCFDictionary */
-# define RCLASS_IS_INCLUDED           0x200000 /* module is included */
-# define RCLASS_IS_SET_SUBCLASS       0x400000 /* class is a subclass of NSCFSet */
-# define RCLASS_HAS_ROBJECT_ALLOC     0x800000 /* class uses the default RObject alloc */
+# define RCLASS_IS_OBJECT_SUBCLASS    (1<<12)  /* class is a true RBObject subclass */
+# define RCLASS_IS_RUBY_CLASS         (1<<13)  /* class was created from Ruby */
+# define RCLASS_IS_MODULE             (1<<14)  /* class represents a Ruby Module */
+# define RCLASS_IS_SINGLETON	      (1<<15)  /* class represents a singleton */
+# define RCLASS_IS_FROZEN	      (1<<16)  /* class is frozen */
+# define RCLASS_IS_TAINTED	      (1<<17)  /* class is tainted */
+# define RCLASS_IS_STRING_SUBCLASS    (1<<18)  /* class is a subclass of NSCFString */
+# define RCLASS_IS_ARRAY_SUBCLASS     (1<<19)  /* class is a subclass of NSCFArray */
+# define RCLASS_IS_HASH_SUBCLASS      (1<<20)  /* class is a subclass of NSCFDictionary */
+# define RCLASS_IS_INCLUDED           (1<<21)  /* module is included */
+# define RCLASS_IS_SET_SUBCLASS       (1<<22)  /* class is a subclass of NSCFSet */
+# define RCLASS_HAS_ROBJECT_ALLOC     (1<<23)  /* class uses the default RObject alloc */
+# define RCLASS_SCOPE_PRIVATE	      (1<<24)  /* class opened for private methods */
+# define RCLASS_SCOPE_PROTECTED	      (1<<25)  /* class opened for protected methods */
+# define RCLASS_SCOPE_MOD_FUNC	      (1<<26)  /* class opened for module_function methods */
 # if defined(__LP64__)
 #  define _PTR_TYPE uint64_t
 #  define RCLASS_VERSION(m) (class_getVersion((Class)m))

Modified: MacRuby/trunk/lib/yaml/rubytypes.rb
===================================================================
--- MacRuby/trunk/lib/yaml/rubytypes.rb	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/lib/yaml/rubytypes.rb	2009-08-22 19:05:28 UTC (rev 2357)
@@ -12,8 +12,10 @@
   def yaml_as(tag)
     attr_writer :taguri
     klass = (self.is_a? Class) ? self : (class << self; self; end)
-    klass.define_method(:taguri) do
-      @taguri || tag
+    klass.instance_eval do
+      define_method(:taguri) do
+        @taguri || tag
+      end
     end
     YAML::LibYAML::DEFAULT_RESOLVER.add_type(tag, self)
   end
@@ -556,4 +558,4 @@
 end
 
 
-=end
\ No newline at end of file
+=end

Modified: MacRuby/trunk/object.c
===================================================================
--- MacRuby/trunk/object.c	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/object.c	2009-08-22 19:05:28 UTC (rev 2357)
@@ -252,7 +252,7 @@
         break;
     }
 call_init_copy:
-    rb_funcall(dest, id_init_copy, 1, obj);
+    rb_vm_call(dest, selInitializeCopy, 1, &obj, false);
 }
 
 /*
@@ -386,18 +386,17 @@
 rb_any_to_string(VALUE obj, SEL sel)
 {
     const char *cname = rb_obj_classname(obj);
-    VALUE str;
-
-    str = rb_sprintf("#<%s:%p>", cname, (void*)obj);
-    if (OBJ_TAINTED(obj)) OBJ_TAINT(str);
-
+    VALUE str = rb_sprintf("#<%s:%p>", cname, (void*)obj);
+    if (OBJ_TAINTED(obj)) {
+	OBJ_TAINT(str);
+    }
     return str;
 }
 
 VALUE
 rb_any_to_s(VALUE obj)
 {
-	return rb_any_to_string(obj, 0);
+    return rb_any_to_string(obj, 0);
 }
 
 VALUE
@@ -1789,8 +1788,9 @@
 	RCLASS_SET_VERSION(klass, v);
     }
     rb_objc_install_primitives((Class)klass, (Class)super);
-    if (super == rb_cObject)
+    if (super == rb_cObject) {
 	rb_define_object_special_methods(klass);
+    }
 
     rb_class_inherited(super, klass);
     rb_mod_initialize(klass, 0);

Modified: MacRuby/trunk/proc.c
===================================================================
--- MacRuby/trunk/proc.c	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/proc.c	2009-08-22 19:05:28 UTC (rev 2357)
@@ -677,14 +677,17 @@
 {
     rb_vm_method_t *m1, *m2;
 
-    if (CLASS_OF(method) != CLASS_OF(other))
+    if (CLASS_OF(method) != CLASS_OF(other)) {
 	return Qfalse;
+    }
 
     Data_Get_Struct(method, rb_vm_method_t, m1);
     Data_Get_Struct(other, rb_vm_method_t, m2);
 
-    if (m1->oclass != m2->oclass || m1->rclass != m2->rclass ||
-	m1->recv != m2->recv || m1->node != m2->node) {
+    if (m1->oclass != m2->oclass
+	|| m1->rclass != m2->rclass
+	|| m1->recv != m2->recv
+	|| m1->node->objc_imp != m2->node->objc_imp) {
 	return Qfalse;
     }
 

Modified: MacRuby/trunk/spec/frozen/language/def_spec.rb
===================================================================
--- MacRuby/trunk/spec/frozen/language/def_spec.rb	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/spec/frozen/language/def_spec.rb	2009-08-22 19:05:28 UTC (rev 2357)
@@ -491,4 +491,4 @@
   end
 end
 
-language_version __FILE__, "def"
\ No newline at end of file
+language_version __FILE__, "def"

Modified: MacRuby/trunk/spec/frozen/library/date/conversions_spec.rb
===================================================================
--- MacRuby/trunk/spec/frozen/library/date/conversions_spec.rb	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/spec/frozen/library/date/conversions_spec.rb	2009-08-22 19:05:28 UTC (rev 2357)
@@ -42,6 +42,11 @@
   end
 end
 
+# The following methods are private in 1.9's date.rb.
+# XXX should we write specs that test if they are private?
+# should we rewrite the specs using #send?
+ruby_version_is "" ... "1.9" do
+
 describe "Date#ordinal_to_jd" do
   it "should convert an ordinal date (year-day) to a Julian day number" do
     Date.ordinal_to_jd(2007, 55).should == 2454156
@@ -150,4 +155,6 @@
   it "should be able to convert a Julian day number into a week day number" do
     Date.jd_to_wday(2454482).should == 3
   end
-end
\ No newline at end of file
+end
+
+end # "" ... "1.9"

Modified: MacRuby/trunk/spec/frozen/tags/macruby/core/array/initialize_copy_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/array/initialize_copy_tags.txt	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/array/initialize_copy_tags.txt	2009-08-22 19:05:28 UTC (rev 2357)
@@ -1,2 +1 @@
-fails:Array#initialize_copy is private
 fails:Array#initialize_copy tries to convert the passed argument to an Array using #to_ary

Modified: MacRuby/trunk/spec/frozen/tags/macruby/core/array/initialize_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/array/initialize_tags.txt	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/array/initialize_tags.txt	2009-08-22 19:05:28 UTC (rev 2357)
@@ -1,4 +1,3 @@
-fails:Array#initialize is private
 fails:Array#initialize with (array) calls #to_ary to convert the value to an array
 fails:Array#initialize with (size, object=nil) calls #to_int to convert the size argument to an Integer when object is given
 fails:Array#initialize with (size, object=nil) calls #to_int to convert the size argument to an Integer when object is not given

Modified: MacRuby/trunk/spec/frozen/tags/macruby/core/basicobject/method_missing_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/basicobject/method_missing_tags.txt	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/basicobject/method_missing_tags.txt	2009-08-22 19:05:28 UTC (rev 2357)
@@ -1,3 +1,2 @@
-fails:BasicObject#method_missing is a private method
 fails:BasicObject#method_missing is called when a private method is called
 fails:BasicObject#method_missing is called when a protected method is called

Deleted: MacRuby/trunk/spec/frozen/tags/macruby/core/kernel/respond_to_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/kernel/respond_to_tags.txt	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/kernel/respond_to_tags.txt	2009-08-22 19:05:28 UTC (rev 2357)
@@ -1,2 +0,0 @@
-fails:Kernel#respond_to? returns false if the given method was undefined
-fails:Kernel#respond_to? returns true if obj responds to the given private method, include_private = true

Deleted: MacRuby/trunk/spec/frozen/tags/macruby/core/kernel/singleton_method_added_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/kernel/singleton_method_added_tags.txt	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/kernel/singleton_method_added_tags.txt	2009-08-22 19:05:28 UTC (rev 2357)
@@ -1 +0,0 @@
-fails:Kernel#singleton_method_added is a private method

Deleted: MacRuby/trunk/spec/frozen/tags/macruby/core/kernel/singleton_method_removed_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/kernel/singleton_method_removed_tags.txt	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/kernel/singleton_method_removed_tags.txt	2009-08-22 19:05:28 UTC (rev 2357)
@@ -1 +0,0 @@
-fails:Kernel#singleton_method_removed is a private method

Deleted: MacRuby/trunk/spec/frozen/tags/macruby/core/kernel/singleton_method_undefined_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/kernel/singleton_method_undefined_tags.txt	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/kernel/singleton_method_undefined_tags.txt	2009-08-22 19:05:28 UTC (rev 2357)
@@ -1 +0,0 @@
-fails:Kernel#singleton_method_undefined is a private method

Modified: MacRuby/trunk/spec/frozen/tags/macruby/core/module/alias_method_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/module/alias_method_tags.txt	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/module/alias_method_tags.txt	2009-08-22 19:05:28 UTC (rev 2357)
@@ -1,3 +1,2 @@
 fails:Module#alias_method retains method visibility
-fails:Module#alias_method is a private method
 fails:Module#alias_method converts a non string/symbol/fixnum name to string using to_str

Deleted: MacRuby/trunk/spec/frozen/tags/macruby/core/module/extended_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/module/extended_tags.txt	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/module/extended_tags.txt	2009-08-22 19:05:28 UTC (rev 2357)
@@ -1 +0,0 @@
-fails:Module#extended is private in its default implementation

Deleted: MacRuby/trunk/spec/frozen/tags/macruby/core/module/included_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/module/included_tags.txt	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/module/included_tags.txt	2009-08-22 19:05:28 UTC (rev 2357)
@@ -1 +0,0 @@
-fails:Module#included is private in its default implementation

Modified: MacRuby/trunk/spec/frozen/tags/macruby/core/module/method_added_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/module/method_added_tags.txt	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/module/method_added_tags.txt	2009-08-22 19:05:28 UTC (rev 2357)
@@ -1,2 +1 @@
-fails:Module#method_added is a private instance method
 fails:Module#method_added is called when a new method is defined in self

Deleted: MacRuby/trunk/spec/frozen/tags/macruby/core/module/private_class_method_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/module/private_class_method_tags.txt	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/module/private_class_method_tags.txt	2009-08-22 19:05:28 UTC (rev 2357)
@@ -1,6 +0,0 @@
-fails:Module#private_class_method makes an existing class method private
-fails:Module#private_class_method makes an existing class method private up the inheritance tree
-fails:Module#private_class_method accepts more than one method at a time
-fails:Module#private_class_method makes a class method private
-fails:Module#private_class_method raises a NameError when the given name is an instance method
-fails:Module#private_class_method raises a NameError when the given name is not a method
\ No newline at end of file

Deleted: MacRuby/trunk/spec/frozen/tags/macruby/core/module/private_instance_methods_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/module/private_instance_methods_tags.txt	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/module/private_instance_methods_tags.txt	2009-08-22 19:05:28 UTC (rev 2357)
@@ -1 +0,0 @@
-fails:Module#private_instance_methods returns a list of private methods in module and its ancestors

Deleted: MacRuby/trunk/spec/frozen/tags/macruby/core/module/private_method_defined_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/module/private_method_defined_tags.txt	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/module/private_method_defined_tags.txt	2009-08-22 19:05:28 UTC (rev 2357)
@@ -1,4 +0,0 @@
-fails:Module#private_method_defined? returns true if the named private method is defined by module or its ancestors
-fails:Module#private_method_defined? accepts symbols for the method name
-fails:Module#private_method_defined? raises an ArgumentError if passed a Fixnum
-fails:Module#private_method_defined? calls #to_str to coerce the passed object to a String

Deleted: MacRuby/trunk/spec/frozen/tags/macruby/core/module/private_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/module/private_tags.txt	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/module/private_tags.txt	2009-08-22 19:05:28 UTC (rev 2357)
@@ -1 +0,0 @@
-fails:Module#private should make the target method uncallable from other types

Modified: MacRuby/trunk/spec/frozen/tags/macruby/core/module/remove_const_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/module/remove_const_tags.txt	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/module/remove_const_tags.txt	2009-08-22 19:05:28 UTC (rev 2357)
@@ -1,5 +1,4 @@
 fails:Module#remove_const removes the constant specified by a String or Symbol from the receiver's constant table
 fails:Module#remove_const raises a NameError if the constant is not defined directly in the module
-fails:Module#remove_const is a private method
 fails:Module#remove_const calls #to_str to convert the given name to a String
 fails:Module#remove_const raises a TypeError if conversion to a String by calling #to_str fails

Deleted: MacRuby/trunk/spec/frozen/tags/macruby/core/range/initialize_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/range/initialize_tags.txt	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/range/initialize_tags.txt	2009-08-22 19:05:28 UTC (rev 2357)
@@ -1 +0,0 @@
-fails:Range#initialize is private

Modified: MacRuby/trunk/spec/frozen/tags/macruby/core/string/initialize_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/string/initialize_tags.txt	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/string/initialize_tags.txt	2009-08-22 19:05:28 UTC (rev 2357)
@@ -1,6 +1,5 @@
 critical:String#initialize raises TypeError on inconvertible object
 critical:String#initialize converts its argument to a string representation
-fails:String#initialize is a private method
 fails:String#initialize returns an instance of a subclass
 fails:String#initialize is called on subclasses
 fails:String#initialize raises a TypeError if self is frozen

Deleted: MacRuby/trunk/spec/frozen/tags/macruby/core/struct/initialize_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/core/struct/initialize_tags.txt	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/spec/frozen/tags/macruby/core/struct/initialize_tags.txt	2009-08-22 19:05:28 UTC (rev 2357)
@@ -1 +0,0 @@
-fails:Struct#initialize is private

Modified: MacRuby/trunk/spec/frozen/tags/macruby/language/def_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/language/def_tags.txt	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/spec/frozen/tags/macruby/language/def_tags.txt	2009-08-22 19:05:28 UTC (rev 2357)
@@ -1,4 +1,3 @@
-fails:Defining an 'initialize' method should make it private
 fails:An instance method with a default argument evaluates the default when required arguments precede it
 fails:An instance method with a default argument prefers to assign to a default argument before a splat argument
 fails:Redefining a singleton method does not inherit a previously set visibility 
@@ -7,4 +6,4 @@
 fails:A method definition inside an instance_eval creates a class method when the receiver is a class
 fails:A method definition in an eval creates an instance method
 fails:A method definition in an eval creates a class method
-fails:A method definition in an eval creates a singleton method
\ No newline at end of file
+fails:A method definition in an eval creates a singleton method

Modified: MacRuby/trunk/spec/frozen/tags/macruby/language/method_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/language/method_tags.txt	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/spec/frozen/tags/macruby/language/method_tags.txt	2009-08-22 19:05:28 UTC (rev 2357)
@@ -1,2 +1 @@
 critical:Calling a method allows any number of args beyond required to method with a splat
-fails:Calling a private getter method does not permit self as a receiver

Deleted: MacRuby/trunk/spec/frozen/tags/macruby/language/private_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/language/private_tags.txt	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/spec/frozen/tags/macruby/language/private_tags.txt	2009-08-22 19:05:28 UTC (rev 2357)
@@ -1,5 +0,0 @@
-fails:The private keyword marks following methods as being private
-fails:The private keyword is overridden when a new class is opened
-fails:The private keyword changes visibility of previously called method
-fails:The private keyword changes the visibility of the existing method in the subclass
-fails:The private keyword changes visiblity of previously called methods with same send/call site

Deleted: MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/initialize_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/initialize_tags.txt	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/matrix/initialize_tags.txt	2009-08-22 19:05:28 UTC (rev 2357)
@@ -1 +0,0 @@
-fails:Matrix#initialize is private

Modified: MacRuby/trunk/spec/frozen/tags/macruby/library/net/ftp/initialize_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/net/ftp/initialize_tags.txt	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/net/ftp/initialize_tags.txt	2009-08-22 19:05:28 UTC (rev 2357)
@@ -1,2 +1 @@
-fails:Net::FTP#initialize is private
 fails:Net::FTP#initialize sets self into binary mode

Deleted: MacRuby/trunk/spec/frozen/tags/macruby/library/net/http/http/initialize_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/net/http/http/initialize_tags.txt	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/net/http/http/initialize_tags.txt	2009-08-22 19:05:28 UTC (rev 2357)
@@ -1 +0,0 @@
-fails:Net::HTTP#initialize is private

Deleted: MacRuby/trunk/spec/frozen/tags/macruby/library/set/initialize_copy_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/set/initialize_copy_tags.txt	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/set/initialize_copy_tags.txt	2009-08-22 19:05:28 UTC (rev 2357)
@@ -1 +0,0 @@
-fails:Set#initialize_copy is private

Deleted: MacRuby/trunk/spec/frozen/tags/macruby/library/set/initialize_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/set/initialize_tags.txt	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/set/initialize_tags.txt	2009-08-22 19:05:28 UTC (rev 2357)
@@ -1 +0,0 @@
-fails:Set#initialize is private

Deleted: MacRuby/trunk/spec/frozen/tags/macruby/library/set/sortedset/initialize_copy_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/set/sortedset/initialize_copy_tags.txt	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/set/sortedset/initialize_copy_tags.txt	2009-08-22 19:05:28 UTC (rev 2357)
@@ -1 +0,0 @@
-fails:SortedSet#initialize_copy is private

Deleted: MacRuby/trunk/spec/frozen/tags/macruby/library/set/sortedset/initialize_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/set/sortedset/initialize_tags.txt	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/set/sortedset/initialize_tags.txt	2009-08-22 19:05:28 UTC (rev 2357)
@@ -1 +0,0 @@
-fails:SortedSet#initialize is private

Deleted: MacRuby/trunk/spec/frozen/tags/macruby/library/stringio/initialize_copy_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/stringio/initialize_copy_tags.txt	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/stringio/initialize_copy_tags.txt	2009-08-22 19:05:28 UTC (rev 2357)
@@ -1 +0,0 @@
-fails:StringIO#initialize_copy is private

Deleted: MacRuby/trunk/spec/frozen/tags/macruby/library/stringscanner/initialize_copy_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/stringscanner/initialize_copy_tags.txt	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/stringscanner/initialize_copy_tags.txt	2009-08-22 19:05:28 UTC (rev 2357)
@@ -1 +0,0 @@
-fails:StringScanner#initialize_copy is a private method

Deleted: MacRuby/trunk/spec/frozen/tags/macruby/library/stringscanner/initialize_tags.txt
===================================================================
--- MacRuby/trunk/spec/frozen/tags/macruby/library/stringscanner/initialize_tags.txt	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/spec/frozen/tags/macruby/library/stringscanner/initialize_tags.txt	2009-08-22 19:05:28 UTC (rev 2357)
@@ -1 +0,0 @@
-fails:StringScanner#initialize is a private method

Modified: MacRuby/trunk/vm.cpp
===================================================================
--- MacRuby/trunk/vm.cpp	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/vm.cpp	2009-08-22 19:05:28 UTC (rev 2357)
@@ -179,7 +179,7 @@
 #define VALUE_TO_GV(v) (value2gv((VALUE)v))
 
 extern "C" void *__cxa_allocate_exception(size_t);
-extern "C" void __cxa_throw(void *, void *, void (*)(void*));
+extern "C" void __cxa_throw(void *, void *, void (*)(void *));
 
 RoxorCore::RoxorCore(void)
 {
@@ -472,7 +472,6 @@
     return GET_CORE()->constant_cache_get(rb_intern(name));
 }
 
-
 struct mcache *
 RoxorCore::method_cache_get(SEL sel, bool super)
 {
@@ -503,15 +502,31 @@
 RoxorCore::method_node_get(IMP imp)
 {
     std::map<IMP, rb_vm_method_node_t *>::iterator iter = ruby_imps.find(imp);
-    rb_vm_method_node_t *m = iter == ruby_imps.end() ? NULL : iter->second;
-    return m;
+    return iter == ruby_imps.end() ? NULL : iter->second;
 }
 
+inline rb_vm_method_node_t *
+RoxorCore::method_node_get(Method m, bool create)
+{
+    std::map<Method, rb_vm_method_node_t *>::iterator iter =
+	ruby_methods.find(m);
+    if (iter == ruby_methods.end()) {
+	if (create) {
+	    rb_vm_method_node_t *n =
+		(rb_vm_method_node_t *)malloc(sizeof(rb_vm_method_node_t));
+	    ruby_methods[m] = n;
+	    return n;
+	}
+	return NULL;
+    }
+    return iter->second;
+}
+
 extern "C"
-rb_vm_method_node_t *
-rb_vm_get_method_node(IMP imp)
+bool
+rb_vm_is_ruby_method(Method m)
 {
-    return GET_CORE()->method_node_get(imp);
+    return GET_CORE()->method_node_get(m) != NULL;
 }
 
 size_t
@@ -597,28 +612,47 @@
 RoxorCore::add_method(Class klass, SEL sel, IMP imp, IMP ruby_imp,
 	const rb_vm_arity_t &arity, int flags, const char *types)
 {
+    // #initialize and #initialize_copy are always private.
+    if (sel == selInitialize || sel == selInitialize2
+	    || sel == selInitializeCopy) {
+	flags |= VM_METHOD_PRIVATE;
+    }
+
 #if ROXOR_VM_DEBUG
-    printf("defining %c[%s %s] with imp %p types %s\n",
+    printf("defining %c[%s %s] with imp %p/%p types %s flags %d\n",
 	    class_isMetaClass(klass) ? '+' : '-',
 	    class_getName(klass),
 	    sel_getName(sel),
 	    imp,
-	    types);
+	    ruby_imp,
+	    types,
+	    flags);
 #endif
 
     // Register the implementation into the runtime.
     class_replaceMethod(klass, sel, imp, types);
 
-    // Cache the method node.
-    std::map<IMP, rb_vm_method_node_t *>::iterator iter = ruby_imps.find(imp);
+    // Cache the method.
+    Method m = class_getInstanceMethod(klass, sel);
+    assert(m != NULL);
+    assert(method_getImplementation(m) == imp);
+    rb_vm_method_node_t *real_node = method_node_get(m, true);
+    real_node->objc_imp = imp;
+    real_node->ruby_imp = ruby_imp;
+    real_node->arity = arity;
+    real_node->flags = flags;
+    real_node->sel = sel;
+
+    // Cache the implementation.
+    std::map<IMP, rb_vm_method_node_t *>::iterator iter2 = ruby_imps.find(imp);
     rb_vm_method_node_t *node;
-    if (iter == ruby_imps.end()) {
+    if (iter2 == ruby_imps.end()) {
 	node = (rb_vm_method_node_t *)malloc(sizeof(rb_vm_method_node_t));
+	node->objc_imp = imp;
 	ruby_imps[imp] = node;
-	node->objc_imp = imp;
     }
     else {
-	node = iter->second;
+	node = iter2->second;
 	assert(node->objc_imp == imp);
     }
     node->arity = arity;
@@ -630,9 +664,9 @@
     }
 
     // Invalidate dispatch cache.
-    std::map<SEL, struct mcache *>::iterator iter2 = mcache.find(sel);
-    if (iter2 != mcache.end()) {
-	iter2->second->flag = 0;
+    std::map<SEL, struct mcache *>::iterator iter3 = mcache.find(sel);
+    if (iter3 != mcache.end()) {
+	iter3->second->flag = 0;
     }
 
     // Invalidate inline operations.
@@ -678,7 +712,6 @@
 	    int i, count = RARRAY_LEN(included_in_classes);
 	    for (i = 0; i < count; i++) {
 		VALUE mod = RARRAY_AT(included_in_classes, i);
-		class_replaceMethod((Class)mod, sel, imp, types);
 #if ROXOR_VM_DEBUG
 		printf("forward %c[%s %s] with imp %p node %p types %s\n",
 			class_isMetaClass((Class)mod) ? '+' : '-',
@@ -688,11 +721,22 @@
 			node,
 			types);
 #endif
+		class_replaceMethod((Class)mod, sel, imp, types);
+
+		Method m = class_getInstanceMethod((Class)mod, sel);
+		assert(m != NULL);
+		assert(method_getImplementation(m) == imp);
+		node = method_node_get(m, true);
+		node->objc_imp = imp;
+		node->ruby_imp = ruby_imp;
+		node->arity = arity;
+		node->flags = flags;
+		node->sel = sel;
 	    }
 	}
     }
 
-    return node;
+    return real_node;
 }
 
 void
@@ -1085,9 +1129,10 @@
     IMP imp = method_getImplementation(method);
     const char *types = method_getTypeEncoding(method);
 
-    rb_vm_method_node_t *node = GET_CORE()->method_node_get(imp);
+    rb_vm_method_node_t *node = GET_CORE()->method_node_get(method);
     if (node == NULL) {
-	rb_raise(rb_eArgError, "cannot alias non-Ruby method `%s'",
+	rb_raise(rb_eArgError,
+		"only pure Ruby methods can be aliased (`%s' is not)",
 		sel_getName(method_getName(method)));
     }
 
@@ -1144,13 +1189,13 @@
 
 extern "C"
 void
-rb_vm_undef(VALUE klass, ID name)
+rb_vm_undef(VALUE klass, VALUE name)
 {
     Class k = GET_VM()->get_current_class();
     if (k != NULL) {
 	klass = (VALUE)k;
     }
-    rb_undef(klass, name);
+    rb_vm_undef_method((Class)klass, rb_to_id(name), true);
 }
 
 extern "C"
@@ -1283,14 +1328,17 @@
 	const rb_vm_arity_t &arity, int flags, IMP imp, Method m)
 {
     if (imp == NULL) {
+	// Compile if necessary.
 	assert(func != NULL);
 	imp = compile(func);
     }
 
+    // Resolve Objective-C signature.
     const int oc_arity = arity.real + 3;
     char types[100];
     resolve_method_type(types, sizeof types, klass, m, sel, oc_arity);
 
+    // Generate Objective-C stub if needed.
     std::map<IMP, IMP>::iterator iter = objc_to_ruby_stubs.find(imp);
     IMP objc_imp;
     if (iter == objc_to_ruby_stubs.end()) {
@@ -1303,6 +1351,21 @@
 	objc_imp = iter->second;
     }
 
+    // Delete the selector from the not-yet-JIT'ed cache if needed.
+    std::multimap<Class, SEL>::iterator iter2, last2;
+    iter2 = method_source_sels.find(klass);
+    if (iter2 != method_source_sels.end()) {
+	last2 = method_source_sels.upper_bound(klass);
+	while (iter2 != last2) {
+	    if (iter2->second == sel) {
+		method_source_sels.erase(iter2);
+		break;
+	    }
+	    ++iter2;
+	}
+    }
+
+    // Finally, add the method.
     return add_method(klass, sel, objc_imp, imp, arity, flags, types);
 }
 
@@ -1380,11 +1443,13 @@
 	const rb_vm_arity_t &arity, int flags)
 {
 #if ROXOR_VM_DEBUG
-    printf("preparing %c[%s %s] with LLVM func %p\n",
+    printf("preparing %c[%s %s] on class %p LLVM func %p flags %d\n",
 	    class_isMetaClass(klass) ? '+' : '-',
 	    class_getName(klass),
 	    sel_getName(sel),
-	    func);
+	    klass,
+	    func,
+	    flags);
 #endif
 
     std::map<Class, rb_vm_method_source_t *> *map =
@@ -1408,18 +1473,33 @@
 }
 
 static void
-prepare_method(Class klass, SEL sel, void *data,
+prepare_method(Class klass, bool singleton, SEL sel, void *data,
 	const rb_vm_arity_t &arity, int flags, bool precompiled)
 {
-    Class k = GET_VM()->get_current_class();
-    if (k != NULL) {
-	const bool meta = class_isMetaClass(klass);
-	klass = k;
-	if (meta) {
-	    klass = *(Class *)klass;
+    if (!singleton) {
+	Class k = GET_VM()->get_current_class();
+	if (k != NULL) {
+	    const bool meta = class_isMetaClass(klass);
+	    klass = k;
+	    if (meta) {
+		klass = *(Class *)klass;
+	    }
 	}
     }
 
+    const long v = RCLASS_VERSION(klass);
+    if (v & RCLASS_SCOPE_PRIVATE) {
+	flags |= VM_METHOD_PRIVATE;
+    }
+    else if (v & RCLASS_SCOPE_PROTECTED) {
+	flags |= VM_METHOD_PROTECTED;
+    }
+
+    if (sel == sel_ignored) {
+	// TODO
+	return;
+    }
+
     const char *sel_name = sel_getName(sel);
     const bool genuine_selector = sel_name[strlen(sel_name) - 1] == ':';
     bool redefined = false;
@@ -1476,8 +1556,10 @@
 	    int i, count = RARRAY_LEN(included_in_classes);
 	    for (i = 0; i < count; i++) {
 		VALUE mod = RARRAY_AT(included_in_classes, i);
-		prepare_method((Class)mod, orig_sel, data, arity, flags,
+		rb_vm_set_current_scope(mod, SCOPE_PUBLIC);
+		prepare_method((Class)mod, false, orig_sel, data, arity, flags,
 			precompiled);
+		rb_vm_set_current_scope(mod, SCOPE_DEFAULT);
 	    }
 	}
     }
@@ -1485,29 +1567,29 @@
 
 extern "C"
 void
-rb_vm_prepare_method(Class klass, SEL sel, Function *func,
+rb_vm_prepare_method(Class klass, bool singleton, SEL sel, Function *func,
 	const rb_vm_arity_t arity, int flags)
 {
-    prepare_method(klass, sel, (void *)func, arity, flags, false);
+    prepare_method(klass, singleton, sel, (void *)func, arity, flags, false);
 }
 
 extern "C"
 void
-rb_vm_prepare_method2(Class klass, SEL sel, IMP ruby_imp,
+rb_vm_prepare_method2(Class klass, bool singleton, SEL sel, IMP ruby_imp,
 	const rb_vm_arity_t arity, int flags)
 {
-    prepare_method(klass, sel, (void *)ruby_imp, arity, flags, true);
+    prepare_method(klass, singleton, sel, (void *)ruby_imp, arity, flags, true);
 }
 
-static void __rb_vm_define_method(Class klass, SEL sel, IMP objc_imp,
-	IMP ruby_imp, const rb_vm_arity_t &arity, int flags, bool direct);
+static rb_vm_method_node_t * __rb_vm_define_method(Class klass, SEL sel,
+	IMP objc_imp, IMP ruby_imp, const rb_vm_arity_t &arity, int flags,
+	bool direct);
 
 #define VISI(x) ((x)&NOEX_MASK)
 #define VISI_CHECK(x,f) (VISI(x) == (f))
 
 static void
-push_method(VALUE ary, SEL sel, rb_vm_method_node_t *node,
-	    int (*filter) (VALUE, ID, VALUE))
+push_method(VALUE ary, SEL sel, int flags, int (*filter) (VALUE, ID, VALUE))
 {
     if (sel == sel_ignored) {
 	return; 
@@ -1530,16 +1612,33 @@
     VALUE sym = ID2SYM(mid);
 
     if (rb_ary_includes(ary, sym) == Qfalse) {
-	if (node != NULL) {
-	    const int type = rb_vm_method_node_noex(node);
-	    (*filter)(sym, type, ary);
+	int type = NOEX_PUBLIC;
+	if (flags & VM_METHOD_PRIVATE) {
+	    type = NOEX_PRIVATE;
 	}
-	else {
-	    rb_ary_push(ary, sym);
+	else if (flags & VM_METHOD_PROTECTED) {
+	    type = NOEX_PROTECTED;
 	}
+	(*filter)(sym, type, ary);
     }
 } 
 
+rb_vm_method_source_t *
+RoxorCore::method_source_get(Class klass, SEL sel)
+{
+    std::map<SEL, std::map<Class, rb_vm_method_source_t *> *>::iterator iter
+	= method_sources.find(sel);
+    if (iter != method_sources.end()) {
+	std::map<Class, rb_vm_method_source_t *> *m = iter->second;
+	std::map<Class, rb_vm_method_source_t *>::iterator iter2
+	    = m->find(klass);
+	if (iter2 != m->end()) {
+	    return iter2->second;
+	}
+    }
+    return NULL;
+}
+
 void
 RoxorCore::get_methods(VALUE ary, Class klass, bool include_objc_methods,
 	int (*filter) (VALUE, ID, VALUE))
@@ -1551,13 +1650,12 @@
     if (methods != NULL) {
 	for (unsigned int i = 0; i < count; i++) {
 	    Method m = methods[i];
-	    SEL sel = method_getName(m);
-	    IMP imp = method_getImplementation(m);
-	    rb_vm_method_node_t *node = rb_vm_get_method_node(imp);
+	    rb_vm_method_node_t *node = method_node_get(m);
 	    if (node == NULL && !include_objc_methods) {
 		continue;
 	    }
-	    push_method(ary, sel, node, filter);
+	    SEL sel = method_getName(m);
+	    push_method(ary, sel, node == NULL ? 0 : node->flags, filter);
 	}
 	free(methods);
     }
@@ -1573,8 +1671,9 @@
 
 	    for (; iter != last; ++iter) {
 		SEL sel = iter->second;
-		// TODO retrieve method NODE*
-		push_method(ary, sel, NULL, filter);
+		rb_vm_method_source_t *src = method_source_get(k, sel);
+		assert(src != NULL);
+		push_method(ary, sel, src->flags, filter);
 	    }
 	}
 
@@ -1628,8 +1727,13 @@
     methods = class_copyMethodList(from_class, &methods_count);
     if (methods != NULL) {
 	for (i = 0; i < methods_count; i++) {
-	    Method method = methods[i];
-	    SEL sel = method_getName(method);
+	    Method m = methods[i];
+	    rb_vm_method_node_t *node = method_node_get(m);
+	    if (node == NULL) {
+		// Only copy pure-Ruby methods.
+		continue;
+	    }
+	    SEL sel = method_getName(m);
 
 #if ROXOR_VM_DEBUG
 	    printf("copy %c[%s %s] to %s\n",
@@ -1641,9 +1745,15 @@
 
 	    class_replaceMethod(to_class,
 		    sel,
-		    method_getImplementation(method),
-		    method_getTypeEncoding(method));
+		    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) {
@@ -1740,15 +1850,14 @@
 	*pimp = imp;
     }
     if (pnode != NULL) {
-	*pnode = GET_CORE()->method_node_get(imp);
+	*pnode = GET_CORE()->method_node_get(m);
     }
     return true;
 }
 
 extern "C"
 void
-rb_vm_define_attr(Class klass, const char *name, bool read, bool write,
-		  int noex)
+rb_vm_define_attr(Class klass, const char *name, bool read, bool write)
 {
     assert(klass != NULL);
     assert(read || write);
@@ -1760,27 +1869,35 @@
     if (read) {
 	Function *f = RoxorCompiler::shared->compile_read_attr(iname);
 	SEL sel = sel_registerName(name);
-	rb_vm_prepare_method(klass, sel, f, rb_vm_arity(0), NODE_FBODY);
+	rb_vm_prepare_method(klass, false, sel, f, rb_vm_arity(0),
+		VM_METHOD_FBODY);
     }
 
     if (write) {
 	Function *f = RoxorCompiler::shared->compile_write_attr(iname);
 	snprintf(buf, sizeof buf, "%s=:", name);
 	SEL sel = sel_registerName(buf);
-	rb_vm_prepare_method(klass, sel, f, rb_vm_arity(1), NODE_FBODY);
+	rb_vm_prepare_method(klass, false, sel, f, rb_vm_arity(1),
+		VM_METHOD_FBODY);
     }
 }
 
-static void
+static rb_vm_method_node_t *
 __rb_vm_define_method(Class klass, SEL sel, IMP objc_imp, IMP ruby_imp,
 		      const rb_vm_arity_t &arity, int flags, bool direct)
 {
     assert(klass != NULL);
 
+    if (sel == sel_ignored) {
+	// TODO
+	return NULL;
+    }
+
     const char *sel_name = sel_getName(sel);
     const bool genuine_selector = sel_name[strlen(sel_name) - 1] == ':';
     int oc_arity = genuine_selector ? arity.real : 0;
     bool redefined = direct;
+    rb_vm_method_node_t *node;
 
 define_method:
     Method method = class_getInstanceMethod(klass, sel);
@@ -1788,7 +1905,8 @@
     char types[100];
     resolve_method_type(types, sizeof types, klass, method, sel, oc_arity);
 
-    GET_CORE()->add_method(klass, sel, objc_imp, ruby_imp, arity, flags, types);
+    node = GET_CORE()->add_method(klass, sel, objc_imp, ruby_imp, arity,
+	    flags, types);
 
     if (!redefined) {
 	if (!genuine_selector && arity.max != arity.min) {
@@ -1811,28 +1929,34 @@
 	    goto define_method;
 	}
     }
+
+    return node;
 }
 
 extern "C"
-void 
+rb_vm_method_node_t * 
 rb_vm_define_method(Class klass, SEL sel, IMP imp, NODE *node, bool direct)
 {
     assert(node != NULL);
 
     // TODO: create objc_imp
-    __rb_vm_define_method(klass, sel, imp, imp, rb_vm_node_arity(node),
+    return __rb_vm_define_method(klass, sel, imp, imp, rb_vm_node_arity(node),
 	    rb_vm_node_flags(node), direct);
 }
 
 extern "C"
-void 
+rb_vm_method_node_t * 
 rb_vm_define_method2(Class klass, SEL sel, rb_vm_method_node_t *node,
-		     bool direct)
+	bool direct)
 {
     assert(node != NULL);
 
-    __rb_vm_define_method(klass, sel, node->objc_imp, node->ruby_imp,
-	    node->arity, node->flags, direct);
+    long flags = node->flags;
+    flags &= ~VM_METHOD_PRIVATE;
+    flags &= ~VM_METHOD_PROTECTED;
+
+    return __rb_vm_define_method(klass, sel, node->objc_imp, node->ruby_imp,
+	    node->arity, flags, direct);
 }
 
 extern "C"
@@ -1850,38 +1974,77 @@
     rb_vm_define_method(klass, sel, imp, body, false);
 }
 
+static VALUE method_missing(VALUE obj, SEL sel, int argc, const VALUE *argv,
+	rb_vm_method_missing_reason_t call_status);
+
+static void *
+undefined_imp(void *rcv, SEL sel)
+{
+    method_missing((VALUE)rcv, sel, NULL, NULL, METHOD_MISSING_DEFAULT);
+    return NULL; // never reached
+}
+
+#define UNDEFINED_IMP(imp) (imp == NULL || imp == (IMP)undefined_imp)
+
+void
+RoxorCore::undef_method(Class klass, SEL sel)
+{
+#if ROXOR_VM_DEBUG
+    printf("undef %c[%s %s]\n",
+	    class_isMetaClass(klass) ? '+' : '-',
+	    class_getName(klass),
+	    sel_getName(sel));
+#endif
+
+    class_replaceMethod((Class)klass, sel, (IMP)undefined_imp, "@@:");
+
+#if 0
+    std::map<Method, rb_vm_method_node_t *>::iterator iter
+	= ruby_methods.find(m);
+    assert(iter != ruby_methods.end());
+    free(iter->second);
+    ruby_methods.erase(iter);
+#endif
+
+#if 0
+    // TODO call undefined
+    if (RCLASS_SINGLETON(klass)) {
+	rb_funcall(rb_iv_get(klass, "__attached__"),
+		   singleton_undefined, 1, ID2SYM(id));
+    }
+    else {
+	rb_funcall(klass, undefined, 1, ID2SYM(id));
+    }
+#endif
+}
+
 extern "C"
 void
-rb_vm_undef_method(Class klass, const char *name, bool must_exist)
+rb_vm_undef_method(Class klass, ID name, bool must_exist)
 {
     rb_vm_method_node_t *node = NULL;
 
-    if (!rb_vm_lookup_method2((Class)klass, rb_intern(name), NULL, NULL,
-		&node)) {
+    if (!rb_vm_lookup_method2((Class)klass, name, NULL, NULL, &node)) {
 	if (must_exist) {
 	    rb_raise(rb_eNameError, "undefined method `%s' for %s `%s'",
-		    name,
+		    rb_id2name(name),
 		    TYPE(klass) == T_MODULE ? "module" : "class",
 		    rb_class2name((VALUE)klass));
 	}
-	assert(name[strlen(name) - 1] != ':');
-	SEL sel = sel_registerName(name);
-	class_replaceMethod((Class)klass, sel, NULL, "@@:");
+	const char *namestr = rb_id2name(name);
+	SEL sel = sel_registerName(namestr);
+	GET_CORE()->undef_method(klass, sel);
     }
-
-    if (node == NULL) {
+    else if (node == NULL) {
 	if (must_exist) {
 	    rb_raise(rb_eRuntimeError,
 		    "cannot undefine method `%s' because it is a native method",
-		    name);
+		    rb_id2name(name));
 	}
-	return; // Do nothing.
     }
-
-    Method m = class_getInstanceMethod((Class)klass, node->sel);
-    assert(m != NULL);
-    class_replaceMethod((Class)klass, node->sel, NULL,
-	    method_getTypeEncoding(m));
+    else {
+	GET_CORE()->undef_method(klass, node->sel);
+    }
 }
 
 extern "C"
@@ -2157,41 +2320,48 @@
         rb_raise(rb_eArgError, "no id given");
     }
 
-    const unsigned char last_call_status =
+    const rb_vm_method_missing_reason_t last_call_status =
 	GET_VM()->get_method_missing_reason();
     const char *format = NULL;
     VALUE exc = rb_eNoMethodError;
 
     switch (last_call_status) {
-#if 0 // TODO
-	case NOEX_PRIVATE:
+	case METHOD_MISSING_PRIVATE:
 	    format = "private method `%s' called for %s";
 	    break;
 
-	case NOEX_PROTECTED:
+	case METHOD_MISSING_PROTECTED:
 	    format = "protected method `%s' called for %s";
 	    break;
-#endif
 
-	case DISPATCH_VCALL:
+	case METHOD_MISSING_VCALL:
 	    format = "undefined local variable or method `%s' for %s";
 	    exc = rb_eNameError;
 	    break;
 
-	case DISPATCH_SUPER:
+	case METHOD_MISSING_SUPER:
 	    format = "super: no superclass method `%s' for %s";
 	    break;
 
+	case METHOD_MISSING_DEFAULT:
 	default:
 	    format = "undefined method `%s' for %s";
 	    break;
     }
 
+    VALUE meth = rb_sym_to_s(argv[0]);
+    if (!rb_vm_respond_to(obj, selToS, true)) {
+	// In case #to_s was undefined on the object, let's generate a
+	// basic string based on it, because otherwise the following code
+	// will raise a #method_missing which will result in an infinite loop.
+	obj = rb_any_to_s(obj);
+    }
+
     int n = 0;
     VALUE args[3];
-    args[n++] = rb_funcall(rb_cNameErrorMesg, '!', 3, rb_str_new2(format), obj,
-	    argv[0]);
-    args[n++] = argv[0];
+    args[n++] = rb_funcall(rb_cNameErrorMesg, '!', 3, rb_str_new2(format),
+	    obj, meth);
+    args[n++] = meth;
     if (exc == rb_eNoMethodError) {
 	args[n++] = rb_ary_new4(argc - 1, argv + 1);
     }
@@ -2204,7 +2374,7 @@
 
 static VALUE
 method_missing(VALUE obj, SEL sel, int argc, const VALUE *argv,
-	       unsigned char call_status)
+	       rb_vm_method_missing_reason_t call_status)
 {
     GET_VM()->set_method_missing_reason(call_status);
 
@@ -2326,7 +2496,7 @@
 
 static force_inline VALUE
 __rb_vm_ruby_dispatch(VALUE self, SEL sel, rb_vm_method_node_t *node,
-		      int argc, const VALUE *argv)
+		      unsigned char opt, int argc, const VALUE *argv)
 {
     const rb_vm_arity_t &arity = node->arity;
     if ((argc < arity.min) || ((arity.max != -1) && (argc > arity.max))) {
@@ -2334,11 +2504,18 @@
 		argc, arity.min);
     }
 
-    if (rb_vm_method_node_empty(node) && arity.max == arity.min) {
+    if ((node->flags & VM_METHOD_PRIVATE) && opt == 0) {
+	// Calling a private method with no explicit receiver OR an attribute
+	// assignment to non-self, triggering #method_missing.
+	method_missing(self, sel, argc, argv, METHOD_MISSING_PRIVATE);
+    }
+
+    if ((node->flags & VM_METHOD_EMPTY) && arity.max == arity.min) {
 	// Calling an empty method, let's just return nil!
 	return Qnil;
     }
-    if (rb_vm_method_node_type(node) == NODE_FBODY && arity.max != arity.min) {
+
+    if ((node->flags & VM_METHOD_FBODY) && arity.max != arity.min) {
 	// Calling a function defined with rb_objc_define_method with
 	// a negative arity, which means a different calling convention.
 	if (arity.real == 2) {
@@ -2360,7 +2537,8 @@
 }
 
 static force_inline void
-fill_rcache(struct mcache *cache, Class klass, rb_vm_method_node_t *node)
+fill_rcache(struct mcache *cache, Class klass, SEL sel,
+	rb_vm_method_node_t *node)
 {
     cache->flag = MCACHE_RCALL;
     rcache.klass = klass;
@@ -2446,16 +2624,16 @@
 recache2:
 	    IMP imp = method_getImplementation(method);
 
-	    if (imp == NULL) {
+	    if (UNDEFINED_IMP(imp)) {
 		// Method was undefined.
 		goto call_method_missing;
 	    }
 
-	    rb_vm_method_node_t *node = GET_CORE()->method_node_get(imp);
+	    rb_vm_method_node_t *node = GET_CORE()->method_node_get(method);
 
 	    if (node != NULL) {
 		// ruby call
-		fill_rcache(cache, klass, node);
+		fill_rcache(cache, klass, sel, node);
 	    }
 	    else {
 		// objc call
@@ -2523,8 +2701,7 @@
 	    if (new_sel != NULL) {
 		Method m = class_getInstanceMethod(klass, new_sel);
 		if (m != NULL) {
-		    IMP imp = method_getImplementation(m);
-		    if (rb_vm_get_method_node(imp) == NULL) {
+		    if (GET_CORE()->method_node_get(m) == NULL) {
 			sel = new_sel;
 			method = m;
 			goto recache2;
@@ -2596,7 +2773,7 @@
 	    }
 	} finalizer(block_already_current, vm);
 
-	return __rb_vm_ruby_dispatch(self, sel, rcache.node, argc, argv);
+	return __rb_vm_ruby_dispatch(self, sel, rcache.node, opt, argc, argv);
     }
     else if (cache->flag == MCACHE_OCALL) {
 	if (ocache.klass != klass) {
@@ -2723,14 +2900,17 @@
     if (new_sel != 0) {
 	Method m = class_getInstanceMethod(klass, new_sel);
 	if (m != NULL
-		&& GET_CORE()->method_node_get(method_getImplementation(m))
-		!= NULL) {
+		&& GET_CORE()->method_node_get(m) != NULL) {
 	    rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)",
 		    argc, argc_expected);
 	}
     }
 
-    return method_missing((VALUE)self, sel, argc, argv, opt);
+    rb_vm_method_missing_reason_t status =
+	opt == DISPATCH_VCALL
+	    ? METHOD_MISSING_VCALL : opt == DISPATCH_SUPER
+		? METHOD_MISSING_SUPER : METHOD_MISSING_DEFAULT;
+    return method_missing((VALUE)self, sel, argc, argv, status);
 }
 
 #define MAX_DISPATCH_ARGS 200
@@ -3441,17 +3621,17 @@
 rb_vm_call(VALUE self, SEL sel, int argc, const VALUE *argv, bool super)
 {
     struct mcache *cache;
-    unsigned char flg = 0;
+    unsigned char opt = DISPATCH_FCALL;
     if (super) {
 	cache = (struct mcache *)alloca(sizeof(struct mcache));
 	cache->flag = 0;
-	flg = DISPATCH_SUPER;
+	opt = DISPATCH_SUPER;
     }
     else {
 	cache = GET_CORE()->method_cache_get(sel, false);
     }
 
-    return __rb_vm_dispatch(GET_VM(), cache, self, NULL, sel, NULL, flg, argc,
+    return __rb_vm_dispatch(GET_VM(), cache, self, NULL, sel, NULL, opt, argc,
 	    argv);
 }
 
@@ -3461,7 +3641,7 @@
 	const VALUE *argv)
 {
     return __rb_vm_dispatch(GET_VM(), (struct mcache *)cache, self, NULL, sel,
-	    NULL, 0, argc, argv);
+	    NULL, DISPATCH_FCALL, argc, argv);
 }
 
 extern "C"
@@ -3470,8 +3650,7 @@
 	VALUE klass, SEL sel, int argc, const VALUE *argv)
 {
     return __rb_vm_dispatch(GET_VM(), (struct mcache *)cache, self,
-	    (Class)klass, sel,
-	    block, 0, argc, argv);
+	    (Class)klass, sel, block, DISPATCH_FCALL, argc, argv);
 }
 
 extern "C"
@@ -3551,14 +3730,18 @@
     assert(method != NULL);
 
     int arity;
+    rb_vm_method_node_t *new_node;
     if (node == NULL) {
 	arity = method_getNumberOfArguments(method) - 2;
+	new_node = NULL;
     }
     else {
 	arity = node->arity.min;
 	if (node->arity.min != node->arity.max) {
 	    arity = -arity - 1;
 	}
+	new_node = (rb_vm_method_node_t *)xmalloc(sizeof(rb_vm_method_node_t));
+	memcpy(new_node, node, sizeof(rb_vm_method_node_t));
     }
 
     rb_vm_method_t *m = (rb_vm_method_t *)xmalloc(sizeof(rb_vm_method_t));
@@ -3568,18 +3751,16 @@
     GC_WB(&m->recv, obj);
     m->sel = sel;
     m->arity = arity;
-    m->node = node;
+    GC_WB(&m->node, new_node);
 
     // Let's allocate a static cache here, since a rb_vm_method_t must always
     // point to the method it was created from.
     struct mcache *c = (struct mcache *)xmalloc(sizeof(struct mcache));
-    if (node == NULL) {
+    if (new_node == NULL) {
 	fill_ocache(c, obj, oklass, imp, sel, method, arity);
     }
     else {
-	rb_vm_method_node_t *node = GET_CORE()->method_node_get(imp);
-	assert(node != NULL);
-	fill_rcache(c, oklass, node);
+	fill_rcache(c, oklass, sel, new_node);
     }
     GC_WB(&m->cache, c);
 
@@ -3856,16 +4037,10 @@
 extern "C" id _objc_msgForward(id receiver, SEL sel, ...);
 #endif
 
+#if 0
 static inline IMP
 class_respond_to(Class klass, SEL sel)
 {
-#if 0
-    Method m = class_getInstanceMethod(klass, sel);
-    if (m != NULL) {
-	return method_getImplementation(m);
-    }
-    return NULL;
-#else
     IMP imp = class_getMethodImplementation(klass, sel);
     if (imp == _objc_msgForward) {
 	if (rb_vm_resolve_method(klass, sel)) {
@@ -3876,8 +4051,8 @@
 	}
     }
     return imp;
+}
 #endif
-}
 
 extern "C"
 bool
@@ -3889,28 +4064,26 @@
 	    selRespondTo);
 
     if (respond_to_imp == basic_respond_to_imp) {
+	// FIXME: too slow!
 	bool reject_pure_ruby_methods = false;
-	IMP imp = class_respond_to((Class)klass, sel);
-	if (imp == NULL) {
+	Method m = class_getInstanceMethod((Class)klass, sel);
+	if (m == NULL) {
 	    const char *selname = sel_getName(sel);
 	    sel = helper_sel(selname, strlen(selname));
 	    if (sel != NULL) {
-		imp = class_respond_to((Class)klass, sel);
-		if (imp == NULL) {
-		    return false;
-		}
+		m = class_getInstanceMethod((Class)klass, sel);
 		reject_pure_ruby_methods = true;
 	    }
 	}
-	if (imp == NULL) {
+
+	if (m == NULL || UNDEFINED_IMP(method_getImplementation(m))) {
 	    return false;
 	}
 
-	rb_vm_method_node_t *node = GET_CORE()->method_node_get(imp);
+	rb_vm_method_node_t *node = GET_CORE()->method_node_get(m);
 	if (node != NULL
-		&& (reject_pure_ruby_methods
-		    || (priv == 0
-			&& (rb_vm_method_node_noex(node) & NOEX_PRIVATE)))) {
+	    && (reject_pure_ruby_methods
+		|| (!priv && (node->flags & VM_METHOD_PRIVATE)))) {
 	    return false;
 	}
         return true;
@@ -4968,6 +5141,76 @@
     rb_thread_wait_for(time);
 }
 
+extern "C"
+Class
+rb_vm_set_current_class(Class klass)
+{
+    RoxorVM *vm = GET_VM();
+    Class old = vm->get_current_class();
+    vm->set_current_class(klass);
+    return old;
+}
+
+extern "C"
+void
+rb_vm_set_current_scope(VALUE mod, rb_vm_scope_t scope)
+{
+    if (scope == SCOPE_DEFAULT) {
+	scope = mod == rb_cObject ? SCOPE_PRIVATE : SCOPE_PUBLIC;
+    }
+    long v = RCLASS_VERSION(mod);
+#if ROXOR_VM_DEBUG
+    const char *scope_name = NULL;
+#endif
+    switch (scope) {
+	case SCOPE_PUBLIC:
+#if ROXOR_VM_DEBUG
+	    scope_name = "public";
+#endif
+	    v &= ~RCLASS_SCOPE_PRIVATE;
+	    v &= ~RCLASS_SCOPE_PROTECTED;
+	    v &= ~RCLASS_SCOPE_MOD_FUNC;
+	    break;
+
+	case SCOPE_PRIVATE:
+#if ROXOR_VM_DEBUG
+	    scope_name = "private";
+#endif
+	    v |= RCLASS_SCOPE_PRIVATE;
+	    v &= ~RCLASS_SCOPE_PROTECTED;
+	    v &= ~RCLASS_SCOPE_MOD_FUNC;
+	    break;
+
+	case SCOPE_PROTECTED:
+#if ROXOR_VM_DEBUG
+	    scope_name = "protected";
+#endif
+	    v &= ~RCLASS_SCOPE_PRIVATE;
+	    v |= RCLASS_SCOPE_PROTECTED;
+	    v &= ~RCLASS_SCOPE_MOD_FUNC;
+	    break;
+
+	case SCOPE_MODULE_FUNC:
+#if ROXOR_VM_DEBUG
+	    scope_name = "module_func";
+#endif
+	    v &= ~RCLASS_SCOPE_PRIVATE;
+	    v &= ~RCLASS_SCOPE_PROTECTED;
+	    v |= RCLASS_SCOPE_MOD_FUNC;
+	    break;
+
+	case SCOPE_DEFAULT:
+	    abort(); // handled earlier
+    }
+
+#if ROXOR_VM_DEBUG
+    printf("changing scope of %s (%p) to %s\n",
+	    class_getName((Class)mod), (void *)mod, scope_name);
+#endif
+
+    RCLASS_SET_VERSION(mod, v);
+}
+
 static VALUE
 builtin_ostub1(IMP imp, id self, SEL sel, int argc, VALUE *argv)
 {
@@ -5109,6 +5352,8 @@
     VALUE top_self = rb_obj_alloc(rb_cTopLevel);
     rb_objc_retain((void *)top_self);
     GET_VM()->set_current_top_object(top_self);
+
+    rb_vm_set_current_scope(rb_cNSObject, SCOPE_PRIVATE);
 }
 
 extern "C"

Modified: MacRuby/trunk/vm.h
===================================================================
--- MacRuby/trunk/vm.h	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/vm.h	2009-08-22 19:05:28 UTC (rev 2357)
@@ -55,9 +55,42 @@
     rb_vm_local_t *locals;
 } rb_vm_binding_t;
 
-#define VM_METHOD_EMPTY	1000
+#define VM_METHOD_EMPTY		1 // method has an empty body (compilation)
+#define VM_METHOD_PRIVATE	2 // method is private (runtime)
+#define VM_METHOD_PROTECTED	4 // method is protected (runtime)
+#define VM_METHOD_FBODY		8 // method has a MRI C prototype (compilation) 
 
-typedef struct {
+static inline int
+rb_vm_noex_flag(const int noex)
+{
+    switch (noex) {
+	case NOEX_PRIVATE:
+	    return VM_METHOD_PRIVATE;
+	case NOEX_PROTECTED:
+	    return VM_METHOD_PROTECTED;
+	default:
+	case NOEX_PUBLIC:
+	    return 0;
+    }
+}
+
+static inline int
+rb_vm_node_flags(NODE *node)
+{
+    int flags = 0;
+    if (nd_type(node) == NODE_FBODY) {
+	flags |= VM_METHOD_FBODY;
+	if (nd_type(node->nd_body) == NODE_METHOD) {
+	    flags |= rb_vm_noex_flag(node->nd_body->nd_noex);
+	}
+    }
+    if (node->nd_body == NULL) {
+	flags |= VM_METHOD_EMPTY;
+    }
+    return flags;
+}
+
+typedef struct rb_vm_method_node {
     rb_vm_arity_t arity;
     SEL sel;
     IMP objc_imp;
@@ -102,16 +135,16 @@
     rb_vm_block_t *body;
     int argc;
     const VALUE *argv;
-    void *vm;  // a C++ instance of RoxorVM
+    void *vm;		// a C++ instance of RoxorVM
     VALUE value;
     pthread_mutex_t sleep_mutex;
     pthread_cond_t sleep_cond;
     rb_vm_thread_status_t status;
     bool in_cond_wait;
-    VALUE locals;  // a Hash object or Qnil
-    VALUE exception;  // killed-by exception or Qnil 
-    VALUE group;  // always a ThreadGroup object
-    VALUE mutexes;  // an Array object or Qnil
+    VALUE locals;	// a Hash object or Qnil
+    VALUE exception;	// killed-by exception or Qnil 
+    VALUE group;	// always a ThreadGroup object
+    VALUE mutexes;	// an Array object or Qnil
 } rb_vm_thread_t;
 
 typedef struct rb_vm_outer {
@@ -206,36 +239,6 @@
     abort();
 }
 
-static inline int
-rb_vm_node_flags(NODE *node)
-{
-    int flags = nd_type(node);
-    if (node->nd_body == NULL) {
-	flags |= VM_METHOD_EMPTY;
-    }
-    return flags;
-}
-
-static inline int
-rb_vm_method_node_type(rb_vm_method_node_t *node)
-{
-    return node->flags & VM_METHOD_EMPTY
-	? node->flags ^ VM_METHOD_EMPTY : node->flags; 
-}
-
-static inline bool
-rb_vm_method_node_empty(rb_vm_method_node_t *node)
-{
-    return node->flags & VM_METHOD_EMPTY;
-}
-
-static inline int
-rb_vm_method_node_noex(rb_vm_method_node_t *node)
-{
-    // TODO
-    return 0;
-}
-
 static inline NODE *
 rb_vm_cfunc_node_from_imp(Class klass, int arity, IMP imp, int noex)
 {
@@ -265,15 +268,14 @@
 	rb_vm_method_node_t **pnode);
 bool rb_vm_lookup_method2(Class klass, ID mid, SEL *psel, IMP *pimp,
 	rb_vm_method_node_t **pnode);
-rb_vm_method_node_t *rb_vm_get_method_node(IMP imp);
-void rb_vm_define_method(Class klass, SEL sel, IMP imp, NODE *node,
-	bool direct);
-void rb_vm_define_method2(Class klass, SEL sel, rb_vm_method_node_t *node,
-	bool direct);
+bool rb_vm_is_ruby_method(Method m);
+rb_vm_method_node_t *rb_vm_define_method(Class klass, SEL sel, IMP imp,
+	NODE *node, bool direct);
+rb_vm_method_node_t *rb_vm_define_method2(Class klass, SEL sel,
+	rb_vm_method_node_t *node, bool direct);
 void rb_vm_define_method3(Class klass, SEL sel, rb_vm_block_t *node);
-void rb_vm_define_attr(Class klass, const char *name, bool read, bool write,
-	int noex);
-void rb_vm_undef_method(Class klass, const char *name, bool must_exist);
+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_alias(VALUE klass, ID name, ID def);
 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);
@@ -415,6 +417,16 @@
 void rb_vm_load_bridge_support(const char *path, const char *framework_path,
 	int options);
 
+typedef enum {
+    SCOPE_DEFAULT = 0,	// public for everything but Object
+    SCOPE_PUBLIC,
+    SCOPE_PRIVATE,
+    SCOPE_PROTECTED,
+    SCOPE_MODULE_FUNC,
+} rb_vm_scope_t;
+
+void rb_vm_set_current_scope(VALUE mod, rb_vm_scope_t scope);
+
 VALUE rb_iseq_compile(VALUE src, VALUE file, VALUE line);
 VALUE rb_iseq_eval(VALUE iseq);
 VALUE rb_iseq_new(NODE *node, VALUE filename);
@@ -528,8 +540,9 @@
 	// Cache to avoid compiling the same Function twice.
 	std::map<Function *, IMP> JITcache;
 
-	// Cache to identify pure Ruby methods.
+	// Cache to identify pure Ruby implementations / methods.
 	std::map<IMP, rb_vm_method_node_t *> ruby_imps;
+	std::map<Method, rb_vm_method_node_t *> ruby_methods;
 
 	// Method and constant caches.
 	std::map<SEL, struct mcache *> mcache;
@@ -651,7 +664,10 @@
 
 	struct mcache *method_cache_get(SEL sel, bool super);
 	rb_vm_method_node_t *method_node_get(IMP imp);
+	rb_vm_method_node_t *method_node_get(Method m, bool create=false);
 
+	rb_vm_method_source_t *method_source_get(Class klass, SEL sel);
+
 	void prepare_method(Class klass, SEL sel, Function *func,
 		const rb_vm_arity_t &arity, int flag);
 	rb_vm_method_node_t *add_method(Class klass, SEL sel, IMP imp,
@@ -660,6 +676,7 @@
 	rb_vm_method_node_t *resolve_method(Class klass, SEL sel,
 		Function *func, const rb_vm_arity_t &arity, int flags,
 		IMP imp, Method m);
+	void undef_method(Class klass, SEL sel);
 	bool resolve_methods(std::map<Class, rb_vm_method_source_t *> *map,
 		Class klass, SEL sel);
 	void copy_methods(Class from_class, Class to_class);
@@ -717,6 +734,14 @@
 
 #define GET_CORE() (RoxorCore::shared)
 
+typedef enum {
+    METHOD_MISSING_DEFAULT = 0,
+    METHOD_MISSING_PRIVATE,
+    METHOD_MISSING_PROTECTED,
+    METHOD_MISSING_VCALL,
+    METHOD_MISSING_SUPER
+} rb_vm_method_missing_reason_t;
+
 // The VM class is instantiated per thread. There is always at least one
 // instance. The VM class is purely thread-safe and concurrent, it does not
 // acquire any lock, except when it calls the Core.
@@ -764,7 +789,7 @@
 	VALUE last_status;
 	VALUE errinfo;
 	int safe_level;
-	unsigned char method_missing_reason;
+	rb_vm_method_missing_reason_t method_missing_reason;
 	bool parse_in_eval;
 
     public:
@@ -780,7 +805,7 @@
 	ACCESSOR(last_status, VALUE);
 	ACCESSOR(errinfo, VALUE);
 	ACCESSOR(safe_level, int);
-	ACCESSOR(method_missing_reason, unsigned char);
+	ACCESSOR(method_missing_reason, rb_vm_method_missing_reason_t);
 	ACCESSOR(parse_in_eval, bool);
 
 	std::string debug_blocks(void);

Modified: MacRuby/trunk/vm_eval.c
===================================================================
--- MacRuby/trunk/vm_eval.c	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/vm_eval.c	2009-08-22 19:05:28 UTC (rev 2357)
@@ -500,7 +500,7 @@
 	klass = 0;
     }
     else {
-	klass = CLASS_OF(self);
+	klass = rb_singleton_class(self);
     }
     return specific_eval(argc, argv, klass, self);
 }

Modified: MacRuby/trunk/vm_method.c
===================================================================
--- MacRuby/trunk/vm_method.c	2009-08-21 22:00:44 UTC (rev 2356)
+++ MacRuby/trunk/vm_method.c	2009-08-22 19:05:28 UTC (rev 2357)
@@ -143,7 +143,7 @@
 	rb_name_error(mid, "method `%s' not defined in %s",
 		      rb_id2name(mid), rb_class2name(klass));
     }
-    if (rb_vm_get_method_node(method_getImplementation(m)) == NULL) {
+    if (!rb_vm_is_ruby_method(m)) {
 	rb_warn("removing pure Objective-C method `%s' may cause serious " \
 		"problem", rb_id2name(mid));
     }
@@ -217,15 +217,35 @@
 	}
     }
 
-#if 0 // TODO
-    if (node->nd_noex != noex) {
-	// TODO if the method exists on a super class, we should add a new method
-	// with the correct noex that calls super
-	assert(!rb_vm_lookup_method((Class)RCLASS_SUPER(klass), sel, NULL, NULL));
+    if (node == NULL) {
+	rb_raise(rb_eRuntimeError,
+		"can't change visibility of non Ruby method `%s'",
+		sel_getName(sel));
+    }
 
-	node->nd_noex = noex;
+    VALUE sklass = RCLASS_SUPER(klass);
+    if (sklass != 0) {
+	Method m = class_getInstanceMethod((Class)sklass, sel);
+	if (m != NULL && method_getImplementation(m) == node->objc_imp) {
+	    // The method actually exists on a superclass, we need to duplicate
+	    // it to the current class then change its visibility.
+	    node = rb_vm_define_method2((Class)klass, sel, node, false);
+	}
     }
-#endif
+
+    switch (noex) {
+	case NOEX_PUBLIC:
+	    node->flags |= 0;
+	    break;
+
+	case NOEX_PRIVATE:
+	    node->flags |= VM_METHOD_PRIVATE;
+	    break;
+
+	case NOEX_PROTECTED:
+	    node->flags |= VM_METHOD_PROTECTED;
+	    break;
+    }
 }
 
 int
@@ -245,25 +265,14 @@
 void
 rb_attr(VALUE klass, ID id, int read, int write, int ex)
 {
-    const char *name;
-    int noex;
-
-    if (!ex) {
-	noex = NOEX_PUBLIC;
-    }
-    else {
-	// TODO honor current scope ex
-	noex = NOEX_PUBLIC;
-    }
-
     if (!rb_is_local_id(id) && !rb_is_const_id(id)) {
 	rb_name_error(id, "invalid attribute name `%s'", rb_id2name(id));
     }
-    name = rb_id2name(id);
-    if (!name) {
+    const char *name = rb_id2name(id);
+    if (name == NULL) {
 	rb_raise(rb_eArgError, "argument needs to be symbol or string");
     }
-    rb_vm_define_attr((Class)klass, name, read, write, noex);
+    rb_vm_define_attr((Class)klass, name, read, write);
     if (write) {
 	rb_objc_define_kvo_setter(klass, id);
     }
@@ -272,59 +281,19 @@
 void
 rb_undef(VALUE klass, ID id)
 {
-    // TODO
-#if 0
-    VALUE origin;
-    NODE *body;
-
-#if 0 // TODO
-    if (rb_vm_cbase() == rb_cObject && klass == rb_cObject) {
+    if (klass == rb_cObject) {
 	rb_secure(4);
     }
-#endif
     if (rb_safe_level() >= 4 && !OBJ_TAINTED(klass)) {
 	rb_raise(rb_eSecurityError, "Insecure: can't undef `%s'",
-		 rb_id2name(id));
+		rb_id2name(id));
     }
     rb_frozen_class_p(klass);
     if (id == object_id || id == __send__ || id == idInitialize) {
 	rb_warn("undefining `%s' may cause serious problem", rb_id2name(id));
     }
-    /* TODO: warn if a very important method of NSObject is undefined 
-     * by default, pure objc methods are not exposed by introspections API 
-     */
-    body = search_method(klass, id, &origin);
-    if (!body || !body->nd_body) {
-	const char *s0 = " class";
-	VALUE c = klass;
 
-	if (RCLASS_SINGLETON(c)) {
-	    VALUE obj = rb_iv_get(klass, "__attached__");
-
-	    switch (TYPE(obj)) {
-	      case T_MODULE:
-	      case T_CLASS:
-		c = obj;
-		s0 = "";
-	    }
-	}
-	else if (TYPE(c) == T_MODULE) {
-	    s0 = " module";
-	}
-	rb_name_error(id, "undefined method `%s' for%s `%s'",
-		      rb_id2name(id), s0, rb_class2name(c));
-    }
-
-    rb_add_method(klass, id, 0, NOEX_PUBLIC);
-
-    if (RCLASS_SINGLETON(klass)) {
-	rb_funcall(rb_iv_get(klass, "__attached__"),
-		   singleton_undefined, 1, ID2SYM(id));
-    }
-    else {
-	rb_funcall(klass, undefined, 1, ID2SYM(id));
-    }
-#endif
+    rb_vm_undef_method((Class)klass, id, true);
 }
 
 /*
@@ -373,8 +342,7 @@
 static VALUE
 rb_mod_undef_method(VALUE mod, SEL sel, int argc, VALUE *argv)
 {
-    int i;
-    for (i = 0; i < argc; i++) {
+    for (int i = 0; i < argc; i++) {
 	rb_undef(mod, rb_to_id(argv[i]));
     }
     return mod;
@@ -441,19 +409,26 @@
  */
 
 static VALUE
-rb_mod_public_method_defined(VALUE mod, SEL sel, VALUE mid)
+check_method_visibility(VALUE mod, ID id, int visi)
 {
-    ID id = rb_to_id(mid);
-    NODE *method;
-
-    method = rb_method_node(mod, id);
-    if (method) {
-	if (VISI_CHECK(method->nd_noex, NOEX_PUBLIC))
-	    return Qtrue;
+    rb_vm_method_node_t *node;
+    if (rb_vm_lookup_method2((Class)mod, id, NULL, NULL, &node)) {
+	if (node != NULL) {
+	    if (node->flags & rb_vm_noex_flag(visi)) {
+		return Qtrue;
+	    }
+	}
     }
     return Qfalse;
 }
 
+static VALUE
+rb_mod_public_method_defined(VALUE mod, SEL sel, VALUE mid)
+{
+    ID id = rb_to_id(mid);
+    return check_method_visibility(mod, id, NOEX_PUBLIC);
+}
+
 /*
  *  call-seq:
  *     mod.private_method_defined?(symbol)    => true or false
@@ -484,14 +459,7 @@
 rb_mod_private_method_defined(VALUE mod, SEL sel, VALUE mid)
 {
     ID id = rb_to_id(mid);
-    NODE *method;
-
-    method = rb_method_node(mod, id);
-    if (method) {
-	if (VISI_CHECK(method->nd_noex, NOEX_PRIVATE))
-	    return Qtrue;
-    }
-    return Qfalse;
+    return check_method_visibility(mod, id, NOEX_PRIVATE);
 }
 
 /*
@@ -524,14 +492,7 @@
 rb_mod_protected_method_defined(VALUE mod, SEL sel, VALUE mid)
 {
     ID id = rb_to_id(mid);
-    NODE *method;
-
-    method = rb_method_node(mod, id);
-    if (method) {
-	if (VISI_CHECK(method->nd_noex, NOEX_PROTECTED))
-	    return Qtrue;
-    }
-    return Qfalse;
+    return check_method_visibility(mod, id, NOEX_PROTECTED);
 }
 
 void
@@ -581,9 +542,8 @@
 static void
 set_method_visibility(VALUE self, int argc, VALUE *argv, ID ex)
 {
-    int i;
     secure_visibility(self);
-    for (i = 0; i < argc; i++) {
+    for (int i = 0; i < argc; i++) {
 	rb_export_method(self, rb_to_id(argv[i]), ex);
     }
 }
@@ -603,7 +563,7 @@
 {
     secure_visibility(module);
     if (argc == 0) {
-	// TODO change scope!
+	rb_vm_set_current_scope(module, SCOPE_PUBLIC);
     }
     else {
 	set_method_visibility(module, argc, argv, NOEX_PUBLIC);
@@ -626,7 +586,7 @@
 {
     secure_visibility(module);
     if (argc == 0) {
-	// TODO change scope!
+	rb_vm_set_current_scope(module, SCOPE_PROTECTED);
     }
     else {
 	set_method_visibility(module, argc, argv, NOEX_PROTECTED);
@@ -658,7 +618,7 @@
 {
     secure_visibility(module);
     if (argc == 0) {
-	// TODO change scope!
+	rb_vm_set_current_scope(module, SCOPE_PRIVATE);
     }
     else {
 	set_method_visibility(module, argc, argv, NOEX_PRIVATE);
@@ -764,21 +724,19 @@
 static VALUE
 rb_mod_modfunc(VALUE module, SEL sel, int argc, VALUE *argv)
 {
-    int i;
-
     if (TYPE(module) != T_MODULE) {
 	rb_raise(rb_eTypeError, "module_function must be called for modules");
     }
 
     secure_visibility(module);
     if (argc == 0) {
-	// TODO change scope!
+	rb_vm_set_current_scope(module, SCOPE_MODULE_FUNC);
 	return module;
     }
 
     set_method_visibility(module, argc, argv, NOEX_PRIVATE);
 
-    for (i = 0; i < argc; i++) {
+    for (int i = 0; i < argc; i++) {
 	ID id = rb_to_id(argv[i]);
 	IMP imp;
 	rb_vm_method_node_t *node;
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20090822/fcf59771/attachment-0001.html>


More information about the macruby-changes mailing list