*** empty log message ***
[bpt/guile.git] / libguile / goops.c
index 7ff530d..02c18ba 100644 (file)
@@ -1,43 +1,19 @@
-/* Copyright (C) 1998,1999,2000,2001 Free Software Foundation, Inc.
+/* Copyright (C) 1998,1999,2000,2001, 2002, 2003 Free Software Foundation, Inc.
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
  *
- * This program is distributed in the hope that it will be useful,
+ * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with this software; see the file COPYING.  If not, write to
- * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- * Boston, MA 02111-1307 USA
- *
- * As a special exception, the Free Software Foundation gives permission
- * for additional uses of the text contained in its release of GUILE.
- *
- * The exception is that, if you link the GUILE library with other files
- * to produce an executable, this does not by itself cause the
- * resulting executable to be covered by the GNU General Public License.
- * Your use of that executable is in no way restricted on account of
- * linking the GUILE library code into it.
- *
- * This exception does not however invalidate any other reasons why
- * the executable file might be covered by the GNU General Public License.
- *
- * This exception applies only to the code released by the
- * Free Software Foundation under the name GUILE.  If you copy
- * code from other Free Software Foundation releases into a copy of
- * GUILE, as the General Public License permits, the exception does
- * not apply to the code that you add in this way.  To avoid misleading
- * anyone as to the status of such modified files, you must delete
- * this exception notice from them.
- *
- * If you write modifications of your own for GUILE, it is your choice
- * whether to permit this exception to apply to your modifications.
- * If you do not wish that, delete this exception notice.  */
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
 \f
 
 /* This software is a derivative work of other copyrighted softwares; the
        {                                                                     \
          class = SCM_CLASS_OF (obj);                                         \
           if (SCM_OBJ_CLASS_REDEF (obj) != SCM_BOOL_F)                               \
-           CALL_GF3 ("change-object-class",                                  \
-                     obj, class, SCM_OBJ_CLASS_REDEF (obj));                 \
+           scm_change_object_class (obj, class, SCM_OBJ_CLASS_REDEF (obj));  \
        }
 
 #define NXT_MTHD_METHODS(m)    (SCM_VELTS (m)[1])
@@ -136,9 +111,14 @@ static SCM scm_goops_lookup_closure;
 
 /* Some classes are defined in libguile/objects.c. */
 SCM scm_class_top, scm_class_object, scm_class_class;
+SCM scm_class_applicable;
 SCM scm_class_entity, scm_class_entity_with_setter;
-SCM scm_class_generic, scm_class_generic_with_setter, scm_class_method;
-SCM scm_class_simple_method, scm_class_accessor;
+SCM scm_class_generic, scm_class_generic_with_setter;
+SCM scm_class_accessor;
+SCM scm_class_extended_generic, scm_class_extended_generic_with_setter;
+SCM scm_class_extended_accessor;
+SCM scm_class_method;
+SCM scm_class_simple_method, scm_class_accessor_method;
 SCM scm_class_procedure_class;
 SCM scm_class_operator_class, scm_class_operator_with_setter_class;
 SCM scm_class_entity_class;
@@ -166,22 +146,11 @@ static SCM scm_sys_goops_loaded (void);
  *
  * Compute-cpl
  *
- *   This version doesn't handle multiple-inheritance. It serves only for
- * booting classes and will be overloaded in Scheme
+ *   This version doesn't fully handle multiple-inheritance. It serves
+ *   only for booting classes and will be overloaded in Scheme
  *
  ******************************************************************************/
 
