From ce9c9a8419a098747755d4570c0f415079807e2c Mon Sep 17 00:00:00 2001
From: Shugo Maeda <shugo@ruby-lang.org>
Date: Wed, 20 Oct 2010 00:16:42 +0900
Subject: [PATCH 30/51] reimplemented classboxes by C.

---
 class.c         |   14 +----
 eval.c          |  178 ++++++++++++++++++++++++++++++++++++++++++++++---------
 insns.def       |    4 +-
 object.c        |    1 -
 prelude.rb      |   73 ----------------------
 vm_insnhelper.c |   40 ++++++++++++
 vm_method.c     |   14 ++++
 7 files changed, 208 insertions(+), 116 deletions(-)

diff --git a/class.c b/class.c
index 3140f67..38321c8 100644
--- a/class.c
+++ b/class.c
@@ -418,14 +418,6 @@ rb_define_class_id(ID id, VALUE super)
     return klass;
 }
 
-VALUE
-rb_mod_opened(VALUE mod)
-{
-    ID opened;
-    CONST_ID(opened, "__opened__");
-    return rb_funcall(mod, opened, 0);
-}
-
 
 /*!
  * Calls Class#inherited.
@@ -1543,11 +1535,11 @@ rb_scan_args(int argc, const VALUE *argv, const char *fmt, ...)
 VALUE
 rb_classbox_new(void)
 {
-    VALUE mdl = class_alloc(T_MODULE, rb_cClassbox);
+    VALUE classbox = class_alloc(T_MODULE, rb_cClassbox);
 
-    RCLASS_M_TBL(mdl) = st_init_numtable();
+    RCLASS_M_TBL(classbox) = st_init_numtable();
 
-    return (VALUE)mdl;
+    return (VALUE) classbox;
 }
 
 VALUE
diff --git a/eval.c b/eval.c
index d371b04..04e8465 100644
--- a/eval.c
+++ b/eval.c
@@ -860,6 +860,136 @@ rb_mod_include(int argc, VALUE *argv, VALUE module)
 }
 
 void
+rb_overlay_module(NODE *cref, VALUE klass, VALUE module)
+{
+    VALUE iclass, c, superclass = klass;
+
+    Check_Type(module, T_MODULE);
+    if (NIL_P(cref->nd_omod)) {
+	cref->nd_omod = rb_hash_new();
+	rb_funcall(cref->nd_omod, rb_intern("compare_by_identity"), 0);
+    }
+    else {
+	if (cref->flags & NODE_FL_CREF_OMOD_SHARED) {
+	    cref->nd_omod = rb_hash_dup(cref->nd_omod);
+	    cref->flags &= ~NODE_FL_CREF_OMOD_SHARED;
+	}
+	if (!NIL_P(c = rb_hash_lookup(cref->nd_omod, klass))) {
+	    superclass = c;
+	}
+    }
+    c = iclass = rb_include_class_new(module, superclass);
+    module = RCLASS_SUPER(module);
+    while (module) {
+	c = RCLASS_SUPER(c) = rb_include_class_new(module, RCLASS_SUPER(c));
+	module = RCLASS_SUPER(module);
+    }
+    rb_hash_aset(cref->nd_omod, klass, iclass);
+    rb_clear_cache_by_class(klass);
+}
+
+static int
+import_classbox_i(VALUE klass, VALUE modules, VALUE arg)
+{
+    NODE *cref = (NODE *) arg;
+    int i;
+
+    for (i = 0; i < RARRAY_LEN(modules); i++) {
+	rb_overlay_module(cref, klass, RARRAY_PTR(modules)[i]);
+    }
+    return ST_CONTINUE;
+}
+
+void
+rb_import_classbox(NODE *cref, VALUE classbox)
+{
+    ID id_overlayed_modules;
+    VALUE overlayed_modules;
+
+    CONST_ID(id_overlayed_modules, "__overlayed_modules__");
+    overlayed_modules = rb_ivar_get(classbox, id_overlayed_modules);
+    if (NIL_P(overlayed_modules)) return;
+    rb_hash_foreach(overlayed_modules, import_classbox_i, (VALUE) cref);
+}
+
+/*
+ *  call-seq:
+ *     import(classbox)    -> self
+ *
+ *  Import <i>classbox</i> into the receiver.
+ */
+
+static VALUE
+rb_mod_import(VALUE module, VALUE classbox)
+{
+    NODE *cref = rb_vm_cref();
+    ID id_imported_classboxes;
+    VALUE imported_classboxes;
+
+    CONST_ID(id_imported_classboxes, "__imported_classboxes__");
+    imported_classboxes = rb_ivar_get(module, id_imported_classboxes);
+    if (NIL_P(imported_classboxes)) {
+	imported_classboxes = rb_hash_new();
+	rb_funcall(imported_classboxes, rb_intern("compare_by_identity"), 0);
+	rb_ivar_set(module, id_imported_classboxes, imported_classboxes);
+    }
+    rb_hash_aset(imported_classboxes, classbox, Qtrue);
+    rb_import_classbox(cref, classbox);
+    return module;
+}
+
+void rb_redefine_opt_method(VALUE, ID);
+
+static VALUE
+classbox_module_method_added(VALUE mod, VALUE mid)
+{
+    ID id = SYM2ID(mid);
+    ID id_refined_class;
+    VALUE klass;
+
+    CONST_ID(id_refined_class, "__refined_class__");
+    klass = rb_ivar_get(mod, id_refined_class);
+    rb_redefine_opt_method(klass, id);
+}
+
+/*
+ *  call-seq:
+ *     refine(klass) { block }   -> self
+ *
+ *  Refine <i>klass</i> in the receiver classbox.
+ */
+
+static VALUE
+rb_classbox_refine(VALUE classbox, VALUE klass)
+{
+    NODE *cref = rb_vm_cref();
+    VALUE mod = rb_module_new();
+    ID id_overlayed_modules, id_refined_class;
+    VALUE overlayed_modules, modules;
+
+    CONST_ID(id_overlayed_modules, "__overlayed_modules__");
+    overlayed_modules = rb_ivar_get(classbox, id_overlayed_modules);
+    if (NIL_P(overlayed_modules)) {
+	overlayed_modules = rb_hash_new();
+	rb_funcall(overlayed_modules, rb_intern("compare_by_identity"), 0);
+	rb_ivar_set(classbox, id_overlayed_modules, overlayed_modules);
+    }
+    modules = rb_hash_aref(overlayed_modules, klass);
+    if (NIL_P(modules)) {
+	modules = rb_ary_new();
+	rb_hash_aset(overlayed_modules, klass, modules);
+    }
+    rb_ary_push(modules, mod);
+    CONST_ID(id_refined_class, "__refined_class__");
+    rb_ivar_set(mod, id_refined_class, klass);
+    rb_define_singleton_method(mod, "method_added",
+			       classbox_module_method_added, 1);
+    rb_overlay_module(cref, klass, mod);
+    rb_mod_module_eval(0, NULL, mod);
+    return Qnil;
+}
+
+void
 rb_obj_call_init(VALUE obj, int argc, VALUE *argv)
 {
     PASS_PASSED_BLOCK();
@@ -971,35 +1101,6 @@ top_include(int argc, VALUE *argv, VALUE self)
     return rb_mod_include(argc, argv, rb_cObject);
 }
 
