Attached is a patch that replaces the OFFSET globals with NUM #defines which contain the method number. This more than halves the number of extern symbols in Lucy.so. The only cost is a constant add for every method invocation which should be negligible.

This also removes the use of offsetof in parcel.c, so we don't need the definition of the VTable struct in that file.

Thoughts?

Nick
>From eed8ec5b00d80ecb735d8f435b5daa0e0354b4fa Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <[email protected]>
Date: Wed, 18 Apr 2012 01:33:21 +0200
Subject: [PATCH] Abolish OFFSET globals

Replace the OFFSET globals with NUM #defines which contain the method
number. This more than halves the number of extern symbols. The only cost
is a constant add for every method invocation which should be negligible.
---
 clownfish/perl/lib/Clownfish/CFC.xs   |   12 +++---
 clownfish/perl/t/201-method.t         |    2 +-
 clownfish/src/CFCBindAliases.c        |    1 +
 clownfish/src/CFCBindClass.c          |   73 +++++++++++++++++----------------
 clownfish/src/CFCBindCore.c           |   19 +++++----
 clownfish/src/CFCBindMethod.c         |   37 ++++++++++-------
 clownfish/src/CFCBindMethod.h         |    2 +-
 clownfish/src/CFCMethod.c             |    8 ++--
 clownfish/src/CFCMethod.h             |   10 ++---
 core/Lucy/Object/Obj.cfh              |    3 +-
 core/Lucy/Object/VTable.c             |   13 +++---
 core/Lucy/Object/VTable.cfh           |    1 +
 core/Lucy/Test/Store/TestFileHandle.c |    2 +-
 13 files changed, 98 insertions(+), 85 deletions(-)

diff --git a/clownfish/perl/lib/Clownfish/CFC.xs 
b/clownfish/perl/lib/Clownfish/CFC.xs
index 0775ab3..c1f1df4 100644
--- a/clownfish/perl/lib/Clownfish/CFC.xs
+++ b/clownfish/perl/lib/Clownfish/CFC.xs
@@ -882,7 +882,7 @@ _various_method_syms(self, invoker)
 ALIAS:
     short_method_sym  = 1
     full_method_sym   = 2
-    full_offset_sym   = 3
+    num_define        = 3
 CODE:
     size_t size = 0;
     switch (ix) {
@@ -893,7 +893,7 @@ CODE:
             size = CFCMethod_full_method_sym(self, invoker, NULL, 0);
             break;
         case 3:
-            size = CFCMethod_full_offset_sym(self, invoker, NULL, 0);
+            size = CFCMethod_num_define(self, invoker, NULL, 0);
             break;
         default: croak("Unexpected ix: %d", (int)ix);
     }
@@ -908,7 +908,7 @@ CODE:
             CFCMethod_full_method_sym(self, invoker, buf, size);
             break;
         case 3:
-            CFCMethod_full_offset_sym(self, invoker, buf, size);
+            CFCMethod_num_define(self, invoker, buf, size);
             break;
         default: croak("Unexpected ix: %d", (int)ix);
     }
@@ -1771,11 +1771,11 @@ CODE:
 OUTPUT: RETVAL
 
 SV*
-_callback_obj_def(meth, offset)
+_callback_obj_def(meth, klass)
     CFCMethod *meth;
-    const char *offset;
+    CFCClass  *klass;
 CODE:
-    RETVAL = S_sv_eat_c_string(CFCBindMeth_callback_obj_def(meth, offset));
+    RETVAL = S_sv_eat_c_string(CFCBindMeth_callback_obj_def(meth, klass));
 OUTPUT: RETVAL
 
 MODULE = Clownfish::CFC  PACKAGE = Clownfish::CFC::Binding::Core::Aliases
diff --git a/clownfish/perl/t/201-method.t b/clownfish/perl/t/201-method.t
index b7494df..47dd3d7 100644
--- a/clownfish/perl/t/201-method.t
+++ b/clownfish/perl/t/201-method.t
@@ -113,7 +113,7 @@ like( $@, qr/final/i, "Can't override final method" );
 
 ok( $not_final->compatible($final), "Finalize clones properly" );
 
