You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucy.apache.org by nw...@apache.org on 2013/07/20 18:05:08 UTC

[lucy-commits] [1/4] git commit: refs/heads/master - Mark VTableSpec and MethSpec arrays as const

Updated Branches:
  refs/heads/master bf58f4a85 -> f089ae805


Mark VTableSpec and MethSpec arrays as const


Project: http://git-wip-us.apache.org/repos/asf/lucy/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy/commit/38b92c30
Tree: http://git-wip-us.apache.org/repos/asf/lucy/tree/38b92c30
Diff: http://git-wip-us.apache.org/repos/asf/lucy/diff/38b92c30

Branch: refs/heads/master
Commit: 38b92c30f9941c61934b1937d06fe22f1d2708d4
Parents: 8b2c808
Author: Nick Wellnhofer <we...@aevum.de>
Authored: Wed Jul 17 20:25:24 2013 +0200
Committer: Nick Wellnhofer <we...@aevum.de>
Committed: Sat Jul 20 17:54:51 2013 +0200

----------------------------------------------------------------------
 clownfish/compiler/src/CFCBindClass.c       | 11 ++++++-----
 clownfish/compiler/src/CFCBindCore.c        |  8 ++++----
 clownfish/runtime/core/Clownfish/VTable.c   | 22 +++++++++++-----------
 clownfish/runtime/core/Clownfish/VTable.cfh |  2 +-
 4 files changed, 22 insertions(+), 21 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy/blob/38b92c30/clownfish/compiler/src/CFCBindClass.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCBindClass.c b/clownfish/compiler/src/CFCBindClass.c