-void
-rb_overlay_module(NODE *cref, VALUE klass, VALUE module)
-{
-    VALUE iclass, c, superclass = klass;
-
-    Check_Type(module, T_MODULE);
-    if (NIL_P(cref->nd_omod)) {
-	cref->nd_omod = rb_hash_new();
-	rb_funcall(cref->nd_omod, rb_intern("compare_by_identity"), 0);
-    }
-    else {
-	if (cref->flags & NODE_FL_CREF_OMOD_SHARED) {
-	    cref->nd_omod = rb_hash_dup(cref->nd_omod);
-	    cref->flags &= ~NODE_FL_CREF_OMOD_SHARED;
-	}
-	if (!NIL_P(c = rb_hash_lookup(cref->nd_omod, klass))) {
-	    superclass = c;
-	}
-    }
-    c = iclass = rb_include_class_new(module, superclass);
-    module = RCLASS_SUPER(module);
-    while (module) {
-	c = RCLASS_SUPER(c) = rb_include_class_new(module, RCLASS_SUPER(c));
-	module = RCLASS_SUPER(module);
-    }
-    rb_hash_aset(cref->nd_omod, klass, iclass);
-    rb_clear_cache_by_class(klass);
-}
-
 /*
  *  call-seq:
  *     overlay_module(klass, mod [, binding])
@@ -1035,6 +1136,22 @@ f_overlay_module(int argc, VALUE *argv, VALUE self)
     return Qnil;
 }
 
+/*
+ *  call-seq:
+ *     import(classbox)    -> self
+ *
+ *  Import <i>classbox</i> into the scope where <code>import</code> is called.
+ */
+
+static VALUE
+f_import(VALUE self, VALUE classbox)
+{
+    NODE *cref = rb_vm_cref();
+
+    rb_import_classbox(cref, classbox);
+    return self;
+}
+
 VALUE rb_f_trace_var();
 VALUE rb_f_untrace_var();
 