-#if 0
-static SCM
-compute_cpl (SCM supers, SCM res)
-{
-  return (SCM_NULLP (supers)
-         ? scm_reverse (res)
-         : compute_cpl (SCM_SLOT (SCM_CAR (supers), scm_si_direct_supers),
-                        scm_cons (SCM_CAR (supers), res)));
-}
-#endif
-
 static SCM
 map (SCM (*proc) (SCM), SCM ls)
 {
@@ -325,7 +294,9 @@ compute_getters_n_setters (SCM slots)
        {
          init = scm_get_keyword (k_init_value, options, 0);
          if (init)
-           init = scm_closure (scm_list_2 (SCM_EOL, init), SCM_EOL);
+           init = scm_closure (scm_list_2 (SCM_EOL,
+                                           scm_list_2 (scm_sym_quote, init)),
+                               SCM_EOL);
          else
            init = scm_get_keyword (k_init_thunk, options, SCM_BOOL_F);
        }
@@ -471,20 +442,39 @@ SCM_DEFINE (scm_sys_initialize_object, "%initialize-object", 2, 0, 0,
 }
 #undef FUNC_NAME
 
+/* NOTE: The following macros are interdependent with code
+ *       in goops.scm:compute-getters-n-setters
+ */
+#define SCM_GNS_INSTANCE_ALLOCATED_P(gns)      \
+  (SCM_INUMP (SCM_CDDR (gns))                  \
+   || (SCM_CONSP (SCM_CDDR (gns))              \
+       && SCM_CONSP (SCM_CDDDR (gns))          \
+       && SCM_CONSP (SCM_CDDDDR (gns))))
+#define SCM_GNS_INDEX(gns)                     \
+  (SCM_INUMP (SCM_CDDR (gns))                  \
+   ? SCM_INUM (SCM_CDDR (gns))                 \
+   : SCM_INUM (SCM_CAR (SCM_CDDDDR (gns))))
+#define SCM_GNS_SIZE(gns)                      \
+  (SCM_INUMP (SCM_CDDR (gns))                  \
+   ? 1                                         \
+   : SCM_INUM (SCM_CADR (SCM_CDDDDR (gns))))
 
 SCM_KEYWORD (k_class, "class");
+SCM_KEYWORD (k_allocation, "allocation");
+SCM_KEYWORD (k_instance, "instance");
 
 SCM_DEFINE (scm_sys_prep_layout_x, "%prep-layout!", 1, 0, 0,
            (SCM class),
            "")
 #define FUNC_NAME s_scm_sys_prep_layout_x
 {
-  SCM slots, nfields;
+  SCM slots, getters_n_setters, nfields;
   unsigned long int n, i;
   char *s;
 
   SCM_VALIDATE_INSTANCE (1, class);
   slots = SCM_SLOT (class, scm_si_slots);
+  getters_n_setters = SCM_SLOT (class, scm_si_getters_n_setters);
   nfields = SCM_SLOT (class, scm_si_nfields);
   if (!SCM_INUMP (nfields) || SCM_INUM (nfields) < 0)
     SCM_MISC_ERROR ("bad value in nfields slot: ~S",
@@ -496,51 +486,79 @@ SCM_DEFINE (scm_sys_prep_layout_x, "%prep-layout!", 1, 0, 0,
                    scm_list_1 (nfields));
 
   s = n > 0 ? scm_malloc (n) : 0;
-  for (i = 0; i < n; i += 2)
+  i = 0;
+  while (SCM_CONSP (getters_n_setters))
     {
-      long len;
-      SCM type;
-      char p, a;
-
-      if (!SCM_CONSP (slots))
-       SCM_MISC_ERROR ("too few slot definitions", SCM_EOL);
-      len = scm_ilength (SCM_CDAR (slots));
-      type = scm_i_get_keyword (k_class, SCM_CDAR (slots), len, SCM_BOOL_F,
-                               FUNC_NAME);
-      if (SCM_FALSEP (type))
-       {
-         p = 'p';
-         a = 'w';
-       }
-      else
+      if (SCM_GNS_INSTANCE_ALLOCATED_P (SCM_CAR (getters_n_setters)))
        {
-         if (!SCM_CLASSP (type))
-           SCM_MISC_ERROR ("bad slot class", SCM_EOL);
-         else if (SCM_SUBCLASSP (type, scm_class_foreign_slot))
+         SCM type;
+         int len, index, size;
+         char p, a;
+
+         if (i >= n || !SCM_CONSP (slots))
+           goto inconsistent;
+         
+         /* extract slot type */
+         len = scm_ilength (SCM_CDAR (slots));
+         type = scm_i_get_keyword (k_class, SCM_CDAR (slots),
+                                   len, SCM_BOOL_F, FUNC_NAME);
+         /* determine slot GC protection and access mode */
+         if (SCM_FALSEP (type))
            {
-             if (SCM_SUBCLASSP (type, scm_class_self))
-               p = 's';
-             else if (SCM_SUBCLASSP (type, scm_class_protected))
-               p = 'p';
-             else
-               p = 'u';
-
-             if (SCM_SUBCLASSP (type, scm_class_opaque))
-               a = 'o';
-             else if (SCM_SUBCLASSP (type, scm_class_read_only))
-               a = 'r';
-             else
-               a = 'w';
+             p = 'p';
+             a = 'w';
            }
          else
            {
-             p = 'p';
-             a = 'w';
+             if (!SCM_CLASSP (type))
+               {
+                 if (s)
+                   free (s);
+                 SCM_MISC_ERROR ("bad slot class", SCM_EOL);
+               }
+             else if (SCM_SUBCLASSP (type, scm_class_foreign_slot))
+               {
+                 if (SCM_SUBCLASSP (type, scm_class_self))
+                   p = 's';
+                 else if (SCM_SUBCLASSP (type, scm_class_protected))
+                   p = 'p';
+                 else
+                   p = 'u';
+
+                 if (SCM_SUBCLASSP (type, scm_class_opaque))
+                   a = 'o';
+                 else if (SCM_SUBCLASSP (type, scm_class_read_only))
+                   a = 'r';
+                 else
+                   a = 'w';
+               }
+             else
+               {
+                 p = 'p';
+                 a = 'w';
+               }
+           }
+      
+         index = SCM_GNS_INDEX (SCM_CAR (getters_n_setters));
+         if (index != (i >> 1))
+           goto inconsistent;
+         size = SCM_GNS_SIZE (SCM_CAR (getters_n_setters));
+         while (size)
+           {
+             s[i++] = p;
+             s[i++] = a;
+             --size;
            }
        }
-      s[i] = p;
-      s[i + 1] = a;
       slots = SCM_CDR (slots);
+      getters_n_setters = SCM_CDR (getters_n_setters);
+    }
+  if (!SCM_NULLP (slots))
+    {
+    inconsistent:
+      if (s)
+       free (s);
+      SCM_MISC_ERROR ("inconsistent getters-n-setters", SCM_EOL);
     }
   SCM_SET_SLOT (class, scm_si_layout, scm_mem2symbol (s, n));
   if (s)
@@ -600,7 +618,7 @@ SCM_DEFINE (scm_sys_inherit_magic_x, "%inherit-magic!", 2, 0, 0,
 }
 #undef FUNC_NAME
 
-void
+static void
 prep_hashsets (SCM class)
 {
   unsigned int i;
@@ -620,9 +638,6 @@ scm_basic_basic_make_class (SCM class, SCM name, SCM dsupers, SCM dslots)
   z = scm_make_struct (class, SCM_INUM0, SCM_EOL);
 
   /* Initialize its slots */
-#if 0
-  cpl   = compute_cpl (dsupers, scm_list_1 (z));
-#endif
   SCM_SET_SLOT (z, scm_si_direct_supers, dsupers);
   cpl   = compute_cpl (z);
   slots = build_slots_list (maplist (dslots), cpl);
@@ -900,17 +915,54 @@ SCM_DEFINE (scm_generic_function_name, "generic-function-name", 1, 0, 0,
 }
 #undef FUNC_NAME
 
+SCM_SYMBOL (sym_methods, "methods");
+SCM_SYMBOL (sym_extended_by, "extended-by");
+SCM_SYMBOL (sym_extends, "extends");
+
+static
+SCM fold_downward_gf_methods (SCM method_lists, SCM gf)
+{
+  SCM gfs = scm_slot_ref (gf, sym_extended_by);
+  method_lists = scm_cons (scm_slot_ref (gf, sym_methods), method_lists);
+  while (!SCM_NULLP (gfs))
+    {
+      method_lists = fold_downward_gf_methods (method_lists, SCM_CAR (gfs));
+      gfs = SCM_CDR (gfs);
+    }
+  return method_lists;
+}
+
+static
+SCM fold_upward_gf_methods (SCM method_lists, SCM gf)
+{
+  if (SCM_IS_A_P (gf, scm_class_extended_generic))
+    {
+      SCM gfs = scm_slot_ref (gf, sym_extends);
+      while (!SCM_NULLP (gfs))
+       {
+         SCM methods = scm_slot_ref (SCM_CAR (gfs), sym_methods);
+         method_lists = fold_upward_gf_methods (scm_cons (methods,
+                                                          method_lists),
+                                                SCM_CAR (gfs));
+         gfs = SCM_CDR (gfs);
+       }
+    }
+  return method_lists;
+}
+
 SCM_DEFINE (scm_generic_function_methods, "generic-function-methods", 1, 0, 0,
            (SCM obj),
            "Return the methods of the generic function @var{obj}.")
 #define FUNC_NAME s_scm_generic_function_methods
 {
+  SCM methods;
   SCM_VALIDATE_GENERIC (1, obj);
-  return scm_slot_ref (obj, scm_str2symbol ("methods"));
+  methods = fold_upward_gf_methods (SCM_EOL, obj);
+  methods = fold_downward_gf_methods (methods, obj);
+  return scm_append (methods);
 }
 #undef FUNC_NAME
 
-
 SCM_DEFINE (scm_method_generic_function, "method-generic-function", 1, 0, 0,
            (SCM obj),
            "Return the generic function for the method @var{obj}.")
@@ -1022,7 +1074,7 @@ SCM_DEFINE (scm_sys_fast_slot_ref, "%fast-slot-ref", 2, 0, 0,
   i = SCM_INUM (index);
   SCM_ASSERT_RANGE (2, index, i < SCM_NUMBER_OF_SLOTS (obj));
 
-  return scm_at_assert_bound_ref (obj, index);
+  return SCM_SLOT (obj, i);
 }
 #undef FUNC_NAME
 
@@ -1477,9 +1529,7 @@ SCM_DEFINE (scm_sys_invalidate_class, "%invalidate-class", 1, 0, 0,
 static scm_t_bits **hell;
 static long n_hell = 1;                /* one place for the evil one himself */
 static long hell_size = 4;
-#ifdef USE_THREADS
-static scm_t_mutex hell_mutex;
-#endif
+static SCM hell_mutex;
 
 static long
 burnin (SCM o)
@@ -1495,9 +1545,7 @@ static void
 go_to_hell (void *o)
 {
   SCM obj = SCM_PACK ((scm_t_bits) o);
-#ifdef USE_THREADS
-  scm_mutex_lock (&hell_mutex);
-#endif
+  scm_lock_mutex (hell_mutex);
   if (n_hell == hell_size)
     {
       long new_size = 2 * hell_size;
@@ -1505,21 +1553,15 @@ go_to_hell (void *o)
       hell_size = new_size;
     }
   hell[n_hell++] = SCM_STRUCT_DATA (obj);
-#ifdef USE_THREADS
-  scm_mutex_unlock (&hell_mutex);
-#endif
+  scm_unlock_mutex (hell_mutex);
 }
 
 static void
 go_to_heaven (void *o)
 {
-#ifdef USE_THREADS
-  scm_mutex_lock (&hell_mutex);
-#endif
+  scm_lock_mutex (hell_mutex);
   hell[burnin (SCM_PACK ((scm_t_bits) o))] = hell[--n_hell];
-#ifdef USE_THREADS
-  scm_mutex_unlock (&hell_mutex);
-#endif
+  scm_unlock_mutex (hell_mutex);
 }
 
 
@@ -1532,6 +1574,10 @@ purgatory (void *args)
                      SCM_PACK ((scm_t_bits) args));
 }
 
+/* This function calls the generic function change-class for all
+ * instances which aren't currently undergoing class change.
+ */
+
 void
 scm_change_object_class (SCM obj, SCM old_class SCM_UNUSED, SCM new_class)
 {
@@ -1563,7 +1609,7 @@ SCM_SYMBOL (sym_no_method, "no-method");
 
 static SCM list_of_no_method;
 
-SCM_SYMBOL (scm_sym_args, "args");
+SCM_GLOBAL_SYMBOL (scm_sym_args, "args");
 
 SCM
 scm_make_method_cache (SCM gf)
@@ -1651,14 +1697,67 @@ SCM_DEFINE (scm_primitive_generic_generic, "primitive-generic-generic", 1, 0, 0,
 {
   if (scm_subr_p (subr) && SCM_SUBR_GENERIC (subr))
     {
-      SCM gf = *SCM_SUBR_GENERIC (subr);
-      if (gf)
-       return gf;
+      if (!*SCM_SUBR_GENERIC (subr))
+       scm_enable_primitive_generic_x (scm_list_1 (subr));
+      return *SCM_SUBR_GENERIC (subr);
     }
   SCM_WRONG_TYPE_ARG (SCM_ARG1, subr);
 }
 #undef FUNC_NAME
 
+typedef struct t_extension {
+  struct t_extension *next;
+  SCM extended;
+  SCM extension;
+} t_extension;
+
+static t_extension *extensions = 0;
+
+SCM_VARIABLE (scm_var_make_extended_generic, "make-extended-generic");
+
+void
+scm_c_extend_primitive_generic (SCM extended, SCM extension)
+{
+  if (goops_loaded_p)
+    {
+      SCM gf, gext;
+      if (!*SCM_SUBR_GENERIC (extended))
+       scm_enable_primitive_generic_x (scm_list_1 (extended));
+      gf = *SCM_SUBR_GENERIC (extended);
+      gext = scm_call_2 (SCM_VARIABLE_REF (scm_var_make_extended_generic),
+                        gf,
+                        SCM_SNAME (extension));
+      *SCM_SUBR_GENERIC (extension) = gext;
+    }
+  else
+    {
+      t_extension *e = scm_malloc (sizeof (t_extension));
+      t_extension **loc = &extensions;
+      /* Make sure that extensions are placed before their own
+       * extensions in the extensions list.  O(N^2) algorithm, but
+       * extensions of primitive generics are rare.
+       */
+      while (*loc && extension != (*loc)->extended)
+       loc = &(*loc)->next;
+      e->next = *loc;
+      e->extended = extended;
+      e->extension = extension;
+      *loc = e;
+    }
+}
+
+static void
+setup_extended_primitive_generics ()
+{
+  while (extensions)
+    {
+      t_extension *e = extensions;
+      scm_c_extend_primitive_generic (e->extended, e->extension);
+      extensions = e->next;
+      free (e);
+    }
+}
+
 /******************************************************************************
  *
  * Protocol for calling a generic fumction
@@ -1767,7 +1866,7 @@ sort_applicable_methods (SCM method_list, long size, SCM const *targs)
        We're not allocating elements in this routine, so this should
        pose no problem.
       */
-      v      = SCM_WRITABLE_VELTS (vector);
+      v = SCM_WRITABLE_VELTS (vector);
     }
 
   /* Use a simple shell sort since it is generally faster than qsort on
@@ -1839,7 +1938,7 @@ scm_compute_applicable_methods (SCM gf, SCM args, long len, int find_method_p)
     *p++ = scm_class_of (SCM_CAR (args));
   
   /* Build a list of all applicable methods */
-  for (l = SCM_SLOT (gf, scm_si_methods); !SCM_NULLP (l); l = SCM_CDR (l))
+  for (l = scm_generic_function_methods (gf); !SCM_NULLP (l); l = SCM_CDR (l))
     {
       fl = SPEC_OF (SCM_CAR (l));
       /* Only accept accessors which match exactly in first arg. */
@@ -1872,7 +1971,7 @@ scm_compute_applicable_methods (SCM gf, SCM args, long len, int find_method_p)
       return SCM_BOOL_F;
     }
 
-  scm_remember_upto_here (tmp);
+  scm_remember_upto_here_1 (tmp);
   return (count == 1
          ? applicable
          : sort_applicable_methods (applicable, count, types));
@@ -1955,7 +2054,6 @@ scm_m_atdispatch (SCM xorig, SCM env)
 #undef FUNC_NAME
 
 
-#ifdef USE_THREADS
 static void
 lock_cache_mutex (void *m)
 {
@@ -1969,7 +2067,6 @@ unlock_cache_mutex (void *m)
   SCM mutex = SCM_PACK ((scm_t_bits) m);
   scm_unlock_mutex (mutex);
 }
-#endif
 
 static SCM
 call_memoize_method (void *a)
@@ -1991,16 +2088,12 @@ SCM
 scm_memoize_method (SCM x, SCM args)
 {
   SCM gf = SCM_CAR (scm_last_pair (x));
-#ifdef USE_THREADS
   return scm_internal_dynamic_wind (
     lock_cache_mutex,
     call_memoize_method,
     unlock_cache_mutex,
     (void *) SCM_UNPACK (scm_cons2 (gf, x, args)),
     (void *) SCM_UNPACK (SCM_SLOT (gf, scm_si_cache_mutex)));
-#else
-  return call_memoize_method ((void *) SCM_UNPACK (scm_cons2 (gf, x, args)));
-#endif
 }
 
 /******************************************************************************
@@ -2035,24 +2128,20 @@ SCM_DEFINE (scm_make, "make",  0, 0, 1,
   class = SCM_CAR(args);
   args  = SCM_CDR(args);
 
-  if (class == scm_class_generic || class == scm_class_generic_with_setter)
+  if (class == scm_class_generic || class == scm_class_accessor)
     {
-#ifdef USE_THREADS
       z = scm_make_struct (class, SCM_INUM0,
-                          scm_list_4 (SCM_EOL,
+                          scm_list_5 (SCM_EOL,
                                       SCM_INUM0,
                                       SCM_BOOL_F,
-                                      scm_make_mutex ()));
-#else
-      z = scm_make_struct (class, SCM_INUM0,
-                          scm_list_3 (SCM_EOL, SCM_INUM0, SCM_BOOL_F));
-#endif
+                                      scm_make_mutex (),
+                                      SCM_EOL));
       scm_set_procedure_property_x (z, scm_sym_name,
                                    scm_get_keyword (k_name,
                                                     args,
                                                     SCM_BOOL_F));
       clear_method_cache (z);
-      if (class == scm_class_generic_with_setter)
+      if (class == scm_class_accessor)
        {
          SCM setter = scm_get_keyword (k_setter, args, SCM_BOOL_F);
          if (!SCM_FALSEP (setter))
@@ -2065,7 +2154,7 @@ SCM_DEFINE (scm_make, "make",  0, 0, 1,
 
       if (class == scm_class_method
          || class == scm_class_simple_method
-         || class == scm_class_accessor)
+         || class == scm_class_accessor_method)
        {
          SCM_SET_SLOT (z, scm_si_generic_function,
            scm_i_get_keyword (k_gf,
@@ -2165,6 +2254,26 @@ SCM_DEFINE (scm_sys_method_more_specific_p, "%method-more-specific?", 3, 0, 0,
  *
  ******************************************************************************/
 
+static void
+fix_cpl (SCM c, SCM before, SCM after)
+{
+  SCM cpl = SCM_SLOT (c, scm_si_cpl);
+  SCM ls = scm_c_memq (after, cpl);
+  SCM tail = scm_delq1_x (before, SCM_CDR (ls));
+  if (SCM_FALSEP (ls))
+    /* if this condition occurs, fix_cpl should not be applied this way */
+    abort ();
+  SCM_SETCAR (ls, before);
+  SCM_SETCDR (ls, scm_cons (after, tail));
+  {
+    SCM dslots = SCM_SLOT (c, scm_si_direct_slots);
+    SCM slots = build_slots_list (maplist (dslots), cpl);
+    SCM g_n_s = compute_getters_n_setters (slots);
+    SCM_SET_SLOT (c, scm_si_slots, slots);
+    SCM_SET_SLOT (c, scm_si_getters_n_setters, g_n_s);
+  }
+}
+
 
 static void
 make_stdcls (SCM *var, char *name, SCM meta, SCM super, SCM slots)
@@ -2194,12 +2303,8 @@ create_standard_classes (void)
   SCM amethod_slots = scm_list_1 (scm_list_3 (scm_str2symbol ("slot-definition"),
                                              k_init_keyword,
                                              k_slot_definition));
-#ifdef USE_THREADS
   SCM mutex_slot = scm_list_1 (scm_str2symbol ("make-mutex"));
-#else
-  SCM mutex_slot = SCM_BOOL_F;
-#endif
-  SCM gf_slots = scm_list_4 (scm_str2symbol ("methods"),
+  SCM gf_slots = scm_list_5 (scm_str2symbol ("methods"),
                             scm_list_3 (scm_str2symbol ("n-specialized"),
                                         k_init_value,
                                         SCM_INUM0),
@@ -2210,8 +2315,13 @@ create_standard_classes (void)
                                         k_init_thunk,
                                         scm_closure (scm_list_2 (SCM_EOL,
                                                                  mutex_slot),
-                                                     SCM_EOL)));
-
+                                                     SCM_EOL)),
+                            scm_list_3 (scm_str2symbol ("extended-by"),
+                                        k_init_value,
+                                        SCM_EOL));
+  SCM egf_slots = scm_list_1 (scm_list_3 (scm_str2symbol ("extends"),
+                                         k_init_value,
+                                         SCM_EOL));
   /* Foreign class slot classes */
   make_stdcls (&scm_class_foreign_slot,           "<foreign-slot>",
               scm_class_class, scm_class_top,             SCM_EOL);
@@ -2223,7 +2333,7 @@ create_standard_classes (void)
               scm_class_class, scm_class_foreign_slot,    SCM_EOL);
   make_stdcls (&scm_class_self,                   "<self-slot>",
               scm_class_class,
-              scm_list_2 (scm_class_foreign_slot, scm_class_read_only),
+              scm_class_read_only,
               SCM_EOL);
   make_stdcls (&scm_class_protected_opaque, "<protected-opaque-slot>",
               scm_class_class,
@@ -2277,30 +2387,47 @@ create_standard_classes (void)
   make_stdcls (&scm_class_simple_method,   "<simple-method>",
               scm_class_class, scm_class_method,          SCM_EOL);
   SCM_SET_CLASS_FLAGS (scm_class_simple_method, SCM_CLASSF_SIMPLE_METHOD);
-  make_stdcls (&scm_class_accessor,       "<accessor-method>",
+  make_stdcls (&scm_class_accessor_method, "<accessor-method>",
               scm_class_class, scm_class_simple_method,   amethod_slots);
-  SCM_SET_CLASS_FLAGS (scm_class_accessor, SCM_CLASSF_ACCESSOR_METHOD);
+  SCM_SET_CLASS_FLAGS (scm_class_accessor_method, SCM_CLASSF_ACCESSOR_METHOD);
+  make_stdcls (&scm_class_applicable,     "<applicable>",
+              scm_class_class, scm_class_top, SCM_EOL);
   make_stdcls (&scm_class_entity,         "<entity>",
-              scm_class_entity_class, scm_class_object,   SCM_EOL);
+              scm_class_entity_class,
+              scm_list_2 (scm_class_object, scm_class_applicable),
+              SCM_EOL);
   make_stdcls (&scm_class_entity_with_setter, "<entity-with-setter>",
               scm_class_entity_class, scm_class_entity,   SCM_EOL);
   make_stdcls (&scm_class_generic,        "<generic>",
               scm_class_entity_class, scm_class_entity,   gf_slots);
   SCM_SET_CLASS_FLAGS (scm_class_generic, SCM_CLASSF_PURE_GENERIC);
+  make_stdcls (&scm_class_extended_generic, "<extended-generic>",
+              scm_class_entity_class, scm_class_generic, egf_slots);
+  SCM_SET_CLASS_FLAGS (scm_class_extended_generic, SCM_CLASSF_PURE_GENERIC);
   make_stdcls (&scm_class_generic_with_setter, "<generic-with-setter>",
               scm_class_entity_class,
               scm_list_2 (scm_class_generic, scm_class_entity_with_setter),
               SCM_EOL);
-#if 0
-  /* Patch cpl since compute_cpl doesn't support multiple inheritance. */
-  SCM_SET_SLOT (scm_class_generic_with_setter, scm_si_cpl,
-    scm_append (scm_list_3 (scm_list_2 (scm_class_generic_with_setter,
-                                       scm_class_generic),
-                           SCM_SLOT (scm_class_entity_with_setter,
-                                     scm_si_cpl),
-                           SCM_EOL)));
-#endif
   SCM_SET_CLASS_FLAGS (scm_class_generic_with_setter, SCM_CLASSF_PURE_GENERIC);
+  make_stdcls (&scm_class_accessor,       "<accessor>",
+              scm_class_entity_class, scm_class_generic_with_setter, SCM_EOL);
+  SCM_SET_CLASS_FLAGS (scm_class_accessor, SCM_CLASSF_PURE_GENERIC);
+  make_stdcls (&scm_class_extended_generic_with_setter,
+              "<extended-generic-with-setter>",
+              scm_class_entity_class,
+              scm_list_2 (scm_class_generic_with_setter,
+                          scm_class_extended_generic),
+              SCM_EOL);
+  SCM_SET_CLASS_FLAGS (scm_class_extended_generic_with_setter,
+                      SCM_CLASSF_PURE_GENERIC);
+  make_stdcls (&scm_class_extended_accessor, "<extended-accessor>",
+              scm_class_entity_class,
+              scm_list_2 (scm_class_accessor,
+                          scm_class_extended_generic_with_setter),
+              SCM_EOL);
+  fix_cpl (scm_class_extended_accessor,
+          scm_class_extended_generic, scm_class_generic);
+  SCM_SET_CLASS_FLAGS (scm_class_extended_accessor, SCM_CLASSF_PURE_GENERIC);
 
   /* Primitive types classes */
   make_stdcls (&scm_class_boolean,        "<boolean>",
@@ -2332,7 +2459,7 @@ create_standard_classes (void)
   make_stdcls (&scm_class_unknown,        "<unknown>",
               scm_class_class, scm_class_top,             SCM_EOL);
   make_stdcls (&scm_class_procedure,      "<procedure>",
-              scm_class_procedure_class, scm_class_top,   SCM_EOL);
+              scm_class_procedure_class, scm_class_applicable, SCM_EOL);
   make_stdcls (&scm_class_procedure_with_setter, "<procedure-with-setter>",
               scm_class_procedure_class, scm_class_procedure, SCM_EOL);
   make_stdcls (&scm_class_primitive_generic, "<primitive-generic>",
@@ -2356,7 +2483,7 @@ create_standard_classes (void)
  **********************************************************************/
 
 static SCM
-make_class_from_template (char *template, char *type_name, SCM supers)
+make_class_from_template (char *template, char *type_name, SCM supers, int applicablep)
 {
   SCM class, name;
   if (type_name)
@@ -2368,7 +2495,9 @@ make_class_from_template (char *template, char *type_name, SCM supers)
   else
     name = SCM_GOOPS_UNBOUND;
 
-  class = scm_permanent_object (scm_basic_make_class (scm_class_class,
+  class = scm_permanent_object (scm_basic_make_class (applicablep
+                                                     ? scm_class_procedure_class
+                                                     : scm_class_class,
                                                      name,
                                                      supers,
                                                      SCM_EOL));
@@ -2381,11 +2510,49 @@ make_class_from_template (char *template, char *type_name, SCM supers)
 }
 
 SCM
-scm_make_extended_class (char *type_name)
+scm_make_extended_class (char *type_name, int applicablep)
 {
   return make_class_from_template ("<%s>",
                                   type_name,
-                                  scm_list_1 (scm_class_top));
+                                  scm_list_1 (applicablep
+                                              ? scm_class_applicable
+                                              : scm_class_top),
+                                  applicablep);
+}
+
+void
+scm_i_inherit_applicable (SCM c)
+{
+  if (!SCM_SUBCLASSP (c, scm_class_applicable))
+    {
+      SCM dsupers = SCM_SLOT (c, scm_si_direct_supers);
+      SCM cpl = SCM_SLOT (c, scm_si_cpl);
+      /* patch scm_class_applicable into direct-supers */
+      SCM top = scm_c_memq (scm_class_top, dsupers);
+      if (SCM_FALSEP (top))
+       dsupers = scm_append (scm_list_2 (dsupers,
+                                         scm_list_1 (scm_class_applicable)));
+      else
+       {
+         SCM_SETCAR (top, scm_class_applicable);
+         SCM_SETCDR (top, scm_cons (scm_class_top, SCM_CDR (top)));
+       }
+      SCM_SET_SLOT (c, scm_si_direct_supers, dsupers);
+      /* patch scm_class_applicable into cpl */
+      top = scm_c_memq (scm_class_top, cpl);
+      if (SCM_FALSEP (top))
+       abort ();
+      else
+       {
+         SCM_SETCAR (top, scm_class_applicable);
+         SCM_SETCDR (top, scm_cons (scm_class_top, SCM_CDR (top)));
+       }
+      /* add class to direct-subclasses of scm_class_applicable */
+      SCM_SET_SLOT (scm_class_applicable,
+                   scm_si_direct_subclasses,
+                   scm_cons (c, SCM_SLOT (scm_class_applicable,
+                                          scm_si_direct_subclasses)));
+    }
 }
 
 static void
@@ -2393,7 +2560,7 @@ create_smob_classes (void)
 {
   long i;
 
-  scm_smob_class = (SCM *) malloc (255 * sizeof (SCM));
+  scm_smob_class = (SCM *) scm_malloc (255 * sizeof (SCM));
   for (i = 0; i < 255; ++i)
     scm_smob_class[i] = 0;
 
@@ -2404,7 +2571,8 @@ create_smob_classes (void)
 
   for (i = 0; i < scm_numsmob; ++i)
     if (!scm_smob_class[i])
-      scm_smob_class[i] = scm_make_extended_class (SCM_SMOBNAME (i));
+      scm_smob_class[i] = scm_make_extended_class (SCM_SMOBNAME (i),
+                                                  scm_smobs[i].apply != 0);
 }
 
 void
@@ -2412,20 +2580,24 @@ scm_make_port_classes (long ptobnum, char *type_name)
 {
   SCM c, class = make_class_from_template ("<%s-port>",
                                           type_name,
-                                          scm_list_1 (scm_class_port));
+                                          scm_list_1 (scm_class_port),
+                                          0);
   scm_port_class[SCM_IN_PCLASS_INDEX + ptobnum]
     = make_class_from_template ("<%s-input-port>",
                                type_name,
-                               scm_list_2 (class, scm_class_input_port));
+                               scm_list_2 (class, scm_class_input_port),
+                               0);
   scm_port_class[SCM_OUT_PCLASS_INDEX + ptobnum]
     = make_class_from_template ("<%s-output-port>",
                                type_name,
-                               scm_list_2 (class, scm_class_output_port));
+                               scm_list_2 (class, scm_class_output_port),
+                               0);
   scm_port_class[SCM_INOUT_PCLASS_INDEX + ptobnum]
     = c
     = make_class_from_template ("<%s-input-output-port>",
                                type_name,
-                               scm_list_2 (class, scm_class_input_output_port));
+                               scm_list_2 (class, scm_class_input_output_port),
+                               0);
   /* Patch cpl (since this tree is too complex for the C level compute-cpl) */
   SCM_SET_SLOT (c, scm_si_cpl,
                scm_cons2 (c, class, SCM_SLOT (scm_class_input_output_port, scm_si_cpl)));