index f0a86a2..f507596 100644
--- a/clownfish/compiler/src/CFCBindClass.c
+++ b/clownfish/compiler/src/CFCBindClass.c
@@ -312,7 +312,8 @@ CFCBindClass_to_c_data(CFCBindClass *self) {
                 // symbol and then store a pointer to that symbol inside the
                 // VTableSpec struct.
                 novel_ms_var
-                    = CFCUtil_cat(novel_ms_var, "static cfish_NovelMethSpec ",
+                    = CFCUtil_cat(novel_ms_var,
+                                  "static const cfish_NovelMethSpec ",
                                   vt_var, "_NOVEL_METHS[] = {\n", NULL);
             }
             else {
@@ -327,8 +328,8 @@ CFCBindClass_to_c_data(CFCBindClass *self) {
                 // Start an array of cfish_OverriddenMethSpec structs.
                 overridden_ms_var
                     = CFCUtil_cat(overridden_ms_var,
-                                  "static cfish_OverriddenMethSpec ", vt_var,
-                                  "_OVERRIDDEN_METHS[] = {\n", NULL);
+                                  "static const cfish_OverriddenMethSpec ",
+                                  vt_var, "_OVERRIDDEN_METHS[] = {\n", NULL);
             }
             else {
                 overridden_ms_var
@@ -343,8 +344,8 @@ CFCBindClass_to_c_data(CFCBindClass *self) {
                 // Start an array of cfish_InheritedMethSpec structs.
                 inherited_ms_var
                     = CFCUtil_cat(inherited_ms_var,
-                                  "static cfish_InheritedMethSpec ", vt_var,
-                                  "_INHERITED_METHS[] = {\n", NULL);
+                                  "static const cfish_InheritedMethSpec ",
+                                  vt_var, "_INHERITED_METHS[] = {\n", NULL);
             }
             else {
                 inherited_ms_var = CFCUtil_cat(inherited_ms_var, ",\n", NULL);

http://git-wip-us.apache.org/repos/asf/lucy/blob/38b92c30/clownfish/compiler/src/CFCBindCore.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCBindCore.c b/clownfish/compiler/src/CFCBindCore.c
index 41f634b..af28e6a 100644
--- a/clownfish/compiler/src/CFCBindCore.c
+++ b/clownfish/compiler/src/CFCBindCore.c
@@ -250,9 +250,9 @@ S_write_parcel_h(CFCBindCore *self, CFCParcel *parcel) {
         "    uint32_t       num_novel_meths;\n"
         "    uint32_t       num_overridden_meths;\n"
         "    uint32_t       num_inherited_meths;\n"
-        "    cfish_NovelMethSpec      *novel_meth_specs;\n"
-        "    cfish_OverriddenMethSpec *overridden_meth_specs;\n"
-        "    cfish_InheritedMethSpec  *inherited_meth_specs;\n"
+        "    const cfish_NovelMethSpec      *novel_meth_specs;\n"
+        "    const cfish_OverriddenMethSpec *overridden_meth_specs;\n"
+        "    const cfish_InheritedMethSpec  *inherited_meth_specs;\n"
         "} cfish_VTableSpec;\n"
         "\n"
         "#ifdef CFISH_USE_SHORT_NAMES\n"
@@ -355,7 +355,7 @@ S_write_parcel_c(CFCBindCore *self, CFCParcel *parcel) {
     char *includes     = CFCUtil_strdup("");
     char *c_data       = CFCUtil_strdup("");
     char *vt_specs = CFCUtil_strdup(
-        "static cfish_VTableSpec vtable_specs[] = {\n");
+        "static const cfish_VTableSpec vtable_specs[] = {\n");
     int num_specs = 0;
     CFCClass **ordered  = CFCHierarchy_ordered_classes(hierarchy);
     for (int i = 0; ordered[i] != NULL; i++) {

http://git-wip-us.apache.org/repos/asf/lucy/blob/38b92c30/clownfish/runtime/core/Clownfish/VTable.c
----------------------------------------------------------------------
diff --git a/clownfish/runtime/core/Clownfish/VTable.c b/clownfish/runtime/core/Clownfish/VTable.c
index 11222e9..58391b2 100644
--- a/clownfish/runtime/core/Clownfish/VTable.c
+++ b/clownfish/runtime/core/Clownfish/VTable.c
@@ -52,7 +52,7 @@ S_claim_parcel_id(void);
 LockFreeRegistry *VTable_registry = NULL;
 
 void
-VTable_bootstrap(VTableSpec *specs, size_t num_specs)
+VTable_bootstrap(const VTableSpec *specs, size_t num_specs)
 {
     int32_t parcel_id = S_claim_parcel_id();
 
@@ -64,8 +64,8 @@ VTable_bootstrap(VTableSpec *specs, size_t num_specs)
      * - Initialize method pointers.
      */
     for (size_t i = 0; i < num_specs; ++i) {
-        VTableSpec *spec   = &specs[i];
-        VTable     *parent = spec->parent ? *spec->parent : NULL;
+        const VTableSpec *spec = &specs[i];
+        VTable *parent = spec->parent ? *spec->parent : NULL;
 
         size_t ivars_offset = 0;
         if (spec->ivars_offset_ptr != NULL) {
@@ -103,18 +103,18 @@ VTable_bootstrap(VTableSpec *specs, size_t num_specs)
         }
 
         for (size_t i = 0; i < spec->num_inherited_meths; ++i) {
-            InheritedMethSpec *mspec = &spec->inherited_meth_specs[i];
+            const InheritedMethSpec *mspec = &spec->inherited_meth_specs[i];
             *mspec->offset = *mspec->parent_offset;
         }
 
         for (size_t i = 0; i < spec->num_overridden_meths; ++i) {
-            OverriddenMethSpec *mspec = &spec->overridden_meth_specs[i];
+            const OverriddenMethSpec *mspec = &spec->overridden_meth_specs[i];
             *mspec->offset = *mspec->parent_offset;
             VTable_override(vtable, mspec->func, *mspec->offset);
         }
 
         for (size_t i = 0; i < spec->num_novel_meths; ++i) {
-            NovelMethSpec *mspec = &spec->novel_meth_specs[i];
+            const NovelMethSpec *mspec = &spec->novel_meth_specs[i];
             *mspec->offset = novel_offset;
             novel_offset += sizeof(cfish_method_t);
             VTable_override(vtable, mspec->func, *mspec->offset);
@@ -128,8 +128,8 @@ VTable_bootstrap(VTableSpec *specs, size_t num_specs)
      * - Initialize refcount.
      */
     for (size_t i = 0; i < num_specs; ++i) {
-        VTableSpec *spec   = &specs[i];
-        VTable     *vtable = *spec->vtable;
+        const VTableSpec *spec = &specs[i];
+        VTable *vtable = *spec->vtable;
 
         VTable_init_obj(VTABLE, vtable);
     }
@@ -141,14 +141,14 @@ VTable_bootstrap(VTableSpec *specs, size_t num_specs)
      * - Register vtable.
      */
     for (size_t i = 0; i < num_specs; ++i) {
-        VTableSpec *spec   = &specs[i];
-        VTable     *vtable = *spec->vtable;
+        const VTableSpec *spec = &specs[i];
+        VTable *vtable = *spec->vtable;
 
         vtable->name    = CB_newf("%s", spec->name);
         vtable->methods = VA_new(0);
 
         for (size_t i = 0; i < spec->num_novel_meths; ++i) {
-            NovelMethSpec *mspec = &spec->novel_meth_specs[i];
+            const NovelMethSpec *mspec = &spec->novel_meth_specs[i];
             CharBuf *name = CB_newf("%s", mspec->name);
             Method *method = Method_new(name, mspec->callback_func,
                                         *mspec->offset);

http://git-wip-us.apache.org/repos/asf/lucy/blob/38b92c30/clownfish/runtime/core/Clownfish/VTable.cfh
----------------------------------------------------------------------
diff --git a/clownfish/runtime/core/Clownfish/VTable.cfh b/clownfish/runtime/core/Clownfish/VTable.cfh
index 6d62f44..c065495 100644
--- a/clownfish/runtime/core/Clownfish/VTable.cfh
+++ b/clownfish/runtime/core/Clownfish/VTable.cfh
@@ -38,7 +38,7 @@ class Clownfish::VTable inherits Clownfish::Obj {
     inert size_t offset_of_parent;
 
     inert void
-    bootstrap(cfish_VTableSpec *specs, size_t num_specs);
+    bootstrap(const cfish_VTableSpec *specs, size_t num_specs);
 
     /** Return a singleton.  If a VTable can be found in the registry based on
      * the supplied class name, it will be returned.  Otherwise, a new VTable


[lucy-commits] [4/4] git commit: refs/heads/master - Adjust some comments

Posted by nw...@apache.org.
Adjust some comments


Project: http://git-wip-us.apache.org/repos/asf/lucy/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy/commit/f089ae80
Tree: http://git-wip-us.apache.org/repos/asf/lucy/tree/f089ae80
Diff: http://git-wip-us.apache.org/repos/asf/lucy/diff/f089ae80

Branch: refs/heads/master
Commit: f089ae8051e55fb53dc14d7ff644a2c734fdbb64
Parents: 38b92c3
Author: Nick Wellnhofer <we...@aevum.de>
Authored: Sat Jul 20 18:04:25 2013 +0200
Committer: Nick Wellnhofer <we...@aevum.de>
Committed: Sat Jul 20 18:04:25 2013 +0200

----------------------------------------------------------------------
 clownfish/compiler/src/CFCBindCore.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy/blob/f089ae80/clownfish/compiler/src/CFCBindCore.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCBindCore.c b/clownfish/compiler/src/CFCBindCore.c
index af28e6a..5a7c94a 100644
--- a/clownfish/compiler/src/CFCBindCore.c
+++ b/clownfish/compiler/src/CFCBindCore.c
@@ -418,7 +418,7 @@ S_write_parcel_c(CFCBindCore *self, CFCParcel *parcel) {
     char pattern[] =
         "%s\n"
         "\n"
-        "#define C_CFISH_VTABLE\n"          // Needed for method_ptrs offset.
+        "#define C_CFISH_VTABLE\n"          // Needed for abstract methods.
         "#include <stdio.h>\n"
         "#include <stdlib.h>\n"
         "%s\n"
@@ -428,7 +428,7 @@ S_write_parcel_c(CFCBindCore *self, CFCParcel *parcel) {
         "#include \"Clownfish/Err.h\"\n"     // Needed for dump/load.
         "#include \"Clownfish/Num.h\"\n"     // Needed for dump/load.
         "#include \"Clownfish/VArray.h\"\n"  // Needed for dump/load.
-        "#include \"Clownfish/VTable.h\"\n"  // Needed for method_ptrs offset.
+        "#include \"Clownfish/VTable.h\"\n"  // Needed for bootstrap.
         "%s\n"
         "\n"
         "%s\n"


[lucy-commits] [3/4] git commit: refs/heads/master - Carry over novel flag when finalizing methods

Posted by nw...@apache.org.
Carry over novel flag when finalizing methods


Project: http://git-wip-us.apache.org/repos/asf/lucy/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy/commit/0f184c2a
Tree: http://git-wip-us.apache.org/repos/asf/lucy/tree/0f184c2a
Diff: http://git-wip-us.apache.org/repos/asf/lucy/diff/0f184c2a

Branch: refs/heads/master
Commit: 0f184c2a5a7243b3653d82f79a95bd1fc48f7dbd
Parents: bf58f4a
Author: Nick Wellnhofer <we...@aevum.de>
Authored: Wed Jul 17 19:50:44 2013 +0200
Committer: Nick Wellnhofer <we...@aevum.de>
Committed: Sat Jul 20 17:54:51 2013 +0200

----------------------------------------------------------------------
 clownfish/compiler/src/CFCMethod.c | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy/blob/0f184c2a/clownfish/compiler/src/CFCMethod.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCMethod.c b/clownfish/compiler/src/CFCMethod.c
index 595cab7..9710209 100644
--- a/clownfish/compiler/src/CFCMethod.c
+++ b/clownfish/compiler/src/CFCMethod.c
@@ -229,6 +229,7 @@ CFCMethod_finalize(CFCMethod *self) {
                         self->function.param_list,
                         self->function.docucomment, true,
                         self->is_abstract);
+    finalized->is_novel = self->is_novel;
     return finalized;
 }
 


[lucy-commits] [2/4] git commit: refs/heads/master - Dynamic method offsets

Posted by nw...@apache.org.
Dynamic method offsets

Create separate specs for novel, overridden, and inherited methods and
use them to initialize method offsets dynamically during bootstrap.


Project: http://git-wip-us.apache.org/repos/asf/lucy/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy/commit/8b2c8081
Tree: http://git-wip-us.apache.org/repos/asf/lucy/tree/8b2c8081
Diff: http://git-wip-us.apache.org/repos/asf/lucy/diff/8b2c8081

Branch: refs/heads/master
Commit: 8b2c8081edd864ce58aeb2cd745705ff4b303d00
Parents: 0f184c2
Author: Nick Wellnhofer <we...@aevum.de>
Authored: Mon Jul 15 01:55:07 2013 +0200
Committer: Nick Wellnhofer <we...@aevum.de>
Committed: Sat Jul 20 17:54:51 2013 +0200

----------------------------------------------------------------------
 clownfish/compiler/perl/lib/Clownfish/CFC.xs |  20 ++-
 clownfish/compiler/src/CFCBindClass.c        | 192 +++++++++++++++-------
 clownfish/compiler/src/CFCBindCore.c         |  39 +++--
 clownfish/compiler/src/CFCBindMethod.c       |  61 +++++--
 clownfish/compiler/src/CFCBindMethod.h       |  18 +-
 clownfish/runtime/core/Clownfish/VTable.c    |  43 +++--
 6 files changed, 269 insertions(+), 104 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy/blob/8b2c8081/clownfish/compiler/perl/lib/Clownfish/CFC.xs
----------------------------------------------------------------------
diff --git a/clownfish/compiler/perl/lib/Clownfish/CFC.xs b/clownfish/compiler/perl/lib/Clownfish/CFC.xs
index 1b36124..fafe3c3 100644
--- a/clownfish/compiler/perl/lib/Clownfish/CFC.xs
+++ b/clownfish/compiler/perl/lib/Clownfish/CFC.xs
@@ -1971,10 +1971,26 @@ CODE:
 OUTPUT: RETVAL
 
 SV*
-_spec_def(meth)
+_novel_spec_def(meth)
     CFCMethod *meth;
 CODE:
-    RETVAL = S_sv_eat_c_string(CFCBindMeth_spec_def(meth));
+    RETVAL = S_sv_eat_c_string(CFCBindMeth_novel_spec_def(meth));
+OUTPUT: RETVAL
+
+SV*
+_overridden_spec_def(meth, klass)
+    CFCMethod *meth;
+    CFCClass  *klass;
+CODE:
+    RETVAL = S_sv_eat_c_string(CFCBindMeth_overridden_spec_def(meth, klass));
+OUTPUT: RETVAL
+
+SV*
+_inherited_spec_def(meth, klass)
+    CFCMethod *meth;
+    CFCClass  *klass;
+CODE:
+    RETVAL = S_sv_eat_c_string(CFCBindMeth_inherited_spec_def(meth, klass));
 OUTPUT: RETVAL
 
 MODULE = Clownfish::CFC  PACKAGE = Clownfish::CFC::Binding::Core::Aliases

http://git-wip-us.apache.org/repos/asf/lucy/blob/8b2c8081/clownfish/compiler/src/CFCBindClass.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCBindClass.c b/clownfish/compiler/src/CFCBindClass.c
index 8b72db1..f0a86a2 100644
--- a/clownfish/compiler/src/CFCBindClass.c
+++ b/clownfish/compiler/src/CFCBindClass.c
@@ -34,7 +34,6 @@
 struct CFCBindClass {
     CFCBase base;
     CFCClass *client;
-    char *method_specs_var;
     char *short_names_macro;
 };
 
@@ -91,9 +90,7 @@ CFCBindClass_init(CFCBindClass *self, CFCClass *client) {
     CFCUTIL_NULL_CHECK(client);
     self->client = (CFCClass*)CFCBase_incref((CFCBase*)client);
 
-    const char *full_vtable_var = CFCClass_full_vtable_var(client);
     const char *PREFIX = CFCClass_get_PREFIX(client);
-    self->method_specs_var  = CFCUtil_sprintf("%s_METHODS", full_vtable_var);
     self->short_names_macro = CFCUtil_sprintf("%sUSE_SHORT_NAMES", PREFIX);
 
     return self;
@@ -101,7 +98,6 @@ CFCBindClass_init(CFCBindClass *self, CFCClass *client) {
 
 void
 CFCBindClass_destroy(CFCBindClass *self) {
-    FREEMEM(self->method_specs_var);
     FREEMEM(self->short_names_macro);
     CFCBase_decref((CFCBase*)self->client);
     CFCBase_destroy((CFCBase*)self);
@@ -270,6 +266,7 @@ S_to_c_header_dynamic(CFCBindClass *self) {
 char*
 CFCBindClass_to_c_data(CFCBindClass *self) {
     CFCClass *client = self->client;
+    const char *class_name = CFCClass_get_class_name(client);
 
     if (CFCClass_inert(client)) {
         return CFCUtil_strdup(CFCClass_get_autocode(client));
@@ -281,55 +278,92 @@ CFCBindClass_to_c_data(CFCBindClass *self) {
     const char *vt_var    = CFCClass_full_vtable_var(client);
 
     CFCMethod **methods  = CFCClass_methods(client);
-    CFCMethod **fresh_methods = CFCClass_fresh_methods(client);
 
-    char *offsets     = CFCUtil_strdup("");
-    char *method_defs = CFCUtil_strdup("");
-    char *ms_var      = CFCUtil_strdup("");
+    char *offsets           = CFCUtil_strdup("");
+    char *method_defs       = CFCUtil_strdup("");
+    char *novel_ms_var      = CFCUtil_strdup("");
+    char *overridden_ms_var = CFCUtil_strdup("");
+    char *inherited_ms_var  = CFCUtil_strdup("");
 
     for (int meth_num = 0; methods[meth_num] != NULL; meth_num++) {
         CFCMethod *method = methods[meth_num];
+
+        // Define method offset variable.
         char *full_offset_sym = CFCMethod_full_offset_sym(method, client);
-        // Create offset in bytes for the method from the top of the VTable
-        // object.
-        const char pattern[] =
-            "size_t %s = offsetof(cfish_VTable, method_ptrs)"
-            " + %d * sizeof(cfish_method_t);\n";
-        char *offset = CFCUtil_sprintf(pattern, full_offset_sym, meth_num);
-        offsets = CFCUtil_cat(offsets, offset, NULL);
+        offsets = CFCUtil_cat(offsets, "size_t ", full_offset_sym, ";\n",
+                              NULL);
         FREEMEM(full_offset_sym);
-        FREEMEM(offset);
-    }
 
-    if (fresh_methods[0] != NULL) {
-        /* Start an array of cfish_MethodSpec structs.  Since C89 doesn't allow 
-         * us to initialize a pointer to an anonymous array inside a global
-         * struct, we have to give it a real symbol and then store a pointer to
-         * that symbol inside the VTableSpec struct. */
-        ms_var = CFCUtil_cat(ms_var, "static cfish_MethodSpec ",
-                             self->method_specs_var, "[] = {\n", NULL);
-
-        for (int meth_num = 0; fresh_methods[meth_num] != NULL; meth_num++) {
-            CFCMethod *method = fresh_methods[meth_num];
-
-            // Create a default implementation for abstract methods.
-            if (CFCMethod_abstract(method)) {
-                char *method_def = CFCBindMeth_abstract_method_def(method);
-                method_defs = CFCUtil_cat(method_defs, method_def, "\n", NULL);
-                FREEMEM(method_def);
-            }
+        const char *meth_class_name = CFCMethod_get_class_name(method);
+        int is_fresh = strcmp(class_name, meth_class_name) == 0;
 
-            // Define MethodSpec struct.
-            if (meth_num != 0) {
-                ms_var = CFCUtil_cat(ms_var, ",\n", NULL);
+        // Create a default implementation for abstract methods.
+        if (is_fresh && CFCMethod_abstract(method)) {
+            char *method_def = CFCBindMeth_abstract_method_def(method);
+            method_defs = CFCUtil_cat(method_defs, method_def, "\n", NULL);
+            FREEMEM(method_def);
+        }
+
+        if (is_fresh && CFCMethod_novel(method)) {
+            if (novel_ms_var[0] == '\0') {
+                // Start an array of cfish_NovelMethSpec structs.  Since C89
+                // doesn't allow us to initialize a pointer to an anonymous
+                // array inside a global struct, we have to give it a real
+                // symbol and then store a pointer to that symbol inside the
+                // VTableSpec struct.
+                novel_ms_var
+                    = CFCUtil_cat(novel_ms_var, "static cfish_NovelMethSpec ",
+                                  vt_var, "_NOVEL_METHS[] = {\n", NULL);
+            }
+            else {
+                novel_ms_var = CFCUtil_cat(novel_ms_var, ",\n", NULL);
+            }
+            char *ms_def = CFCBindMeth_novel_spec_def(method);
+            novel_ms_var = CFCUtil_cat(novel_ms_var, ms_def, NULL);
+            FREEMEM(ms_def);
+        }
+        else if (is_fresh) {
+            if (overridden_ms_var[0] == '\0') {
+                // Start an array of cfish_OverriddenMethSpec structs.
+                overridden_ms_var
+                    = CFCUtil_cat(overridden_ms_var,
+                                  "static cfish_OverriddenMethSpec ", vt_var,
+                                  "_OVERRIDDEN_METHS[] = {\n", NULL);
+            }
+            else {
+                overridden_ms_var
+                    = CFCUtil_cat(overridden_ms_var, ",\n", NULL);
             }
-            char *ms_def = CFCBindMeth_spec_def(method);
-            ms_var = CFCUtil_cat(ms_var, ms_def, NULL);
+            char *ms_def = CFCBindMeth_overridden_spec_def(method, client);
+            overridden_ms_var = CFCUtil_cat(overridden_ms_var, ms_def, NULL);
             FREEMEM(ms_def);
         }
+        else {
+            if (inherited_ms_var[0] == '\0') {
+                // Start an array of cfish_InheritedMethSpec structs.
+                inherited_ms_var
+                    = CFCUtil_cat(inherited_ms_var,
+                                  "static cfish_InheritedMethSpec ", vt_var,
+                                  "_INHERITED_METHS[] = {\n", NULL);
+            }
+            else {
+                inherited_ms_var = CFCUtil_cat(inherited_ms_var, ",\n", NULL);
+            }
+            char *ms_def = CFCBindMeth_inherited_spec_def(method, client);
+            inherited_ms_var = CFCUtil_cat(inherited_ms_var, ms_def, NULL);
+            FREEMEM(ms_def);
+        }
+    }
 
-        // Close MethodSpec array definition.
-        ms_var =  CFCUtil_cat(ms_var, "\n};\n", NULL);
+    // Close MethSpec array definitions.
+    if (novel_ms_var[0] != '\0') {
+        novel_ms_var = CFCUtil_cat(novel_ms_var, "\n};\n\n", NULL);
+    }
+    if (overridden_ms_var[0] != '\0') {
+        overridden_ms_var = CFCUtil_cat(overridden_ms_var, "\n};\n\n", NULL);
+    }
+    if (inherited_ms_var[0] != '\0') {
+        inherited_ms_var = CFCUtil_cat(inherited_ms_var, "\n};\n\n", NULL);
     }
 
     const char pattern[] =
@@ -350,12 +384,12 @@ CFCBindClass_to_c_data(CFCBindClass *self) {
         "\n"
         "%s\n"
         "\n"
-        "/* Define the cfish_MethodSpec structs used during VTable\n"
-        " * initialization.\n"
+        "/* Define the MethSpec structs used during VTable initialization.\n"
         " */\n"
         "\n"
-        "%s\n"
-        "\n"
+        "%s"
+        "%s"
+        "%s"
         "/* Define this class's VTable.\n"
         " */\n"
         "\n"
@@ -366,13 +400,16 @@ CFCBindClass_to_c_data(CFCBindClass *self) {
         "\n"
         "%s\n"
         "\n";
-    char *code = CFCUtil_sprintf(pattern, ivars_offset, offsets, method_defs,
-                                 ms_var, vt_var, autocode);
+    char *code
+        = CFCUtil_sprintf(pattern, ivars_offset, offsets, method_defs,
+                          novel_ms_var, overridden_ms_var, inherited_ms_var,
+                          vt_var, autocode);
 
-    FREEMEM(fresh_methods);
     FREEMEM(offsets);
     FREEMEM(method_defs);
-    FREEMEM(ms_var);
+    FREEMEM(novel_ms_var);
+    FREEMEM(overridden_ms_var);
+    FREEMEM(inherited_ms_var);
     return code;
 }
 
@@ -441,16 +478,37 @@ CFCBindClass_spec_def(CFCBindClass *self) {
         parent_ref = CFCUtil_strdup("NULL");
     }
 
-    int num_fresh = 0;
-    int num_novel = 0;
-    CFCMethod **fresh_methods = CFCClass_fresh_methods(client);
-    for (int meth_num = 0; fresh_methods[meth_num] != NULL; meth_num++) {
-        CFCMethod *method = fresh_methods[meth_num];
-        ++num_fresh;
-        if (CFCMethod_novel(method)) { ++num_novel; }
+    int num_novel      = 0;
+    int num_overridden = 0;
+    int num_inherited  = 0;
+    CFCMethod **methods = CFCClass_methods(client);
+
+    for (int meth_num = 0; methods[meth_num] != NULL; meth_num++) {
+        CFCMethod *method = methods[meth_num];
+        const char *meth_class_name = CFCMethod_get_class_name(method);
+
+        if (strcmp(class_name, meth_class_name) == 0) {
+            if (CFCMethod_novel(method)) {
+                ++num_novel;
+            }
+            else {
+                ++num_overridden;
+            }
+        }
+        else {
+            ++num_inherited;
+        }
     }
-    FREEMEM(fresh_methods);
-    const char *ms_var = num_fresh ? self->method_specs_var : "NULL";
+
+    char *novel_ms_var      = num_novel
+                              ? CFCUtil_sprintf("%s_NOVEL_METHS", vt_var)
+                              : CFCUtil_strdup("NULL");
+    char *overridden_ms_var = num_overridden
+                              ? CFCUtil_sprintf("%s_OVERRIDDEN_METHS", vt_var)
+                              : CFCUtil_strdup("NULL");
+    char *inherited_ms_var  = num_inherited
+                              ? CFCUtil_sprintf("%s_INHERITED_METHS", vt_var)
+                              : CFCUtil_strdup("NULL");
 
     const char *ivars_or_not = strcmp(prefix, "cfish_") == 0
                                ? struct_sym : ivars_struct;
@@ -463,15 +521,23 @@ CFCBindClass_spec_def(CFCBindClass *self) {
         "        \"%s\", /* name */\n"
         "        sizeof(%s), /* ivars_size */\n"
         "        &%s, /* ivars_offset_ptr */\n"
-        "        %d, /* num_fresh */\n"
         "        %d, /* num_novel */\n"
-        "        %s /* method_specs */\n"
+        "        %d, /* num_overridden */\n"
+        "        %d, /* num_inherited */\n"
+        "        %s, /* novel_meth_specs */\n"
+        "        %s, /* overridden_meth_specs */\n"
+        "        %s /* inherited_meth_specs */\n"
         "    }";
-    char *code = CFCUtil_sprintf(pattern, vt_var, parent_ref, class_name,
-                                 ivars_or_not, ivars_offset_name,
-                                 num_fresh, num_novel, ms_var);
+    char *code
+        = CFCUtil_sprintf(pattern, vt_var, parent_ref, class_name,
+                          ivars_or_not, ivars_offset_name, num_novel,
+                          num_overridden, num_inherited, novel_ms_var,
+                          overridden_ms_var, inherited_ms_var);
 
     FREEMEM(parent_ref);
+    FREEMEM(novel_ms_var);
+    FREEMEM(overridden_ms_var);
+    FREEMEM(inherited_ms_var);
     return code;
 }
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/8b2c8081/clownfish/compiler/src/CFCBindCore.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCBindCore.c b/clownfish/compiler/src/CFCBindCore.c
index 7abc4c2..41f634b 100644
--- a/clownfish/compiler/src/CFCBindCore.c
+++ b/clownfish/compiler/src/CFCBindCore.c
@@ -223,30 +223,45 @@ S_write_parcel_h(CFCBindCore *self, CFCParcel *parcel) {
         "/* Structs for VTable initialization.\n"
         " */\n"
         "\n"
-        "typedef struct cfish_MethodSpec {\n"
-        "    int             is_novel;\n"
+        "typedef struct cfish_NovelMethSpec {\n"
+        "    size_t         *offset;\n"
         "    const char     *name;\n"
         "    cfish_method_t  func;\n"
         "    cfish_method_t  callback_func;\n"
+        "} cfish_NovelMethSpec;\n"
+        "\n"
+        "typedef struct cfish_OverriddenMethSpec {\n"
         "    size_t         *offset;\n"
-        "} cfish_MethodSpec;\n"
+        "    size_t         *parent_offset;\n"
+        "    cfish_method_t  func;\n"
+        "} cfish_OverriddenMethSpec;\n"
+        "\n"
+        "typedef struct cfish_InheritedMethSpec {\n"
+        "    size_t *offset;\n"
+        "    size_t *parent_offset;\n"
+        "} cfish_InheritedMethSpec;\n"
         "\n"
         "typedef struct cfish_VTableSpec {\n"
-        "    cfish_VTable     **vtable;\n"
-        "    cfish_VTable     **parent;\n"
-        "    const char        *name;\n"
-        "    size_t             ivars_size;\n"
-        "    size_t            *ivars_offset_ptr;\n"
-        "    size_t             num_fresh;\n"
-        "    size_t             num_novel;\n"
-        "    cfish_MethodSpec  *method_specs;\n"
+        "    cfish_VTable **vtable;\n"
+        "    cfish_VTable **parent;\n"
+        "    const char    *name;\n"
+        "    size_t         ivars_size;\n"
+        "    size_t        *ivars_offset_ptr;\n"
+        "    uint32_t       num_novel_meths;\n"
+        "    uint32_t       num_overridden_meths;\n"
+        "    uint32_t       num_inherited_meths;\n"
+        "    cfish_NovelMethSpec      *novel_meth_specs;\n"
+        "    cfish_OverriddenMethSpec *overridden_meth_specs;\n"
+        "    cfish_InheritedMethSpec  *inherited_meth_specs;\n"
         "} cfish_VTableSpec;\n"
         "\n"
         "#ifdef CFISH_USE_SHORT_NAMES\n"
         "  #define METHOD_PTR               CFISH_METHOD_PTR\n"
         "  #define SUPER_METHOD_PTR         CFISH_SUPER_METHOD_PTR\n"
         "  #define OVERRIDDEN               CFISH_OVERRIDDEN\n"
-        "  #define MethodSpec               cfish_MethodSpec\n"
+        "  #define NovelMethSpec            cfish_NovelMethSpec\n"
+        "  #define OverriddenMethSpec       cfish_OverriddenMethSpec\n"
+        "  #define InheritedMethSpec        cfish_InheritedMethSpec\n"
         "  #define VTableSpec               cfish_VTableSpec\n"
         "#endif\n"
         "\n";

http://git-wip-us.apache.org/repos/asf/lucy/blob/8b2c8081/clownfish/compiler/src/CFCBindMethod.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCBindMethod.c b/clownfish/compiler/src/CFCBindMethod.c
index c2214a1..3669b04 100644
--- a/clownfish/compiler/src/CFCBindMethod.c
+++ b/clownfish/compiler/src/CFCBindMethod.c
@@ -146,13 +146,12 @@ CFCBindMeth_typedef_dec(struct CFCMethod *method, CFCClass *klass) {
 }
 
 char*
-CFCBindMeth_spec_def(CFCMethod *method) {
-    const char *macro_sym   = CFCMethod_get_macro_sym(method);
-    const char *impl_sym    = CFCMethod_implementing_func_sym(method);
-    int         is_novel    = CFCMethod_novel(method);
+CFCBindMeth_novel_spec_def(CFCMethod *method) {
+    const char *macro_sym = CFCMethod_get_macro_sym(method);
+    const char *impl_sym  = CFCMethod_implementing_func_sym(method);
 
     const char *full_override_sym = "NULL";
-    if (is_novel && !CFCMethod_final(method)) {
+    if (!CFCMethod_final(method)) {
         full_override_sym = CFCMethod_full_override_sym(method);
     }
 
@@ -160,20 +159,62 @@ CFCBindMeth_spec_def(CFCMethod *method) {
 
     char pattern[] =
         "    {\n"
-        "        %d, /* is_novel */\n"
+        "        &%s, /* offset */\n"
         "        \"%s\", /* name */\n"
         "        (cfish_method_t)%s, /* func */\n"
-        "        (cfish_method_t)%s, /* callback_func */\n"
-        "        &%s /* offset */\n"
+        "        (cfish_method_t)%s /* callback_func */\n"
         "    }";
     char *def
-        = CFCUtil_sprintf(pattern, is_novel, macro_sym, impl_sym,
-                          full_override_sym, full_offset_sym);
+        = CFCUtil_sprintf(pattern, full_offset_sym, macro_sym, impl_sym,
+                          full_override_sym);
 
     FREEMEM(full_offset_sym);
     return def;
 }
 
+char*
+CFCBindMeth_overridden_spec_def(CFCMethod *method, CFCClass *klass) {
+    const char *impl_sym  = CFCMethod_implementing_func_sym(method);
+
+    char *full_offset_sym = CFCMethod_full_offset_sym(method, NULL);
+
+    CFCClass *parent = CFCClass_get_parent(klass);
+    char *parent_offset_sym = CFCMethod_full_offset_sym(method, parent);
+
+    char pattern[] =
+        "    {\n"
+        "        &%s, /* offset */\n"
+        "        &%s, /* parent_offset */\n"
+        "        (cfish_method_t)%s /* func */\n"
+        "    }";
+    char *def
+        = CFCUtil_sprintf(pattern, full_offset_sym, parent_offset_sym,
+                          impl_sym);
+
+    FREEMEM(full_offset_sym);
+    FREEMEM(parent_offset_sym);
+    return def;
+}
+
+char*
+CFCBindMeth_inherited_spec_def(CFCMethod *method, CFCClass *klass) {
+    char *full_offset_sym = CFCMethod_full_offset_sym(method, klass);
+
+    CFCClass *parent = CFCClass_get_parent(klass);
+    char *parent_offset_sym = CFCMethod_full_offset_sym(method, parent);
+
+    char pattern[] =
+        "    {\n"
+        "        &%s, /* offset */\n"
+        "        &%s /* parent_offset */\n"
+        "    }";
+    char *def = CFCUtil_sprintf(pattern, full_offset_sym, parent_offset_sym);
+
+    FREEMEM(full_offset_sym);
+    FREEMEM(parent_offset_sym);
+    return def;
+}
+
 static char*
 S_build_unused_vars(CFCVariable **vars) {
     char *unused = CFCUtil_strdup("");

http://git-wip-us.apache.org/repos/asf/lucy/blob/8b2c8081/clownfish/compiler/src/CFCBindMethod.h
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCBindMethod.h b/clownfish/compiler/src/CFCBindMethod.h
index 85945da..9f2f256 100644
--- a/clownfish/compiler/src/CFCBindMethod.h
+++ b/clownfish/compiler/src/CFCBindMethod.h
@@ -44,11 +44,25 @@ CFCBindMeth_method_def(struct CFCMethod *method, struct CFCClass *klass);
 char*
 CFCBindMeth_typedef_dec(struct CFCMethod *method, struct CFCClass *klass);
 
-/** Return C code defining the MethodSpec object for this method, which
+/** Return C code defining the MethSpec object for a novel method, which
  * is used during VTable initialization.
  */
 char*
-CFCBindMeth_spec_def(struct CFCMethod *method);
+CFCBindMeth_novel_spec_def(struct CFCMethod *method);
+
+/** Return C code defining the MethSpec object for an overridden method,
+ * which is used during VTable initialization.
+ */
+char*
+CFCBindMeth_overridden_spec_def(struct CFCMethod *method,
+                                struct CFCClass *klass);
+
+/** Return C code defining the MethSpec object for an inherited method,
+ * which is used during VTable initialization.
+ */
+char*
+CFCBindMeth_inherited_spec_def(struct CFCMethod *method,
+                               struct CFCClass *klass);
 
 /** Return C code implementing a version of the method which throws an
  * "abstract method" error at runtime, for methods which are declared as

http://git-wip-us.apache.org/repos/asf/lucy/blob/8b2c8081/clownfish/runtime/core/Clownfish/VTable.c
----------------------------------------------------------------------
diff --git a/clownfish/runtime/core/Clownfish/VTable.c b/clownfish/runtime/core/Clownfish/VTable.c
index 268664c..11222e9 100644
--- a/clownfish/runtime/core/Clownfish/VTable.c
+++ b/clownfish/runtime/core/Clownfish/VTable.c
@@ -82,10 +82,12 @@ VTable_bootstrap(VTableSpec *specs, size_t num_specs)
             }
         }
 
-        size_t vt_alloc_size = parent
-                               ? parent->vt_alloc_size
-                               : offsetof(VTable, method_ptrs);
-        vt_alloc_size += spec->num_novel * sizeof(cfish_method_t);
+        size_t novel_offset = parent
+                              ? parent->vt_alloc_size
+                              : offsetof(VTable, method_ptrs);
+        size_t vt_alloc_size = novel_offset
+                               + spec->num_novel_meths
+                                 * sizeof(cfish_method_t);
         VTable *vtable = (VTable*)Memory_wrapped_calloc(vt_alloc_size, 1);
 
         vtable->parent         = parent;
@@ -100,8 +102,21 @@ VTable_bootstrap(VTableSpec *specs, size_t num_specs)
             memcpy(vtable->method_ptrs, parent->method_ptrs, parent_ptrs_size);
         }
 
-        for (size_t i = 0; i < spec->num_fresh; ++i) {
-            MethodSpec *mspec = &spec->method_specs[i];
+        for (size_t i = 0; i < spec->num_inherited_meths; ++i) {
+            InheritedMethSpec *mspec = &spec->inherited_meth_specs[i];
+            *mspec->offset = *mspec->parent_offset;
+        }
+
+        for (size_t i = 0; i < spec->num_overridden_meths; ++i) {
+            OverriddenMethSpec *mspec = &spec->overridden_meth_specs[i];
+            *mspec->offset = *mspec->parent_offset;
+            VTable_override(vtable, mspec->func, *mspec->offset);
+        }
+
+        for (size_t i = 0; i < spec->num_novel_meths; ++i) {
+            NovelMethSpec *mspec = &spec->novel_meth_specs[i];
+            *mspec->offset = novel_offset;
+            novel_offset += sizeof(cfish_method_t);
             VTable_override(vtable, mspec->func, *mspec->offset);
         }
 
@@ -132,15 +147,13 @@ VTable_bootstrap(VTableSpec *specs, size_t num_specs)
         vtable->name    = CB_newf("%s", spec->name);
         vtable->methods = VA_new(0);
 
-        for (size_t i = 0; i < spec->num_fresh; ++i) {
-            MethodSpec *mspec = &spec->method_specs[i];
-            if (mspec->is_novel) {
-                CharBuf *name = CB_newf("%s", mspec->name);
-                Method *method = Method_new(name, mspec->callback_func,
-                                            *mspec->offset);
-                VA_Push(vtable->methods, (Obj*)method);
-                DECREF(name);
-            }
+        for (size_t i = 0; i < spec->num_novel_meths; ++i) {
+            NovelMethSpec *mspec = &spec->novel_meth_specs[i];
+            CharBuf *name = CB_newf("%s", mspec->name);
+            Method *method = Method_new(name, mspec->callback_func,
+                                        *mspec->offset);
+            VA_Push(vtable->methods, (Obj*)method);
+            DECREF(name);
         }
 
         VTable_add_to_registry(vtable);