@@ -1187,6 +1304,8 @@ Init_eval(void)
     rb_define_private_method(rb_cModule, "append_features", rb_mod_append_features, 1);
     rb_define_private_method(rb_cModule, "extend_object", rb_mod_extend_object, 1);
     rb_define_private_method(rb_cModule, "include", rb_mod_include, -1);
+    rb_define_private_method(rb_cModule, "import", rb_mod_import, 1);
+    rb_define_private_method(rb_cClassbox, "refine", rb_classbox_refine, 1);
 
     rb_undef_method(rb_cClass, "module_function");
 
@@ -1203,6 +1322,7 @@ Init_eval(void)
     rb_define_singleton_method(rb_vm_top_self(), "include", top_include, -1);
 
     rb_define_global_function("overlay_module", f_overlay_module, -1);
+    rb_define_global_function("import", f_import, 1);
 
     rb_define_method(rb_mKernel, "extend", rb_obj_extend, -1);
 
diff --git a/insns.def b/insns.def
index c04b215..0ce5d55 100644
--- a/insns.def
+++ b/insns.def
@@ -972,7 +972,7 @@ defineclass
 	    }
 	}
 	else {
-	    /* new module declaration */
+	    /* new classbox declaration */
 	    klass = rb_define_classbox_id(id);
 	    rb_set_class_path_string(klass, cbase, rb_id2str(id));
 	    rb_const_set(cbase, id, klass);
@@ -989,7 +989,7 @@ defineclass
 		  VM_FRAME_MAGIC_CLASS, klass, 0, (VALUE) GET_BLOCK_PTR(),
 		  class_iseq->iseq_encoded, GET_SP(), 0,
 		  class_iseq->local_size);
-    rb_mod_opened(klass);
+    vm_import_classboxes(class_iseq->cref_stack, klass, define_type);
     RESTORE_REGS();
 
     INC_VM_STATE_VERSION();
diff --git a/object.c b/object.c
index ba1a20b..e2ed9e8 100644
--- a/object.c
+++ b/object.c
@@ -2535,7 +2535,6 @@ Init_Object(void)
     rb_define_private_method(rb_cModule, "method_added", rb_obj_dummy, 1);
     rb_define_private_method(rb_cModule, "method_removed", rb_obj_dummy, 1);
     rb_define_private_method(rb_cModule, "method_undefined", rb_obj_dummy, 1);
-    rb_define_private_method(rb_cModule, "__opened__", rb_obj_dummy, 0);
 
     rb_define_method(rb_mKernel, "nil?", rb_false, 0);
     rb_define_method(rb_mKernel, "===", rb_equal, 1);
diff --git a/prelude.rb b/prelude.rb
index d0afbd0..04bf850 100644
--- a/prelude.rb
+++ b/prelude.rb
@@ -29,76 +29,3 @@ class Thread
     }
   end
 end