@@ -2436,7 +2608,7 @@ create_port_classes (void)
 {
   long i;
 
-  scm_port_class = (SCM *) malloc (3 * 256 * sizeof (SCM));
+  scm_port_class = (SCM *) scm_malloc (3 * 256 * sizeof (SCM));
   for (i = 0; i < 3 * 256; ++i)
     scm_port_class[i] = 0;
 
@@ -2445,13 +2617,14 @@ create_port_classes (void)
 }
 
 static SCM
-make_struct_class (void *closure SCM_UNUSED, SCM key SCM_UNUSED,
-                  SCM data, SCM prev SCM_UNUSED)
+make_struct_class (void *closure SCM_UNUSED,
+                  SCM vtable, SCM data, SCM prev SCM_UNUSED)
 {
   if (!SCM_FALSEP (SCM_STRUCT_TABLE_NAME (data)))
     SCM_SET_STRUCT_TABLE_CLASS (data,
                                scm_make_extended_class
-                               (SCM_SYMBOL_CHARS (SCM_STRUCT_TABLE_NAME (data))));
+                               (SCM_SYMBOL_CHARS (SCM_STRUCT_TABLE_NAME (data)),
+                                SCM_CLASS_FLAGS (vtable) & SCM_CLASSF_OPERATOR));
   return SCM_UNSPECIFIED;
 }
 