-for my $meth_meth (qw( short_method_sym full_method_sym full_offset_sym)) {
+for my $meth_meth (qw( short_method_sym full_method_sym num_define )) {
     eval { my $blah = $method->$meth_meth; };
     like( $@, qr/invoker/, "$meth_meth requires invoker" );
 }
diff --git a/clownfish/src/CFCBindAliases.c b/clownfish/src/CFCBindAliases.c
index 008719d..734441f 100644
--- a/clownfish/src/CFCBindAliases.c
+++ b/clownfish/src/CFCBindAliases.c
@@ -102,6 +102,7 @@ struct alias aliases[] = {
     {"cfish_VTable_add_to_registry", "lucy_VTable_add_to_registry"},
     {"cfish_VTable_add_alias_to_registry", 
"lucy_VTable_add_alias_to_registry"},
     {"cfish_VTable_offset_of_parent", "lucy_VTable_offset_of_parent"},
+    {"cfish_VTable_offset_of_methods", "lucy_VTable_offset_of_methods"},
     {"cfish_VTable_singleton", "lucy_VTable_singleton"},
     {"Cfish_VTable_Get_Name", "Lucy_VTable_Get_Name"},
     {"Cfish_VTable_Make_Obj", "Lucy_VTable_Make_Obj"},
diff --git a/clownfish/src/CFCBindClass.c b/clownfish/src/CFCBindClass.c
index e1302cf..10136fe 100644
--- a/clownfish/src/CFCBindClass.c
+++ b/clownfish/src/CFCBindClass.c
@@ -58,6 +58,10 @@ S_vtable_definition(CFCBindClass *self);
 static char*
 S_callback_declarations(CFCBindClass *self);
 
+// Define method numbers.
+static char*
+S_method_num_defs(CFCBindClass *self);
+
 // Declare typedefs for fresh methods, to ease casting.
 static char*
 S_method_typedefs(CFCBindClass *self);
@@ -187,6 +191,7 @@ S_to_c_header_dynamic(CFCBindClass *self) {
     char *parent_include        = S_parent_include(self);
     char *sub_declarations      = S_sub_declarations(self);
     char *inert_var_defs        = S_inert_var_declarations(self);
+    char *method_num_defs       = S_method_num_defs(self);
     char *method_typedefs       = S_method_typedefs(self);
     char *method_defs           = S_method_defs(self);
     char *callback_declarations = S_callback_declarations(self);
@@ -225,6 +230,11 @@ S_to_c_header_dynamic(CFCBindClass *self) {
         "\n"
         "%s\n"
         "\n"
+        "/* Define method numbers.\n"
+        " */\n"
+        "\n"
+        "%s\n"
+        "\n"
         "/* Define typedefs for each dynamic method, allowing us to cast 
generic\n"
         " * pointers to the appropriate function pointer type more cleanly.\n"
         " */\n"
@@ -255,6 +265,7 @@ S_to_c_header_dynamic(CFCBindClass *self) {
                   + strlen(inert_var_defs)
                   + strlen(sub_declarations)
                   + strlen(callback_declarations)
+                  + strlen(method_num_defs)
                   + strlen(method_typedefs)
                   + strlen(method_defs)
                   + strlen(vt_var)
@@ -264,13 +275,14 @@ S_to_c_header_dynamic(CFCBindClass *self) {
     char *content = (char*)MALLOCATE(size);
     sprintf(content, pattern, parent_include, privacy_symbol, struct_def,
             privacy_symbol, inert_var_defs, sub_declarations,
-            callback_declarations, method_typedefs, method_defs,
-            vt_var, short_names);
+            callback_declarations, method_num_defs, method_typedefs,
+            method_defs, vt_var, short_names);
 
     FREEMEM(struct_def);
     FREEMEM(parent_include);
     FREEMEM(sub_declarations);
     FREEMEM(inert_var_defs);
+    FREEMEM(method_num_defs);
     FREEMEM(method_typedefs);
     FREEMEM(method_defs);
     FREEMEM(callback_declarations);
@@ -294,7 +306,6 @@ CFCBindClass_to_c_data(CFCBindClass *self) {
     CFCMethod **methods  = CFCClass_methods(client);
     CFCMethod **fresh_methods = CFCClass_fresh_methods(client);
 
-    char *offsets    = CFCUtil_strdup("");
     char *cb_funcs   = CFCUtil_strdup("");
     char *cb_objects = CFCUtil_strdup("");
 
@@ -313,23 +324,6 @@ CFCBindClass_to_c_data(CFCBindClass *self) {
     for (int meth_num = 0; methods[meth_num] != NULL; meth_num++) {
         CFCMethod *method = methods[meth_num];
         int method_is_fresh = S_method_is_fresh(method, fresh_methods);
-        size_t off_sym_size 
-            = CFCMethod_full_offset_sym(method, cnick, NULL, 0);
-        char *full_offset_sym = (char*)MALLOCATE(off_sym_size);
-        CFCMethod_full_offset_sym(method, cnick, full_offset_sym,
-                                  off_sym_size);
-        char meth_num_str[20];
-        sprintf(meth_num_str, "%d", meth_num);
-
-        // Create offset in bytes for the method from the top of the VTable
-        // object.
-        char *offset_str = CFCUtil_cat(CFCUtil_strdup(""),
-                                       "(offsetof(cfish_VTable, methods) + ",
-                                       meth_num_str,
-                                       " * sizeof(cfish_method_t))", NULL);
-        offsets = CFCUtil_cat(offsets, "size_t ", full_offset_sym, " = ",
-                              offset_str, ";\n", NULL);
-        FREEMEM(full_offset_sym);
 
         // Create a default implementation for abstract methods.
         if (method_is_fresh && CFCMethod_abstract(method)) {
@@ -342,10 +336,9 @@ CFCBindClass_to_c_data(CFCBindClass *self) {
         // host.
         if (CFCMethod_public(method) || CFCMethod_abstract(method)) {
             if (method_is_fresh && CFCMethod_novel(method)) {
-                char *cb_def = CFCBindMeth_callback_def(method);
-                char *cb_obj_def
-                    = CFCBindMeth_callback_obj_def(method, offset_str);
-                cb_funcs = CFCUtil_cat(cb_funcs, cb_def, "\n", NULL);
+                char *cb_def     = CFCBindMeth_callback_def(method);
+                char *cb_obj_def = CFCBindMeth_callback_obj_def(method, 
client);
+                cb_funcs   = CFCUtil_cat(cb_funcs, cb_def, "\n", NULL);
                 cb_objects = CFCUtil_cat(cb_objects, cb_obj_def, NULL);
                 FREEMEM(cb_def);
                 FREEMEM(cb_obj_def);
@@ -361,8 +354,6 @@ CFCBindClass_to_c_data(CFCBindClass *self) {
         const char *implementing_sym = CFCMethod_implementing_func_sym(method);
         method_var = CFCUtil_cat(method_var, "(cfish_method_t)",
                                  implementing_sym, ",\n    ", NULL);
-
-        FREEMEM(offset_str);
     }
 
     // Close callbacks variable definition.
@@ -373,12 +364,6 @@ CFCBindClass_to_c_data(CFCBindClass *self) {
     const char pattern[] =
         "#include \"%s\"\n"
         "\n"
-        "/* Offsets for method pointers, measured in bytes, from the top\n"
-        " * of this class's vtable.\n"
-        " */\n"
-        "\n"
-        "%s\n"
-        "\n"
         "/* Define functions which implement host callbacks for the methods\n"
         " * of this class which can be overridden via the host.\n"
         " */\n"
@@ -414,7 +399,6 @@ CFCBindClass_to_c_data(CFCBindClass *self) {
         "\n";
     size_t size = sizeof(pattern)
                   + strlen(include_h)
-                  + strlen(offsets)
                   + strlen(cb_funcs)
                   + strlen(cb_objects)
                   + strlen(cb_var)
@@ -423,12 +407,11 @@ CFCBindClass_to_c_data(CFCBindClass *self) {
                   + strlen(autocode)
                   + 100;
     char *code = (char*)MALLOCATE(size);
-    sprintf(code, pattern, include_h, offsets, cb_funcs, cb_objects, cb_var,
+    sprintf(code, pattern, include_h, cb_funcs, cb_objects, cb_var,
             method_var, vt_var, autocode);
 
     FREEMEM(method_var);
     FREEMEM(fresh_methods);
-    FREEMEM(offsets);
     FREEMEM(cb_funcs);
     FREEMEM(cb_objects);
     FREEMEM(cb_var);
@@ -576,6 +559,26 @@ S_callback_declarations(CFCBindClass *self) {
     return declarations;
 }
 
+// Create #defines for method numbers.
+static char*
+S_method_num_defs(CFCBindClass *self) {
+    const char *cnick = CFCClass_get_cnick(self->client);
+    CFCMethod **methods = CFCClass_methods(self->client);
+    char *method_num_defs = CFCUtil_strdup("");
+    for (int i = 0; methods[i] != NULL; i++) {
+        CFCMethod *method = methods[i];
+        size_t num_define_size = CFCMethod_num_define(method, cnick, NULL, 0);
+        char *num_define = (char*)MALLOCATE(num_define_size);
+        CFCMethod_num_define(method, cnick, num_define, num_define_size);
+        char method_num_str[20];
+        sprintf(method_num_str, "%d", i);
+        method_num_defs = CFCUtil_cat(method_num_defs, "#define ", num_define,
+                                      " ", method_num_str, "\n", NULL);
+        FREEMEM(num_define);
+    }
+    return method_num_defs;
+}
+
 // Declare typedefs for every fresh method implementation, to ease casting.
 static char*
 S_method_typedefs(CFCBindClass *self) {
diff --git a/clownfish/src/CFCBindCore.c b/clownfish/src/CFCBindCore.c
index f5c2117..4bddf94 100644
--- a/clownfish/src/CFCBindCore.c
+++ b/clownfish/src/CFCBindCore.c
@@ -176,12 +176,15 @@ S_write_parcel_h(CFCBindCore *self) {
         " */\n"
         "#define %sMETHOD(_vtable, _class_nick, _meth_name) \\\n"
         "     cfish_method(_vtable, \\\n"
-        "     %s ## _class_nick ## _ ## _meth_name ## _OFFSET)\n"
+        "     %s ## _class_nick ## _ ## _meth_name ## _NUM)\n"
         "\n"
+        "extern size_t cfish_VTable_offset_of_methods;\n"
         "static CHY_INLINE cfish_method_t\n"
-        "cfish_method(const void *vtable, size_t offset) {\n"
+        "cfish_method(const void *vtable, size_t method_num) {\n"
         "    union { char *cptr; cfish_method_t *fptr; } ptr;\n"
-        "    ptr.cptr = (char*)vtable + offset;\n"
+        "    ptr.cptr = (char*)vtable\n"
+        "               + cfish_VTable_offset_of_methods\n"
+        "               + method_num * sizeof(cfish_method_t);\n"
         "    return ptr.fptr[0];\n"
         "}\n"
         "\n"
@@ -189,22 +192,22 @@ S_write_parcel_h(CFCBindCore *self) {
         " * vtable. */\n"
         "#define %sSUPER_METHOD(_vtable, _class_nick, _meth_name) \\\n"
         "     cfish_super_method(_vtable, \\\n"
-        "     %s ## _class_nick ## _ ## _meth_name ## _OFFSET)\n"
+        "     %s ## _class_nick ## _ ## _meth_name ## _NUM)\n"
         "\n"
         "extern size_t cfish_VTable_offset_of_parent;\n"
         "static CHY_INLINE cfish_method_t\n"
-        "cfish_super_method(const void *vtable, size_t offset) {\n"
+        "cfish_super_method(const void *vtable, size_t method_num) {\n"
         "    char *vt_as_char = (char*)vtable;\n"
         "    cfish_VTable **parent_ptr\n"
         "        = (cfish_VTable**)(vt_as_char + 
cfish_VTable_offset_of_parent);\n"
-        "    return cfish_method(*parent_ptr, offset);\n"
+        "    return cfish_method(*parent_ptr, method_num);\n"
         "}\n"
         "\n"
         "/* Return a boolean indicating whether a method has been 
overridden.\n"
         " */\n"
         "#define %sOVERRIDDEN(_self, _class_nick, _meth_name, _micro_name) 
\\\n"
         "        (cfish_method(*((cfish_VTable**)_self), \\\n"
-        "            %s ## _class_nick ## _ ## _meth_name ## _OFFSET )\\\n"
+        "            %s ## _class_nick ## _ ## _meth_name ## _NUM )\\\n"
         "            != (cfish_method_t)%s ## _class_nick ## _ ## _micro_name 
)\n"
         "\n"
         "#ifdef CFISH_USE_SHORT_NAMES\n"
@@ -217,7 +220,7 @@ S_write_parcel_h(CFCBindCore *self) {
         "    const char    *name;\n"
         "    size_t         name_len;\n"
         "    cfish_method_t func;\n"
-        "    size_t         offset;\n"
+        "    size_t         method_num;\n"
         "} cfish_Callback;\n"
         "\n"
         "void\n"
diff --git a/clownfish/src/CFCBindMethod.c b/clownfish/src/CFCBindMethod.c
index 6679997..b263519 100644
--- a/clownfish/src/CFCBindMethod.c
+++ b/clownfish/src/CFCBindMethod.c
@@ -140,9 +140,9 @@ S_virtual_method_def(CFCMethod *method, CFCClass *klass) {
     char *full_meth_sym = (char*)MALLOCATE(meth_sym_size);
     CFCMethod_full_method_sym(method, cnick, full_meth_sym, meth_sym_size);
 
-    size_t offset_sym_size = CFCMethod_full_offset_sym(method, cnick, NULL, 0);
-    char *full_offset_sym = (char*)MALLOCATE(offset_sym_size);
-    CFCMethod_full_offset_sym(method, cnick, full_offset_sym, offset_sym_size);
+    size_t num_define_size = CFCMethod_num_define(method, cnick, NULL, 0);
+    char *num_define = (char*)MALLOCATE(num_define_size);
+    CFCMethod_num_define(method, cnick, num_define, num_define_size);
 
     // Prepare parameter lists, minus invoker.  The invoker gets forced to
     // "self" later.
@@ -161,21 +161,21 @@ S_virtual_method_def(CFCMethod *method, CFCClass *klass) {
     const char *maybe_return = CFCType_is_void(return_type) ? "" : "return ";
 
     const char pattern[] =
-        "extern size_t %s;\n"
         "static CHY_INLINE %s\n"
         "%s(const %s *self%s) {\n"
-        "    char *const method_address = *(char**)self + %s;\n"
+        "    char *const method_address = *(char**)self\n"
+        "                                 + cfish_VTable_offset_of_methods\n"
+        "                                 + %s * sizeof(cfish_method_t);\n"
         "    const %s method = *((%s*)method_address);\n"
         "    %smethod((%s*)self%s);\n"
         "}\n";
 
     size_t size = sizeof(pattern)
-                  + strlen(full_offset_sym)
                   + strlen(ret_type_str)
                   + strlen(full_meth_sym)
                   + strlen(invoker_struct)
                   + strlen(params_minus_invoker)
-                  + strlen(full_offset_sym)
+                  + strlen(num_define)
                   + strlen(typedef_str)
                   + strlen(typedef_str)
                   + strlen(maybe_return)
@@ -183,12 +183,11 @@ S_virtual_method_def(CFCMethod *method, CFCClass *klass) {
                   + strlen(arg_names_minus_invoker)
                   + 40;
     char *method_def = (char*)MALLOCATE(size);
-    sprintf(method_def, pattern, full_offset_sym, ret_type_str,
-            full_meth_sym, invoker_struct, params_minus_invoker,
-            full_offset_sym, typedef_str, typedef_str, maybe_return,
-            common_struct, arg_names_minus_invoker);
+    sprintf(method_def, pattern, ret_type_str, full_meth_sym, invoker_struct,
+            params_minus_invoker, num_define, typedef_str, typedef_str,
+            maybe_return, common_struct, arg_names_minus_invoker);
 
-    FREEMEM(full_offset_sym);
+    FREEMEM(num_define);
     FREEMEM(full_meth_sym);
     return method_def;
 }
@@ -218,22 +217,30 @@ CFCBindMeth_callback_dec(CFCMethod *method) {
 }
 
 char*
-CFCBindMeth_callback_obj_def(CFCMethod *method, const char *offset) {
+CFCBindMeth_callback_obj_def(CFCMethod *method, CFCClass *klass) {
+    const char *cnick             = CFCClass_get_cnick(klass);
     const char *macro_sym         = CFCMethod_get_macro_sym(method);
     unsigned    macro_sym_len     = strlen(macro_sym);
     const char *full_override_sym = CFCMethod_full_override_sym(method);
     const char *full_callback_sym = CFCMethod_full_callback_sym(method);
+
+    size_t num_define_size = CFCMethod_num_define(method, cnick, NULL, 0);
+    char *num_define = (char*)MALLOCATE(num_define_size);
+    CFCMethod_num_define(method, cnick, num_define, num_define_size);
+
     char pattern[] =
         "cfish_Callback %s = {\"%s\", %u, (cfish_method_t)%s, %s};\n";
     size_t size = sizeof(pattern)
                   + macro_sym_len
                   + strlen(full_override_sym)
                   + strlen(full_callback_sym)
-                  + strlen(offset)
+                  + strlen(num_define)
                   + 30;
     char *def = (char*)MALLOCATE(size);
     sprintf(def, pattern, full_callback_sym, macro_sym, macro_sym_len,
-            full_override_sym, offset);
+            full_override_sym, num_define);
+
+    FREEMEM(num_define);
     return def;
 }
 
diff --git a/clownfish/src/CFCBindMethod.h b/clownfish/src/CFCBindMethod.h
index 2283f87..d5e9612 100644
--- a/clownfish/src/CFCBindMethod.h
+++ b/clownfish/src/CFCBindMethod.h
@@ -53,7 +53,7 @@ CFCBindMeth_callback_dec(struct CFCMethod *method);
  * introspection data and a pointer to the callback function.
  */
 char*
-CFCBindMeth_callback_obj_def(struct CFCMethod *method, const char* offset);
+CFCBindMeth_callback_obj_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
diff --git a/clownfish/src/CFCMethod.c b/clownfish/src/CFCMethod.c
index 864196c..bd6982e 100644
--- a/clownfish/src/CFCMethod.c
+++ b/clownfish/src/CFCMethod.c
@@ -271,14 +271,14 @@ CFCMethod_full_method_sym(CFCMethod *self, const char 
*invoker, char *buf,
 }
 
 size_t
-CFCMethod_full_offset_sym(CFCMethod *self, const char *invoker, char *buf,
-                          size_t buf_size) {
+CFCMethod_num_define(CFCMethod *self, const char *invoker, char *buf,
+                     size_t buf_size) {
     CFCUTIL_NULL_CHECK(invoker);
     size_t needed = CFCMethod_full_method_sym(self, invoker, NULL, 0)
-                    + strlen("_OFFSET");
+                    + strlen("_NUM");
     if (buf_size >= needed) {
         CFCMethod_full_method_sym(self, invoker, buf, buf_size);
-        strcat(buf, "_OFFSET");
+        strcat(buf, "_NUM");
     }
     return needed;
 }
diff --git a/clownfish/src/CFCMethod.h b/clownfish/src/CFCMethod.h
index cecbaf0..23d1347 100644
--- a/clownfish/src/CFCMethod.h
+++ b/clownfish/src/CFCMethod.h
@@ -123,14 +123,14 @@ size_t
 CFCMethod_full_method_sym(CFCMethod *self, const char *invoker, char *buf,
                           size_t buf_size);
 
-/** Create the fully qualified name of the variable which stores the method's
- * vtable offset, e.g. "crust_LobClaw_pinch_OFFSET".
+/** Create the name of the #define which contains the method's position
+ * in the vtable, e.g. "Crust_LobClaw_Pinch_NUM".
  *
- * @return the number of bytes which the symbol would occupy.
+ * @return the number of bytes which the name would occupy.
  */
 size_t
-CFCMethod_full_offset_sym(CFCMethod *self, const char *invoker, char *buf,
-                          size_t buf_size);
+CFCMethod_num_define(CFCMethod *self, const char *invoker, char *buf,
+                     size_t buf_size);
 
 const char*
 CFCMethod_get_macro_sym(CFCMethod *self);
diff --git a/core/Lucy/Object/Obj.cfh b/core/Lucy/Object/Obj.cfh
index 473d609..01f4b43 100644
--- a/core/Lucy/Object/Obj.cfh
+++ b/core/Lucy/Object/Obj.cfh
@@ -191,8 +191,7 @@ __C__
 static CHY_INLINE void
 lucy_Obj_super_destroy(lucy_Obj *self, lucy_VTable *vtable) {
     lucy_Obj_destroy_t super_destroy
-        = (lucy_Obj_destroy_t)cfish_super_method(vtable,
-                                                 Lucy_Obj_Destroy_OFFSET);
+        = (lucy_Obj_destroy_t)cfish_super_method(vtable, Lucy_Obj_Destroy_NUM);
     super_destroy(self);
 }
 
diff --git a/core/Lucy/Object/VTable.c b/core/Lucy/Object/VTable.c
index b5a81a2..8e8b9dc 100644
--- a/core/Lucy/Object/VTable.c
+++ b/core/Lucy/Object/VTable.c
@@ -33,7 +33,8 @@
 #include "Lucy/Util/Atomic.h"
 #include "Lucy/Util/Memory.h"
 
-size_t VTable_offset_of_parent = offsetof(VTable, parent);
+size_t VTable_offset_of_parent  = offsetof(VTable, parent);
+size_t VTable_offset_of_methods = offsetof(VTable, methods);
 
 // Remove spaces and underscores, convert to lower case.
 static void
@@ -43,7 +44,7 @@ LockFreeRegistry *VTable_registry = NULL;
 
 VTable*
 VTable_allocate(size_t num_methods) {
-    size_t vt_alloc_size = offsetof(cfish_VTable, methods)
+    size_t vt_alloc_size = VTable_offset_of_methods
                            + num_methods * sizeof(cfish_method_t);
     VTable *self = (VTable*)Memory_wrapped_calloc(vt_alloc_size, 1);
     self->vt_alloc_size = vt_alloc_size;
@@ -129,10 +130,8 @@ VTable_get_refcount(VTable *self) {
 }
 
 void
-VTable_override(VTable *self, lucy_method_t method, size_t offset) {
-    union { char *char_ptr; lucy_method_t *func_ptr; } pointer;
-    pointer.char_ptr = ((char*)self) + offset;
-    pointer.func_ptr[0] = method;
+VTable_override(VTable *self, lucy_method_t method, size_t method_num) {
+    self->methods[method_num] = method;
 }
 
 CharBuf*
@@ -213,7 +212,7 @@ VTable_singleton(const CharBuf *class_name, VTable *parent) 
{
                 S_scrunch_charbuf((CharBuf*)callback_name, scrunched);
                 if (Hash_Fetch(meths, (Obj*)scrunched)) {
                     VTable_Override(singleton, callback->func,
-                                    callback->offset);
+                                    callback->method_num);
                 }
             }
             DECREF(scrunched);
diff --git a/core/Lucy/Object/VTable.cfh b/core/Lucy/Object/VTable.cfh
index 7734c95..4cd2298 100644
--- a/core/Lucy/Object/VTable.cfh
+++ b/core/Lucy/Object/VTable.cfh
@@ -36,6 +36,7 @@ class Lucy::Object::VTable inherits Lucy::Object::Obj {
 
     inert LockFreeRegistry *registry;
     inert size_t offset_of_parent;
+    inert size_t offset_of_methods;
 
     inert VTable*
     allocate(size_t num_methods);
diff --git a/core/Lucy/Test/Store/TestFileHandle.c 
b/core/Lucy/Test/Store/TestFileHandle.c
index 14aa1e3..8878a38 100644
--- a/core/Lucy/Test/Store/TestFileHandle.c
+++ b/core/Lucy/Test/Store/TestFileHandle.c
@@ -37,7 +37,7 @@ S_new_filehandle() {
     if (!vtable) {
         vtable = VTable_singleton((CharBuf*)klass, FILEHANDLE);
     }
-    VTable_Override(vtable, S_no_op_method, Lucy_FH_Close_OFFSET);
+    VTable_Override(vtable, S_no_op_method, Lucy_FH_Close_NUM);
     fh = (FileHandle*)VTable_Make_Obj(vtable);
     return FH_do_open(fh, NULL, 0);
 }
-- 
1.7.10

Reply via email to