-
-class Classbox
-  def import_to(binding)
-    return unless @__overlayed_modules__
-    @__overlayed_modules__.each do |klass, modules|
-      modules.each do |mod|
-        overlay_module(klass, mod, binding)
-      end
-    end
-  end
-
-  private
-
-  @@__optimized_methods__ = [
-    :+, :-, :*, :/, :%, :==, :===, :<, :<=, :<<, :[], :[]=, :>, :>=, :!, :!=,
-    :length, :size, :succ
-  ]
-
-  def refine(klass, &block)
-    @__overlayed_modules__ ||= {}
-    mod = Module.new
-    modules = @__overlayed_modules__[klass] ||= []
-    modules.push(mod)
-    overlay_module(klass, mod, binding(1))
-    mod.singleton_class.send(:define_method, :method_added) do |mid|
-      if @@__optimized_methods__.include?(mid)
-        klass.send(:alias_method, :__original_optimized_method__, mid)
-        klass.send(:define_method, mid) {}
-        klass.send(:alias_method, mid, :__original_optimized_method__)
-        klass.send(:remove_method, :__original_optimized_method__)
-      end
-    end
-    mod.module_eval(&block)
-  end
-end
-
-def import(klassbox)
-  klassbox.import_to(binding(1))
-end
-
-class Module
-  def import(klassbox)
-    @__imported_classboxes__ ||= {}
-    @__imported_classboxes__[klassbox] = true
-    klassbox.import_to(binding(1))
-  end
-
-  def __opened__(b = binding(1))
-    return unless @__imported_classboxes__
-    @__imported_classboxes__.each_key do |klassbox|
-      klassbox.import_to(b)
-    end
-  end
-end
-
-class Class
-  def __opened__
-    unless @__imported_classboxes__
-      @__imported_classboxes__ =
-        self.superclass.instance_variable_get(:@__imported_classboxes__)
-      @__imported_classboxes__ &&= @__imported_classboxes__.dup
-    end
-    super(binding(1))
-  end
-end
-
-class Classbox
-  def __opened__
-    b = binding(1)
-    import_to(b)
-    super(b)
-  end
-end
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index bd1491e..f09fdeb 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -1732,3 +1732,43 @@ opt_eq_func(VALUE recv, VALUE obj, IC ic)
     return Qundef;
 }
 
+void rb_import_classbox(NODE *cref, VALUE classbox);
+
+static int
+vm_import_classbox_i(VALUE classbox, VALUE value, VALUE arg)
+{
+    NODE *cref = (NODE *) arg;
+
+    rb_import_classbox(cref, classbox);
+    return ST_CONTINUE;
+}
+
+static void
+vm_import_classboxes(NODE *cref, VALUE klass, int define_type)
+{
+    ID id_imported_classboxes;
+    VALUE imported_classboxes;
+
+    CONST_ID(id_imported_classboxes, "__imported_classboxes__");
+    imported_classboxes = rb_ivar_get(klass, id_imported_classboxes);
+    switch (define_type) {
+    case 0:
+	if (NIL_P(imported_classboxes)) {
+	    VALUE super = rb_class_real(RCLASS_SUPER(klass));
+	    imported_classboxes = rb_ivar_get(super, id_imported_classboxes);
+	    if (!NIL_P(imported_classboxes)) {
+		imported_classboxes = rb_hash_dup(imported_classboxes);
+		rb_ivar_set(klass, id_imported_classboxes, imported_classboxes);
+	    }
+	}
+	break;
+    case 3:
+	rb_import_classbox(cref, klass);
+	break;
+    }
+    if (!NIL_P(imported_classboxes)) {
+	rb_hash_foreach(imported_classboxes, vm_import_classbox_i,
+		       	(VALUE) cref);
+    }
+}
+
diff --git a/vm_method.c b/vm_method.c
index 63bbc51..d5ebf75 100644
--- a/vm_method.c
+++ b/vm_method.c
@@ -1347,6 +1347,20 @@ obj_respond_to_missing(VALUE obj, VALUE priv)
 }
 
 void
+rb_redefine_opt_method(VALUE klass, ID mid)
+{
+    st_data_t key, data;
+    rb_method_entry_t *me = 0;
+
+    if (!st_lookup(RCLASS_M_TBL(klass), mid, &data) ||
+	!(me = (rb_method_entry_t *)data) ||
+	(!me->def || me->def->type == VM_METHOD_TYPE_UNDEF)) {
+	return;
+    }
+    rb_vm_check_redefinition_opt_method(me);
+}
+
+void
 Init_eval_method(void)
 {
 #undef rb_intern
-- 
1.7.0.4