@@ -2563,15 +2736,13 @@ scm_add_slot (SCM class, char *slot_name, SCM slot_class,
                             slot_class,
                             setter ? k_accessor : k_getter,
                             gf);
-      SCM gns = scm_list_4 (name, SCM_BOOL_F, get, set);
-
-      scm_add_method (gf, scm_make (scm_list_5 (scm_class_accessor,
+      scm_add_method (gf, scm_make (scm_list_5 (scm_class_accessor_method,
                                                k_specializers,
                                                scm_list_1 (class),
                                                k_procedure,
                                                getm)));
       scm_add_method (scm_setter (gf),
-                     scm_make (scm_list_5 (scm_class_accessor,
+                     scm_make (scm_list_5 (scm_class_accessor_method,
                                            k_specializers,
                                            scm_list_2 (class, scm_class_top),
                                            k_procedure,
@@ -2581,16 +2752,16 @@ scm_add_slot (SCM class, char *slot_name, SCM slot_class,
       SCM_SET_SLOT (class, scm_si_slots,
                    scm_append_x (scm_list_2 (SCM_SLOT (class, scm_si_slots),
                                              scm_list_1 (slot))));
-      SCM_SET_SLOT (class, scm_si_getters_n_setters,
-                   scm_append_x (scm_list_2 (SCM_SLOT (class, scm_si_getters_n_setters),
-                                             scm_list_1 (gns))));
+      {
+       SCM n = SCM_SLOT (class, scm_si_nfields);
+       SCM gns = scm_list_n (name, SCM_BOOL_F, get, set, n, SCM_MAKINUM (1));
+       SCM_SET_SLOT (class, scm_si_getters_n_setters,
+                     scm_append_x (scm_list_2 (SCM_SLOT (class, scm_si_getters_n_setters),
+                                               scm_list_1 (gns))));
+       SCM_SET_SLOT (class, scm_si_nfields, SCM_MAKINUM (SCM_INUM (n) + 1));
+      }
     }
   }
-  {
-    long n = SCM_INUM (SCM_SLOT (class, scm_si_nfields));
-
-    SCM_SET_SLOT (class, scm_si_nfields, SCM_MAKINUM (n + 1));
-  }
 }
 
 SCM
@@ -2621,10 +2792,10 @@ SCM
 scm_ensure_accessor (SCM name)
 {
   SCM gf = scm_call_2 (SCM_TOP_LEVEL_LOOKUP_CLOSURE, name, SCM_BOOL_F);
-  if (!SCM_IS_A_P (gf, scm_class_generic_with_setter))
+  if (!SCM_IS_A_P (gf, scm_class_accessor))
     {
       gf = scm_make (scm_list_3 (scm_class_generic, k_name, name));
-      gf = scm_make (scm_list_5 (scm_class_generic_with_setter,
+      gf = scm_make (scm_list_5 (scm_class_accessor,
                                 k_name, name, k_setter, gf));
     }
   return gf;
@@ -2668,6 +2839,7 @@ SCM_DEFINE (scm_sys_goops_loaded, "%goops-loaded", 0, 0, 0,
   var_compute_applicable_methods =
     scm_sym2var (sym_compute_applicable_methods, scm_goops_lookup_closure,
                 SCM_BOOL_F);
+  setup_extended_primitive_generics ();
   return SCM_UNSPECIFIED;
 }
 #undef FUNC_NAME
@@ -2695,9 +2867,7 @@ scm_init_goops_builtins (void)
   list_of_no_method = scm_permanent_object (scm_list_1 (sym_no_method));
 
   hell = scm_malloc (hell_size);
-#ifdef USE_THREADS
-  scm_mutex_init (&hell_mutex);
-#endif
+  hell_mutex = scm_permanent_object (scm_make_mutex ());
 
   create_basic_classes ();
   create_standard_classes ();