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 2015/07/27 18:35:29 UTC

[1/4] lucy-clownfish git commit: Don't allow to subclass final classes

Repository: lucy-clownfish
Updated Branches:
  refs/heads/master 8bfda8334 -> 5e2478048


Don't allow to subclass final classes

Fixes CLOWNFISH-45.


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

Branch: refs/heads/master
Commit: 5e2478048ffc5062dc0a191087e6dfb1e5b87f57
Parents: 5c7144b
Author: Nick Wellnhofer <we...@aevum.de>
Authored: Fri Jul 24 14:50:36 2015 +0200
Committer: Nick Wellnhofer <we...@aevum.de>
Committed: Mon Jul 27 18:26:18 2015 +0200

----------------------------------------------------------------------
 compiler/src/CFCBindCore.c       |  1 +
 compiler/src/CFCBindSpecs.c      | 12 ++++++++++--
 runtime/core/Clownfish/Class.c   |  7 +++++++
 runtime/perl/t/binding/019-obj.t |  9 ++++++++-
 4 files changed, 26 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/5e247804/compiler/src/CFCBindCore.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCBindCore.c b/compiler/src/CFCBindCore.c
index d5f59d7..ce0f9f7 100644
--- a/compiler/src/CFCBindCore.c
+++ b/compiler/src/CFCBindCore.c
@@ -299,6 +299,7 @@ S_write_parcel_h(CFCBindCore *self, CFCParcel *parcel) {
         "\n"
         "/* Flags for internal use. */\n"
         "#define CFISH_fREFCOUNTSPECIAL 0x00000001\n"
+        "#define CFISH_fFINAL           0x00000002\n"
         ;
     const char *cfish_defs_2 =
         "#ifdef CFISH_USE_SHORT_NAMES\n"

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/5e247804/compiler/src/CFCBindSpecs.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCBindSpecs.c b/compiler/src/CFCBindSpecs.c
index f3b377d..4db517b 100644
--- a/compiler/src/CFCBindSpecs.c
+++ b/compiler/src/CFCBindSpecs.c
@@ -116,6 +116,10 @@ CFCBindSpecs_get_typedefs() {
         "    size_t *parent_offset;\n"
         "} cfish_InheritedMethSpec;\n"
         "\n"
+        "typedef enum {\n"
+        "    cfish_ClassSpec_FINAL = 1\n"
+        "} cfish_ClassSpecFlags;\n"
+        "\n"
         "typedef struct cfish_ClassSpec {\n"
         "    cfish_Class **klass;\n"
         "    cfish_Class **parent;\n"
@@ -125,6 +129,7 @@ CFCBindSpecs_get_typedefs() {
         "    uint32_t      num_novel_meths;\n"
         "    uint32_t      num_overridden_meths;\n"
         "    uint32_t      num_inherited_meths;\n"
+        "    uint32_t      flags;\n"
         "} cfish_ClassSpec;\n"
         "\n";
 }
@@ -137,6 +142,8 @@ CFCBindSpecs_add_class(CFCBindSpecs *self, CFCClass *klass) {
     const char *class_var         = CFCClass_full_class_var(klass);
     const char *ivars_offset_name = CFCClass_full_ivars_offset(klass);
 
+    const char *flags = CFCClass_final(klass) ? "cfish_ClassSpec_FINAL" : "0";
+
     char *ivars_size = S_ivars_size(klass);
 
     char *parent_ptr = NULL;
@@ -200,12 +207,13 @@ CFCBindSpecs_add_class(CFCBindSpecs *self, CFCClass *klass) {
         "        &%s, /* ivars_offset_ptr */\n"
         "        %d, /* num_novel */\n"
         "        %d, /* num_overridden */\n"
-        "        %d /* num_inherited */\n"
+        "        %d, /* num_inherited */\n"
+        "        %s /* flags */\n"
         "    }";
     char *class_spec
         = CFCUtil_sprintf(pattern, class_var, parent_ptr, class_name,
                           ivars_size, ivars_offset_name, num_new_novel,
-                          num_new_overridden, num_new_inherited);
+                          num_new_overridden, num_new_inherited, flags);
 
     const char *sep = self->num_specs == 0 ? "" : ",\n";
     self->class_specs = CFCUtil_cat(self->class_specs, sep, class_spec, NULL);

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/5e247804/runtime/core/Clownfish/Class.c
----------------------------------------------------------------------
diff --git a/runtime/core/Clownfish/Class.c b/runtime/core/Clownfish/Class.c
index 474e8a2..5f30de2 100644
--- a/runtime/core/Clownfish/Class.c
+++ b/runtime/core/Clownfish/Class.c
@@ -155,6 +155,9 @@ Class_bootstrap(const cfish_ClassSpec *specs, size_t num_specs,
            ) {
             klass->flags |= CFISH_fREFCOUNTSPECIAL;
         }
+        if (spec->flags & cfish_ClassSpec_FINAL) {
+            klass->flags |= CFISH_fFINAL;
+        }
 
         if (parent) {
             // Copy parent vtable.
@@ -266,6 +269,10 @@ Class_init_registry() {
 
 static Class*
 S_simple_subclass(Class *parent, String *name) {
+    if (parent->flags & CFISH_fFINAL) {
+        THROW(ERR, "Can't subclass final class %o", Class_Get_Name(parent));
+    }
+
     Class *subclass
         = (Class*)Memory_wrapped_calloc(parent->class_alloc_size, 1);
     Class_Init_Obj(parent->klass, subclass);

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/5e247804/runtime/perl/t/binding/019-obj.t
----------------------------------------------------------------------
diff --git a/runtime/perl/t/binding/019-obj.t b/runtime/perl/t/binding/019-obj.t
index 5de41df..545b235 100644
--- a/runtime/perl/t/binding/019-obj.t
+++ b/runtime/perl/t/binding/019-obj.t
@@ -16,7 +16,7 @@
 use strict;
 use warnings;
 
-use Test::More tests => 24;
+use Test::More tests => 25;
 
 package TestObj;
 use base qw( Clownfish::Obj );
@@ -57,6 +57,9 @@ use base qw( Clownfish::Test::AliasTestObj );
     sub perl_alias {"Perl"}
 }
 
+package SubclassFinalTestObj;
+use base qw( Clownfish::Vector );
+
 package main;
 use Storable qw( freeze thaw );
 use Clownfish::Test;
@@ -152,3 +155,7 @@ my $overridden_alias_test = OverriddenAliasTestObj->new;
 is( $overridden_alias_test->call_aliased_from_c, 'Perl',
     'Overriding aliased methods works' );
 
+eval { SubclassFinalTestObj->new; };
+like( $@, qr/Can't subclass final class Clownfish::Vector/,
+      "Final class can't be subclassed" );
+


[4/4] lucy-clownfish git commit: CFCBindSpecs class

Posted by nw...@apache.org.
CFCBindSpecs class

Handle ClassSpecs and MethSpecs in a single place.


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

Branch: refs/heads/master
Commit: 2b3ed29a7cf05fd1c0ae6b23482cadcf445dbf03
Parents: 8bfda83
Author: Nick Wellnhofer <we...@aevum.de>
Authored: Thu Jul 23 19:51:01 2015 +0200
Committer: Nick Wellnhofer <we...@aevum.de>
Committed: Mon Jul 27 18:26:18 2015 +0200

----------------------------------------------------------------------
 compiler/include/CFC.h             |   1 +
 compiler/perl/lib/Clownfish/CFC.xs |  24 --
 compiler/src/CFCBindClass.c        | 205 +---------------
 compiler/src/CFCBindClass.h        |   5 -
 compiler/src/CFCBindCore.c         |  89 +++----
 compiler/src/CFCBindMethod.c       |  75 ------
 compiler/src/CFCBindMethod.h       |  20 --
 compiler/src/CFCBindSpecs.c        | 419 ++++++++++++++++++++++++++++++++
 compiler/src/CFCBindSpecs.h        |  58 +++++
 compiler/src/CFCClass.c            |  18 ++
 compiler/src/CFCClass.h            |   6 +
 11 files changed, 534 insertions(+), 386 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/2b3ed29a/compiler/include/CFC.h
----------------------------------------------------------------------
diff --git a/compiler/include/CFC.h b/compiler/include/CFC.h
index e57c873..9d1c222 100644
--- a/compiler/include/CFC.h
+++ b/compiler/include/CFC.h
@@ -44,6 +44,7 @@
 #include "CFCBindFile.h"
 #include "CFCBindFunction.h"
 #include "CFCBindMethod.h"
+#include "CFCBindSpecs.h"
 
 #include "CFCGo.h"
 #include "CFCGoClass.h"

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/2b3ed29a/compiler/perl/lib/Clownfish/CFC.xs
----------------------------------------------------------------------
diff --git a/compiler/perl/lib/Clownfish/CFC.xs b/compiler/perl/lib/Clownfish/CFC.xs
index d9e28bf..c779c5b 100644
--- a/compiler/perl/lib/Clownfish/CFC.xs
+++ b/compiler/perl/lib/Clownfish/CFC.xs
@@ -1908,30 +1908,6 @@ CODE:
     RETVAL = S_sv_eat_c_string(CFCBindMeth_method_def(meth, klass));
 OUTPUT: RETVAL
 
-SV*
-_novel_spec_def(meth, klass)
-    CFCMethod *meth;
-    CFCClass  *klass;
-CODE:
-    RETVAL = S_sv_eat_c_string(CFCBindMeth_novel_spec_def(meth, klass));
-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
 
 SV*

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/2b3ed29a/compiler/src/CFCBindClass.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCBindClass.c b/compiler/src/CFCBindClass.c
index d1cebf6..f19a174 100644
--- a/compiler/src/CFCBindClass.c
+++ b/compiler/src/CFCBindClass.c
@@ -45,11 +45,6 @@ S_to_c_header_inert(CFCBindClass *self);
 static char*
 S_to_c_header_dynamic(CFCBindClass *self);
 
-// Count the number of member variables declared in ancestor classes
-// outside this package.
-static int
-S_count_non_package_members(CFCBindClass *self);
-
 // Create the definition for the instantiable object struct.
 static char*
 S_struct_definition(CFCBindClass *self);
@@ -286,16 +281,12 @@ CFCBindClass_to_c_data(CFCBindClass *self) {
     }
 
     const char *ivars_offset = CFCClass_full_ivars_offset(client);
-
     const char *class_var    = CFCClass_full_class_var(client);
 
     CFCMethod **methods  = CFCClass_methods(client);
 
     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];
@@ -314,69 +305,6 @@ CFCBindClass_to_c_data(CFCBindClass *self) {
             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
-                // ClassSpec struct.
-                novel_ms_var
-                    = CFCUtil_cat(novel_ms_var,
-                                  "static const cfish_NovelMethSpec ",
-                                  class_var, "_NOVEL_METHS[] = {\n", NULL);
-            }
-            else {
-                novel_ms_var = CFCUtil_cat(novel_ms_var, ",\n", NULL);
-            }
-            char *ms_def = CFCBindMeth_novel_spec_def(method, client);
-            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 const cfish_OverriddenMethSpec ",
-                                  class_var, "_OVERRIDDEN_METHS[] = {\n",
-                                  NULL);
-            }
-            else {
-                overridden_ms_var
-                    = CFCUtil_cat(overridden_ms_var, ",\n", 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 const cfish_InheritedMethSpec ",
-                                  class_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 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[] =
@@ -397,12 +325,6 @@ CFCBindClass_to_c_data(CFCBindClass *self) {
         "\n"
         "%s\n"
         "\n"
-        "/* Define the MethSpec structs used during Class initialization.\n"
-        " */\n"
-        "\n"
-        "%s"
-        "%s"
-        "%s"
         "/* Define the pointer to the Class singleton object.\n"
         " */\n"
         "\n"
@@ -410,36 +332,13 @@ CFCBindClass_to_c_data(CFCBindClass *self) {
         "\n";
     char *code
         = CFCUtil_sprintf(pattern, ivars_offset, offsets, method_defs,
-                          novel_ms_var, overridden_ms_var, inherited_ms_var,
                           class_var);
 
     FREEMEM(offsets);
     FREEMEM(method_defs);
-    FREEMEM(novel_ms_var);
-    FREEMEM(overridden_ms_var);
-    FREEMEM(inherited_ms_var);
     return code;
 }
 
-// Count the number of member variables declared in ancestor classes
-// outside this package.
-static int
-S_count_non_package_members(CFCBindClass *self) {
-    CFCClass  *const client = self->client;
-    CFCParcel *parcel       = CFCClass_get_parcel(client);
-    CFCClass  *ancestor     = CFCClass_get_parent(client);
-    int num_non_package_members = 0;
-
-    while (ancestor && CFCClass_get_parcel(ancestor) == parcel) {
-        ancestor = CFCClass_get_parent(ancestor);
-    }
-    if (ancestor) {
-        num_non_package_members = CFCClass_num_member_vars(ancestor);
-    }
-
-    return num_non_package_members;
-}
-
 // Create the definition for the instantiable object struct.
 static char*
 S_struct_definition(CFCBindClass *self) {
@@ -458,7 +357,7 @@ S_struct_definition(CFCBindClass *self) {
 
     // Add all member variables declared by classes in this package.
     CFCVariable **member_vars = CFCClass_member_vars(client);
-    int num_non_package_members = S_count_non_package_members(self);
+    int num_non_package_members = CFCClass_num_non_package_ivars(client);
     for (int i = num_non_package_members; member_vars[i] != NULL; i++) {
         const char *member_dec = CFCVariable_local_declaration(member_vars[i]);
         member_decs = CFCUtil_cat(member_decs, "\n    ", member_dec, NULL);
@@ -479,108 +378,6 @@ S_struct_definition(CFCBindClass *self) {
     return struct_def;
 }
 
-// Return C definition of the class's ClassSpec.
-char*
-CFCBindClass_spec_def(CFCBindClass *self) {
-    CFCClass *client = self->client;
-
-    CFCParcel  *parcel       = CFCClass_get_parcel(client);
-    CFCClass   *parent       = CFCClass_get_parent(client);
-    const char *class_name   = CFCClass_get_name(client);
-    const char *class_var    = CFCClass_full_class_var(client);
-    const char *struct_sym   = CFCClass_full_struct_sym(client);
-    const char *ivars_struct = CFCClass_full_ivars_struct(client);
-
-    // Create a pointer to the parent Class object.
-    char *parent_ref;
-    if (parent) {
-        parent_ref = CFCUtil_sprintf("&%s", CFCClass_full_class_var(parent));
-    }
-    else {
-        // No parent, e.g. Obj or inert classes.
-        parent_ref = CFCUtil_strdup("NULL");
-    }
-
-    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];
-
-        if (CFCMethod_is_fresh(method, client)) {
-            if (CFCMethod_novel(method)) {
-                ++num_novel;
-            }
-            else {
-                ++num_overridden;
-            }
-        }
-        else {
-            ++num_inherited;
-        }
-    }
-
-    char *novel_ms_var      = num_novel
-                              ? CFCUtil_sprintf("%s_NOVEL_METHS", class_var)
-                              : CFCUtil_strdup("NULL");
-    char *overridden_ms_var = num_overridden
-                              ? CFCUtil_sprintf("%s_OVERRIDDEN_METHS",
-                                                class_var)
-                              : CFCUtil_strdup("NULL");
-    char *inherited_ms_var  = num_inherited
-                              ? CFCUtil_sprintf("%s_INHERITED_METHS",
-                                                class_var)
-                              : CFCUtil_strdup("NULL");
-
-    char *ivars_size = NULL;
-
-    if (CFCParcel_is_cfish(parcel)) {
-        ivars_size = CFCUtil_sprintf("sizeof(%s)", struct_sym);
-    }
-    else {
-        int num_non_package_members = S_count_non_package_members(self);
-        int num_members             = CFCClass_num_member_vars(client);
-
-        if (num_non_package_members == num_members) {
-            // No members in this package.
-            ivars_size = CFCUtil_strdup("0");
-        }
-        else {
-            ivars_size = CFCUtil_sprintf("sizeof(%s)", ivars_struct);
-        }
-    }
-    const char *ivars_offset_name = CFCClass_full_ivars_offset(client);
-
-    char pattern[] =
-        "    {\n"
-        "        &%s, /* class */\n"
-        "        %s, /* parent */\n"
-        "        \"%s\", /* name */\n"
-        "        %s, /* ivars_size */\n"
-        "        &%s, /* ivars_offset_ptr */\n"
-        "        %d, /* num_novel */\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, class_var, parent_ref, class_name,
-                          ivars_size, 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);
-    FREEMEM(ivars_size);
-    return code;
-}
-
 // Declare typedefs for every method, to ease casting.
 static char*
 S_method_typedefs(CFCBindClass *self) {

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/2b3ed29a/compiler/src/CFCBindClass.h
----------------------------------------------------------------------
diff --git a/compiler/src/CFCBindClass.h b/compiler/src/CFCBindClass.h
index c915c65..4780bdc 100644
--- a/compiler/src/CFCBindClass.h
+++ b/compiler/src/CFCBindClass.h
@@ -54,11 +54,6 @@ CFCBindClass_to_c_header(CFCBindClass *self);
 char*
 CFCBindClass_to_c_data(CFCBindClass *self);
 
-/** Return the autogenerated C definition of class's ClassSpec.
- */
-char*
-CFCBindClass_spec_def(CFCBindClass *self);
-
 #ifdef __cplusplus
 }
 #endif

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/2b3ed29a/compiler/src/CFCBindCore.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCBindCore.c b/compiler/src/CFCBindCore.c
index 985f00c..d5f59d7 100644
--- a/compiler/src/CFCBindCore.c
+++ b/compiler/src/CFCBindCore.c
@@ -24,6 +24,7 @@
 #include "CFCBindCore.h"
 #include "CFCBindClass.h"
 #include "CFCBindFile.h"
+#include "CFCBindSpecs.h"
 #include "CFCClass.h"
 #include "CFCFile.h"
 #include "CFCHierarchy.h"
@@ -300,41 +301,6 @@ S_write_parcel_h(CFCBindCore *self, CFCParcel *parcel) {
         "#define CFISH_fREFCOUNTSPECIAL 0x00000001\n"
         ;
     const char *cfish_defs_2 =
-        "/* Structs for Class initialization.\n"
-        " */\n"
-        "\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"
-        "    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_ClassSpec {\n"
-        "    cfish_Class **klass;\n"
-        "    cfish_Class **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"
-        "    const cfish_NovelMethSpec      *novel_meth_specs;\n"
-        "    const cfish_OverriddenMethSpec *overridden_meth_specs;\n"
-        "    const cfish_InheritedMethSpec  *inherited_meth_specs;\n"
-        "} cfish_ClassSpec;\n"
-        "\n"
         "#ifdef CFISH_USE_SHORT_NAMES\n"
         "  #define UNUSED_VAR               CFISH_UNUSED_VAR\n"
         "  #define UNREACHABLE_RETURN       CFISH_UNREACHABLE_RETURN\n"
@@ -352,7 +318,9 @@ S_write_parcel_h(CFCBindCore *self, CFCParcel *parcel) {
     char *extra_defs;
     char *extra_includes;
     if (CFCParcel_is_cfish(parcel)) {
-        extra_defs = CFCUtil_sprintf("%s%s", cfish_defs_1, cfish_defs_2);
+        const char *spec_typedefs = CFCBindSpecs_get_typedefs();
+        extra_defs = CFCUtil_sprintf("%s%s%s", cfish_defs_1, spec_typedefs,
+                                     cfish_defs_2);
         extra_includes = CFCUtil_strdup(cfish_includes);
     }
     else {
@@ -439,10 +407,9 @@ S_write_parcel_c(CFCBindCore *self, CFCParcel *parcel) {
     char *privacy_syms = CFCUtil_strdup("");
     char *includes     = CFCUtil_strdup("");
     char *c_data       = CFCUtil_strdup("");
-    char *class_specs  = CFCUtil_strdup(
-        "static const cfish_ClassSpec class_specs[] = {\n");
-    int num_specs = 0;
-    CFCClass **ordered  = CFCHierarchy_ordered_classes(hierarchy);
+    CFCBindSpecs *specs = CFCBindSpecs_new();
+    CFCClass **ordered = CFCHierarchy_ordered_classes(hierarchy);
+
     for (int i = 0; ordered[i] != NULL; i++) {
         CFCClass *klass = ordered[i];
         const char *class_prefix = CFCClass_get_prefix(klass);
@@ -453,24 +420,22 @@ S_write_parcel_c(CFCBindCore *self, CFCParcel *parcel) {
                                "\"\n", NULL);
 
         CFCBindClass *class_binding = CFCBindClass_new(klass);
+
         char *class_c_data = CFCBindClass_to_c_data(class_binding);
         c_data = CFCUtil_cat(c_data, class_c_data, "\n", NULL);
         FREEMEM(class_c_data);
-        if (!CFCClass_inert(klass)) {
-            if (num_specs != 0) {
-                class_specs = CFCUtil_cat(class_specs, ",\n", NULL);
-            }
-            char *class_spec = CFCBindClass_spec_def(class_binding);
-            class_specs = CFCUtil_cat(class_specs, class_spec, NULL);
-            FREEMEM(class_spec);
-            ++num_specs;
-        }
-        CFCBase_decref((CFCBase*)class_binding);
+
+        CFCBindSpecs_add_class(specs, klass);
+
         const char *privacy_sym = CFCClass_privacy_symbol(klass);
         privacy_syms = CFCUtil_cat(privacy_syms, "#define ",
                                    privacy_sym, "\n", NULL);
+
+        CFCBase_decref((CFCBase*)class_binding);
     }
-    class_specs = CFCUtil_cat(class_specs, "\n};\n", NULL);
+
+    char *spec_defs      = CFCBindSpecs_defs(specs);
+    char *spec_init_func = CFCBindSpecs_init_func_def(specs);
     FREEMEM(ordered);
 
     // Bootstrapping code for prerequisite parcels.
@@ -514,9 +479,15 @@ S_write_parcel_c(CFCBindCore *self, CFCParcel *parcel) {
         "\n"
         "%s\n"
         "\n"
-        "/* ClassSpec structs for initialization.\n"
+        "/* ClassSpec and MethSpec structs for initialization.\n"
         " */\n"
-        "%s\n"
+        "\n"
+        "%s" // spec_defs
+        "\n"
+        "/* Code to initialize ClassSpec and MethSpec structs.\n"
+        " */\n"
+        "\n"
+        "%s" // spec_init_func
         "\n"
         "static int bootstrap_state = 0;\n"
         "\n"
@@ -530,7 +501,7 @@ S_write_parcel_c(CFCBindCore *self, CFCParcel *parcel) {
         "    if (bootstrap_state >= 2) { return; }\n"
         "    bootstrap_state = 1;\n"
         "%s" // Bootstrap inherited parcels.
-        "    cfish_Class_bootstrap(class_specs, %d);\n"
+        "    S_bootstrap_specs();\n"
         "    bootstrap_state = 2;\n"
         "}\n"
         "\n"
@@ -546,9 +517,9 @@ S_write_parcel_c(CFCBindCore *self, CFCParcel *parcel) {
         "%s\n";
     char *file_content
         = CFCUtil_sprintf(pattern, self->c_header, privacy_syms, includes,
-                          c_data, class_specs, prefix, inh_bootstrap,
-                          num_specs, prefix, prefix, prereq_bootstrap, prefix,
-                          self->c_footer);
+                          c_data, spec_defs, spec_init_func, prefix,
+                          inh_bootstrap, prefix, prefix, prereq_bootstrap,
+                          prefix, self->c_footer);
 
     // Unlink then open file.
     const char *src_dest = CFCHierarchy_get_source_dest(hierarchy);
@@ -558,10 +529,12 @@ S_write_parcel_c(CFCBindCore *self, CFCParcel *parcel) {
     CFCUtil_write_file(filepath, file_content, strlen(file_content));
     FREEMEM(filepath);
 
+    CFCBase_decref((CFCBase*)specs);
     FREEMEM(privacy_syms);
     FREEMEM(includes);
     FREEMEM(c_data);
-    FREEMEM(class_specs);
+    FREEMEM(spec_defs);
+    FREEMEM(spec_init_func);
     FREEMEM(inh_bootstrap);
     FREEMEM(prereq_bootstrap);
     FREEMEM(file_content);

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/2b3ed29a/compiler/src/CFCBindMethod.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCBindMethod.c b/compiler/src/CFCBindMethod.c
index 925f481..e4d7301 100644
--- a/compiler/src/CFCBindMethod.c
+++ b/compiler/src/CFCBindMethod.c
@@ -162,81 +162,6 @@ CFCBindMeth_typedef_dec(struct CFCMethod *method, CFCClass *klass) {
 }
 
 char*
-CFCBindMeth_novel_spec_def(CFCMethod *method, CFCClass *klass) {
-    const char *meth_name = CFCMethod_get_name(method);
-
-    char *full_override_sym;
-    if (!CFCMethod_final(method)) {
-        full_override_sym = CFCMethod_full_override_sym(method, klass);
-    }
-    else {
-        full_override_sym = CFCUtil_strdup("NULL");
-    }
-
-    char *imp_func        = CFCMethod_imp_func(method, klass);
-    char *full_offset_sym = CFCMethod_full_offset_sym(method, klass);
-
-    char pattern[] =
-        "    {\n"
-        "        &%s, /* offset */\n"
-        "        \"%s\", /* name */\n"
-        "        (cfish_method_t)%s, /* func */\n"
-        "        (cfish_method_t)%s /* callback_func */\n"
-        "    }";
-    char *def
-        = CFCUtil_sprintf(pattern, full_offset_sym, meth_name, imp_func,
-                          full_override_sym);
-
-    FREEMEM(full_offset_sym);
-    FREEMEM(imp_func);
-    FREEMEM(full_override_sym);
-    return def;
-}
-
-char*
-CFCBindMeth_overridden_spec_def(CFCMethod *method, CFCClass *klass) {
-    char *imp_func        = CFCMethod_imp_func(method, 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"
-        "        (cfish_method_t)%s /* func */\n"
-        "    }";
-    char *def
-        = CFCUtil_sprintf(pattern, full_offset_sym, parent_offset_sym,
-                          imp_func);
-
-    FREEMEM(parent_offset_sym);
-    FREEMEM(full_offset_sym);
-    FREEMEM(imp_func);
-    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;
-}
-
-char*
 CFCBindMeth_abstract_method_def(CFCMethod *method, CFCClass *klass) {
     CFCType    *ret_type      = CFCMethod_get_return_type(method);
     const char *ret_type_str  = CFCType_to_c(ret_type);

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/2b3ed29a/compiler/src/CFCBindMethod.h
----------------------------------------------------------------------
diff --git a/compiler/src/CFCBindMethod.h b/compiler/src/CFCBindMethod.h
index 3bc16ab..4928c70 100644
--- a/compiler/src/CFCBindMethod.h
+++ b/compiler/src/CFCBindMethod.h
@@ -44,26 +44,6 @@ CFCBindMeth_method_def(struct CFCMethod *method, struct CFCClass *klass);
 char*
 CFCBindMeth_typedef_dec(struct CFCMethod *method, struct CFCClass *klass);
 
-/** Return C code defining the MethSpec object for a novel method, which
- * is used during Class initialization.
- */
-char*
-CFCBindMeth_novel_spec_def(struct CFCMethod *method, struct CFCClass *klass);
-
-/** Return C code defining the MethSpec object for an overridden method,
- * which is used during Class 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 Class 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
  * "abstract" in a Clownfish header file.

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/2b3ed29a/compiler/src/CFCBindSpecs.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCBindSpecs.c b/compiler/src/CFCBindSpecs.c
new file mode 100644
index 0000000..513806b
--- /dev/null
+++ b/compiler/src/CFCBindSpecs.c
@@ -0,0 +1,419 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "charmony.h"
+
+#include "CFCBindSpecs.h"
+
+#define CFC_NEED_BASE_STRUCT_DEF
+#include "CFCBase.h"
+#include "CFCClass.h"
+#include "CFCMethod.h"
+#include "CFCParcel.h"
+#include "CFCUtil.h"
+
+struct CFCBindSpecs {
+    CFCBase base;
+
+    char *novel_specs;
+    char *overridden_specs;
+    char *inherited_specs;
+    char *class_specs;
+
+    int num_novel;
+    int num_overridden;
+    int num_inherited;
+    int num_specs;
+};
+
+static char*
+S_ivars_size(CFCClass *klass);
+
+static char*
+S_novel_meth(CFCMethod *method, CFCClass *klass);
+
+static char*
+S_parent_offset(CFCMethod *method, CFCClass *klass);
+
+static char*
+S_overridden_meth(CFCMethod *method, CFCClass *klass);
+
+static char*
+S_inherited_meth(CFCMethod *method, CFCClass *klass);
+
+static const CFCMeta CFCBINDSPECS_META = {
+    "Clownfish::CFC::Binding::Core::Specs",
+    sizeof(CFCBindSpecs),
+    (CFCBase_destroy_t)CFCBindSpecs_destroy
+};
+
+CFCBindSpecs*
+CFCBindSpecs_new() {
+    CFCBindSpecs *self = (CFCBindSpecs*)CFCBase_allocate(&CFCBINDSPECS_META);
+    return CFCBindSpecs_init(self);
+}
+
+CFCBindSpecs*
+CFCBindSpecs_init(CFCBindSpecs *self) {
+    self->novel_specs      = CFCUtil_strdup("");
+    self->overridden_specs = CFCUtil_strdup("");
+    self->inherited_specs  = CFCUtil_strdup("");
+    self->class_specs      = CFCUtil_strdup("");
+
+    return self;
+}
+
+void
+CFCBindSpecs_destroy(CFCBindSpecs *self) {
+    FREEMEM(self->novel_specs);
+    FREEMEM(self->overridden_specs);
+    FREEMEM(self->inherited_specs);
+    FREEMEM(self->class_specs);
+    CFCBase_destroy((CFCBase*)self);
+}
+
+const char*
+CFCBindSpecs_get_typedefs() {
+    return
+        "/* Structs for Class initialization.\n"
+        " */\n"
+        "\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"
+        "    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_ClassSpec {\n"
+        "    cfish_Class **klass;\n"
+        "    cfish_Class **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"
+        "    const cfish_NovelMethSpec      *novel_meth_specs;\n"
+        "    const cfish_OverriddenMethSpec *overridden_meth_specs;\n"
+        "    const cfish_InheritedMethSpec  *inherited_meth_specs;\n"
+        "} cfish_ClassSpec;\n"
+        "\n";
+}
+
+void
+CFCBindSpecs_add_class(CFCBindSpecs *self, CFCClass *klass) {
+    if (CFCClass_inert(klass)) { return; }
+
+    const char *class_name        = CFCClass_get_name(klass);
+    const char *class_var         = CFCClass_full_class_var(klass);
+    const char *ivars_offset_name = CFCClass_full_ivars_offset(klass);
+
+    char *ivars_size = S_ivars_size(klass);
+
+    char *parent_ptr = NULL;
+    CFCClass *parent = CFCClass_get_parent(klass);
+    if (!parent) {
+        parent_ptr = CFCUtil_strdup("NULL");
+    }
+    else {
+        parent_ptr = CFCUtil_sprintf("&%s", CFCClass_full_class_var(parent));
+    }
+
+    char *novel_specs      = CFCUtil_strdup("");
+    char *overridden_specs = CFCUtil_strdup("");
+    char *inherited_specs  = CFCUtil_strdup("");
+    int num_new_novel      = 0;
+    int num_new_overridden = 0;
+    int num_new_inherited  = 0;
+    CFCMethod **methods = CFCClass_methods(klass);
+
+    for (int meth_num = 0; methods[meth_num] != NULL; meth_num++) {
+        CFCMethod *method = methods[meth_num];
+
+        if (CFCMethod_is_fresh(method, klass)) {
+            if (CFCMethod_novel(method)) {
+                const char *sep = num_new_novel == 0 ? "" : ",\n";
+                char *def = S_novel_meth(method, klass);
+                novel_specs = CFCUtil_cat(novel_specs, sep, def, NULL);
+                FREEMEM(def);
+                ++num_new_novel;
+            }
+            else {
+                const char *sep = num_new_overridden == 0 ? "" : ",\n";
+                char *def = S_overridden_meth(method, klass);
+                overridden_specs = CFCUtil_cat(overridden_specs, sep, def,
+                                               NULL);
+                FREEMEM(def);
+                ++num_new_overridden;
+            }
+        }
+        else {
+            const char *sep = num_new_inherited == 0 ? "" : ",\n";
+            char *def = S_inherited_meth(method, klass);
+            inherited_specs = CFCUtil_cat(inherited_specs, sep, def, NULL);
+            FREEMEM(def);
+            ++num_new_inherited;
+        }
+    }
+
+    char *novel_spec_var;
+
+    if (num_new_novel) {
+        novel_spec_var = CFCUtil_sprintf("%s_NOVEL_METHS", class_var);
+
+        const char *pattern =
+            "static cfish_NovelMethSpec %s[] = {\n"
+            "%s\n"
+            "};\n"
+            "\n";
+        char *spec_def = CFCUtil_sprintf(pattern, novel_spec_var, novel_specs);
+        self->novel_specs = CFCUtil_cat(self->novel_specs, spec_def, NULL);
+        FREEMEM(spec_def);
+    }
+    else {
+        novel_spec_var = CFCUtil_strdup("NULL");
+    }
+
+    char *overridden_spec_var;
+
+    if (num_new_overridden) {
+        overridden_spec_var = CFCUtil_sprintf("%s_OVERRIDDEN_METHS",
+                                              class_var);
+
+        const char *pattern =
+            "static cfish_OverriddenMethSpec %s[] = {\n"
+            "%s\n"
+            "};\n"
+            "\n";
+        char *spec_def = CFCUtil_sprintf(pattern, overridden_spec_var,
+                                         overridden_specs);
+        self->overridden_specs = CFCUtil_cat(self->overridden_specs, spec_def,
+                                             NULL);
+        FREEMEM(spec_def);
+    }
+    else {
+        overridden_spec_var = CFCUtil_strdup("NULL");
+    }
+
+    char *inherited_spec_var;
+
+    if (num_new_inherited) {
+        inherited_spec_var = CFCUtil_sprintf("%s_INHERITED_METHS", class_var);
+
+        const char *pattern =
+            "static cfish_InheritedMethSpec %s[] = {\n"
+            "%s\n"
+            "};\n"
+            "\n";
+        char *spec_def = CFCUtil_sprintf(pattern, inherited_spec_var,
+                                         inherited_specs);
+        self->inherited_specs = CFCUtil_cat(self->inherited_specs, spec_def,
+                                            NULL);
+        FREEMEM(spec_def);
+    }
+    else {
+        inherited_spec_var = CFCUtil_strdup("NULL");
+    }
+
+    char pattern[] =
+        "    {\n"
+        "        &%s, /* class */\n"
+        "        %s, /* parent */\n"
+        "        \"%s\", /* name */\n"
+        "        %s, /* ivars_size */\n"
+        "        &%s, /* ivars_offset_ptr */\n"
+        "        %d, /* num_novel */\n"
+        "        %d, /* num_overridden */\n"
+        "        %d, /* num_inherited */\n"
+        "        %s,\n"
+        "        %s,\n"
+        "        %s\n"
+        "    }";
+    char *class_spec
+        = CFCUtil_sprintf(pattern, class_var, parent_ptr, class_name,
+                          ivars_size, ivars_offset_name,
+                          num_new_novel,
+                          num_new_overridden,
+                          num_new_inherited,
+                          novel_spec_var,
+                          overridden_spec_var,
+                          inherited_spec_var);
+
+    const char *sep = self->num_specs == 0 ? "" : ",\n";
+    self->class_specs = CFCUtil_cat(self->class_specs, sep, class_spec, NULL);
+
+    self->num_novel      += num_new_novel;
+    self->num_overridden += num_new_overridden;
+    self->num_inherited  += num_new_inherited;
+    self->num_specs      += 1;
+
+    FREEMEM(class_spec);
+    FREEMEM(inherited_spec_var);
+    FREEMEM(overridden_spec_var);
+    FREEMEM(novel_spec_var);
+    FREEMEM(parent_ptr);
+    FREEMEM(ivars_size);
+}
+
+char*
+CFCBindSpecs_defs(CFCBindSpecs *self) {
+    if (!self->class_specs[0]) { return CFCUtil_strdup(""); }
+
+    const char *pattern =
+        "%s"
+        "%s"
+        "%s"
+        "static cfish_ClassSpec class_specs[] = {\n"
+        "%s\n"
+        "};\n";
+    return CFCUtil_sprintf(pattern, self->novel_specs,
+                           self->overridden_specs, self->inherited_specs,
+                           self->class_specs);
+}
+
+char*
+CFCBindSpecs_init_func_def(CFCBindSpecs *self) {
+    const char *pattern =
+        "static void\n"
+        "S_bootstrap_specs() {\n"
+        "    cfish_Class_bootstrap(class_specs, %d);\n"
+        "}\n";
+    return CFCUtil_sprintf(pattern, self->num_specs);
+}
+
+static char*
+S_ivars_size(CFCClass *klass) {
+    CFCParcel *parcel = CFCClass_get_parcel(klass);
+    char *ivars_size = NULL;
+
+    if (CFCParcel_is_cfish(parcel)) {
+        const char *struct_sym   = CFCClass_full_struct_sym(klass);
+        ivars_size = CFCUtil_sprintf("sizeof(%s)", struct_sym);
+    }
+    else {
+        int num_non_package_ivars = CFCClass_num_non_package_ivars(klass);
+        int num_ivars             = CFCClass_num_member_vars(klass);
+
+        if (num_non_package_ivars == num_ivars) {
+            // No members in this package.
+            ivars_size = CFCUtil_strdup("0");
+        }
+        else {
+            const char *ivars_struct = CFCClass_full_ivars_struct(klass);
+            ivars_size = CFCUtil_sprintf("sizeof(%s)", ivars_struct);
+        }
+    }
+
+    return ivars_size;
+}
+
+static char*
+S_novel_meth(CFCMethod *method, CFCClass *klass) {
+    const char *meth_name = CFCMethod_get_name(method);
+
+    char *full_override_sym;
+    if (!CFCMethod_final(method)) {
+        full_override_sym = CFCMethod_full_override_sym(method, klass);
+    }
+    else {
+        full_override_sym = CFCUtil_strdup("NULL");
+    }
+
+    char *imp_func        = CFCMethod_imp_func(method, klass);
+    char *full_offset_sym = CFCMethod_full_offset_sym(method, klass);
+
+    char pattern[] =
+        "    {\n"
+        "        &%s, /* offset */\n"
+        "        \"%s\", /* name */\n"
+        "        (cfish_method_t)%s, /* func */\n"
+        "        (cfish_method_t)%s /* callback_func */\n"
+        "    }";
+    char *def
+        = CFCUtil_sprintf(pattern, full_offset_sym, meth_name, imp_func,
+                          full_override_sym);
+
+    FREEMEM(full_offset_sym);
+    FREEMEM(imp_func);
+    FREEMEM(full_override_sym);
+    return def;
+}
+
+static char*
+S_parent_offset(CFCMethod *method, CFCClass *klass) {
+    CFCClass *parent = CFCClass_get_parent(klass);
+
+    if (!parent) {
+        return CFCUtil_strdup("NULL");
+    }
+
+    char *parent_offset_sym = CFCMethod_full_offset_sym(method, parent);
+    char *parent_offset = CFCUtil_sprintf("&%s", parent_offset_sym);
+    FREEMEM(parent_offset_sym);
+
+    return parent_offset;
+}
+
+static char*
+S_overridden_meth(CFCMethod *method, CFCClass *klass) {
+    char *imp_func        = CFCMethod_imp_func(method, klass);
+    char *full_offset_sym = CFCMethod_full_offset_sym(method, klass);
+    char *parent_offset   = S_parent_offset(method, klass);
+
+    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, imp_func);
+
+    FREEMEM(parent_offset);
+    FREEMEM(full_offset_sym);
+    FREEMEM(imp_func);
+    return def;
+}
+
+static char*
+S_inherited_meth(CFCMethod *method, CFCClass *klass) {
+    char *full_offset_sym = CFCMethod_full_offset_sym(method, klass);
+    char *parent_offset   = S_parent_offset(method, klass);
+
+    char pattern[] =
+        "    {\n"
+        "        &%s, /* offset */\n"
+        "        %s /* parent_offset */\n"
+        "    }";
+    char *def = CFCUtil_sprintf(pattern, full_offset_sym, parent_offset);
+
+    FREEMEM(full_offset_sym);
+    FREEMEM(parent_offset);
+    return def;
+}
+

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/2b3ed29a/compiler/src/CFCBindSpecs.h
----------------------------------------------------------------------
diff --git a/compiler/src/CFCBindSpecs.h b/compiler/src/CFCBindSpecs.h
new file mode 100644
index 0000000..d3f2b8c
--- /dev/null
+++ b/compiler/src/CFCBindSpecs.h
@@ -0,0 +1,58 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** Clownfish::CFC::Binding::Core::Specs - Generate C code for class
+ * initialization.
+ */
+
+#ifndef H_CFCBINDSPECS
+#define H_CFCBINDSPECS
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct CFCBindSpecs CFCBindSpecs;
+
+struct CFCClass;
+
+CFCBindSpecs*
+CFCBindSpecs_new(void);
+
+CFCBindSpecs*
+CFCBindSpecs_init(CFCBindSpecs *specs);
+
+void
+CFCBindSpecs_destroy(CFCBindSpecs *specs);
+
+const char*
+CFCBindSpecs_get_typedefs(void);
+
+void
+CFCBindSpecs_add_class(CFCBindSpecs *specs, struct CFCClass *klass);
+
+char*
+CFCBindSpecs_defs(CFCBindSpecs *self);
+
+char*
+CFCBindSpecs_init_func_def(CFCBindSpecs *self);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* H_CFCBINDSPECS */
+

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/2b3ed29a/compiler/src/CFCClass.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCClass.c b/compiler/src/CFCClass.c
index acbc22c..1d89de4 100644
--- a/compiler/src/CFCClass.c
+++ b/compiler/src/CFCClass.c
@@ -810,6 +810,24 @@ CFCClass_num_member_vars(CFCClass *self) {
     return self->num_member_vars;
 }
 
+// Count the number of member variables declared in ancestor classes
+// outside this package.
+size_t
+CFCClass_num_non_package_ivars(CFCClass *self) {
+    CFCParcel *parcel       = CFCClass_get_parcel(self);
+    CFCClass  *ancestor     = CFCClass_get_parent(self);
+    int num_non_package_members = 0;
+
+    while (ancestor && CFCClass_get_parcel(ancestor) == parcel) {
+        ancestor = CFCClass_get_parent(ancestor);
+    }
+    if (ancestor) {
+        num_non_package_members = CFCClass_num_member_vars(ancestor);
+    }
+
+    return num_non_package_members;
+}
+
 CFCVariable**
 CFCClass_inert_vars(CFCClass *self) {
     return self->inert_vars;

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/2b3ed29a/compiler/src/CFCClass.h
----------------------------------------------------------------------
diff --git a/compiler/src/CFCClass.h b/compiler/src/CFCClass.h
index 68870bf..e148500 100644
--- a/compiler/src/CFCClass.h
+++ b/compiler/src/CFCClass.h
@@ -208,6 +208,12 @@ CFCClass_member_vars(CFCClass *self);
 size_t
 CFCClass_num_member_vars(CFCClass *self);
 
+/** Count the number of member variables declared in ancestor classes
+ * outside this package.
+ */
+size_t
+CFCClass_num_non_package_ivars(CFCClass *self);
+
 /** Return an array of all inert (shared, class) variables.
  */
 struct CFCVariable**


[3/4] lucy-clownfish git commit: Store MethSpecs in a single array

Posted by nw...@apache.org.
Store MethSpecs in a single array

Reduces size of ClassSpec struct and number of relocations.


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

Branch: refs/heads/master
Commit: 5c7144b6a63ef6d483496ce713c7f4a0184a1d1c
Parents: 05068aa
Author: Nick Wellnhofer <we...@aevum.de>
Authored: Fri Jul 24 14:06:13 2015 +0200
Committer: Nick Wellnhofer <we...@aevum.de>
Committed: Mon Jul 27 18:26:18 2015 +0200

----------------------------------------------------------------------
 compiler/src/CFCBindSpecs.c      | 209 +++++++++++++---------------------
 runtime/core/Clownfish/Class.c   |  21 +++-
 runtime/core/Clownfish/Class.cfh |   5 +-
 3 files changed, 101 insertions(+), 134 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/5c7144b6/compiler/src/CFCBindSpecs.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCBindSpecs.c b/compiler/src/CFCBindSpecs.c
index ff64eca..f3b377d 100644
--- a/compiler/src/CFCBindSpecs.c
+++ b/compiler/src/CFCBindSpecs.c
@@ -43,21 +43,21 @@ struct CFCBindSpecs {
 static char*
 S_ivars_size(CFCClass *klass);
 
-static char*
-S_novel_meth(CFCBindSpecs *self, CFCMethod *method, CFCClass *klass,
-             int meth_index);
+static void
+S_add_novel_meth(CFCBindSpecs *self, CFCMethod *method, CFCClass *klass,
+                 int meth_index);
 
 static char*
 S_parent_offset(CFCBindSpecs *self, CFCMethod *method, CFCClass *klass,
                 const char *meth_type, int meth_index);
 
-static char*
-S_overridden_meth(CFCBindSpecs *self, CFCMethod *method, CFCClass *klass,
-                  int meth_index);
+static void
+S_add_overridden_meth(CFCBindSpecs *self, CFCMethod *method, CFCClass *klass,
+                      int meth_index);
 
-static char*
-S_inherited_meth(CFCBindSpecs *self, CFCMethod *method, CFCClass *klass,
-                 int meth_index);
+static void
+S_add_inherited_meth(CFCBindSpecs *self, CFCMethod *method, CFCClass *klass,
+                     int meth_index);
 
 static const CFCMeta CFCBINDSPECS_META = {
     "Clownfish::CFC::Binding::Core::Specs",
@@ -125,9 +125,6 @@ CFCBindSpecs_get_typedefs() {
         "    uint32_t      num_novel_meths;\n"
         "    uint32_t      num_overridden_meths;\n"
         "    uint32_t      num_inherited_meths;\n"
-        "    const cfish_NovelMethSpec      *novel_meth_specs;\n"
-        "    const cfish_OverriddenMethSpec *overridden_meth_specs;\n"
-        "    const cfish_InheritedMethSpec  *inherited_meth_specs;\n"
         "} cfish_ClassSpec;\n"
         "\n";
 }
@@ -167,9 +164,6 @@ CFCBindSpecs_add_class(CFCBindSpecs *self, CFCClass *klass) {
         }
     }
 
-    char *novel_specs      = CFCUtil_strdup("");
-    char *overridden_specs = CFCUtil_strdup("");
-    char *inherited_specs  = CFCUtil_strdup("");
     int num_new_novel      = 0;
     int num_new_overridden = 0;
     int num_new_inherited  = 0;
@@ -180,91 +174,23 @@ CFCBindSpecs_add_class(CFCBindSpecs *self, CFCClass *klass) {
 
         if (CFCMethod_is_fresh(method, klass)) {
             if (CFCMethod_novel(method)) {
-                const char *sep = num_new_novel == 0 ? "" : ",\n";
-                char *def = S_novel_meth(self, method, klass, num_new_novel);
-                novel_specs = CFCUtil_cat(novel_specs, sep, def, NULL);
-                FREEMEM(def);
+                int meth_index = self->num_novel + num_new_novel;
+                S_add_novel_meth(self, method, klass, meth_index);
                 ++num_new_novel;
             }
             else {
-                const char *sep = num_new_overridden == 0 ? "" : ",\n";
-                char *def = S_overridden_meth(self, method, klass,
-                                              num_new_overridden);
-                overridden_specs = CFCUtil_cat(overridden_specs, sep, def,
-                                               NULL);
-                FREEMEM(def);
+                int meth_index = self->num_overridden + num_new_overridden;
+                S_add_overridden_meth(self, method, klass, meth_index);
                 ++num_new_overridden;
             }
         }
         else {
-            const char *sep = num_new_inherited == 0 ? "" : ",\n";
-            char *def = S_inherited_meth(self, method, klass,
-                                         num_new_inherited);
-            inherited_specs = CFCUtil_cat(inherited_specs, sep, def, NULL);
-            FREEMEM(def);
+            int meth_index = self->num_inherited + num_new_inherited;
+            S_add_inherited_meth(self, method, klass, meth_index);
             ++num_new_inherited;
         }
     }
 
-    char *novel_spec_var;
-
-    if (num_new_novel) {
-        novel_spec_var = CFCUtil_sprintf("%s_NOVEL_METHS", class_var);
-
-        const char *pattern =
-            "static cfish_NovelMethSpec %s[] = {\n"
-            "%s\n"
-            "};\n"
-            "\n";
-        char *spec_def = CFCUtil_sprintf(pattern, novel_spec_var, novel_specs);
-        self->novel_specs = CFCUtil_cat(self->novel_specs, spec_def, NULL);
-        FREEMEM(spec_def);
-    }
-    else {
-        novel_spec_var = CFCUtil_strdup("NULL");
-    }
-
-    char *overridden_spec_var;
-
-    if (num_new_overridden) {
-        overridden_spec_var = CFCUtil_sprintf("%s_OVERRIDDEN_METHS",
-                                              class_var);
-
-        const char *pattern =
-            "static cfish_OverriddenMethSpec %s[] = {\n"
-            "%s\n"
-            "};\n"
-            "\n";
-        char *spec_def = CFCUtil_sprintf(pattern, overridden_spec_var,
-                                         overridden_specs);
-        self->overridden_specs = CFCUtil_cat(self->overridden_specs, spec_def,
-                                             NULL);
-        FREEMEM(spec_def);
-    }
-    else {
-        overridden_spec_var = CFCUtil_strdup("NULL");
-    }
-
-    char *inherited_spec_var;
-
-    if (num_new_inherited) {
-        inherited_spec_var = CFCUtil_sprintf("%s_INHERITED_METHS", class_var);
-
-        const char *pattern =
-            "static cfish_InheritedMethSpec %s[] = {\n"
-            "%s\n"
-            "};\n"
-            "\n";
-        char *spec_def = CFCUtil_sprintf(pattern, inherited_spec_var,
-                                         inherited_specs);
-        self->inherited_specs = CFCUtil_cat(self->inherited_specs, spec_def,
-                                            NULL);
-        FREEMEM(spec_def);
-    }
-    else {
-        inherited_spec_var = CFCUtil_strdup("NULL");
-    }
-
     char pattern[] =
         "    {\n"
         "        &%s, /* class */\n"
@@ -274,20 +200,12 @@ CFCBindSpecs_add_class(CFCBindSpecs *self, CFCClass *klass) {
         "        &%s, /* ivars_offset_ptr */\n"
         "        %d, /* num_novel */\n"
         "        %d, /* num_overridden */\n"
-        "        %d, /* num_inherited */\n"
-        "        %s,\n"
-        "        %s,\n"
-        "        %s\n"
+        "        %d /* num_inherited */\n"
         "    }";
     char *class_spec
         = CFCUtil_sprintf(pattern, class_var, parent_ptr, class_name,
-                          ivars_size, ivars_offset_name,
-                          num_new_novel,
-                          num_new_overridden,
-                          num_new_inherited,
-                          novel_spec_var,
-                          overridden_spec_var,
-                          inherited_spec_var);
+                          ivars_size, ivars_offset_name, num_new_novel,
+                          num_new_overridden, num_new_inherited);
 
     const char *sep = self->num_specs == 0 ? "" : ",\n";
     self->class_specs = CFCUtil_cat(self->class_specs, sep, class_spec, NULL);
@@ -298,16 +216,42 @@ CFCBindSpecs_add_class(CFCBindSpecs *self, CFCClass *klass) {
     self->num_specs      += 1;
 
     FREEMEM(class_spec);
-    FREEMEM(inherited_spec_var);
-    FREEMEM(overridden_spec_var);
-    FREEMEM(novel_spec_var);
     FREEMEM(parent_ptr);
     FREEMEM(ivars_size);
 }
 
 char*
 CFCBindSpecs_defs(CFCBindSpecs *self) {
-    if (!self->class_specs[0]) { return CFCUtil_strdup(""); }
+    if (self->num_specs == 0) { return CFCUtil_strdup(""); }
+
+    const char *novel_pattern =
+        "static cfish_NovelMethSpec novel_specs[] = {\n"
+        "%s\n"
+        "};\n"
+        "\n";
+    char *novel_specs = self->num_novel == 0
+                        ? CFCUtil_strdup("")
+                        : CFCUtil_sprintf(novel_pattern, self->novel_specs);
+
+    const char *overridden_pattern =
+        "static cfish_OverriddenMethSpec overridden_specs[] = {\n"
+        "%s\n"
+        "};\n"
+        "\n";
+    char *overridden_specs = self->num_overridden == 0
+                             ? CFCUtil_strdup("")
+                             : CFCUtil_sprintf(overridden_pattern,
+                                               self->overridden_specs);
+
+    const char *inherited_pattern =
+        "static cfish_InheritedMethSpec inherited_specs[] = {\n"
+        "%s\n"
+        "};\n"
+        "\n";
+    char *inherited_specs = self->num_inherited == 0
+                            ? CFCUtil_strdup("")
+                            : CFCUtil_sprintf(inherited_pattern,
+                                              self->inherited_specs);
 
     const char *pattern =
         "%s"
@@ -316,9 +260,13 @@ CFCBindSpecs_defs(CFCBindSpecs *self) {
         "static cfish_ClassSpec class_specs[] = {\n"
         "%s\n"
         "};\n";
-    return CFCUtil_sprintf(pattern, self->novel_specs,
-                           self->overridden_specs, self->inherited_specs,
-                           self->class_specs);
+    char *defs = CFCUtil_sprintf(pattern, novel_specs, overridden_specs,
+                                 inherited_specs, self->class_specs);
+
+    FREEMEM(inherited_specs);
+    FREEMEM(overridden_specs);
+    FREEMEM(novel_specs);
+    return defs;
 }
 
 char*
@@ -328,7 +276,8 @@ CFCBindSpecs_init_func_def(CFCBindSpecs *self) {
         "S_bootstrap_specs() {\n"
         "%s"
         "\n"
-        "    cfish_Class_bootstrap(class_specs, %d);\n"
+        "    cfish_Class_bootstrap(class_specs, %d, novel_specs,\n"
+        "                          overridden_specs, inherited_specs);\n"
         "}\n";
     return CFCUtil_sprintf(pattern, self->init_code, self->num_specs);
 }
@@ -359,12 +308,11 @@ S_ivars_size(CFCClass *klass) {
     return ivars_size;
 }
 
-static char*
-S_novel_meth(CFCBindSpecs *self, CFCMethod *method, CFCClass *klass,
-             int meth_index) {
-    CHY_UNUSED_VAR(self);
-    CHY_UNUSED_VAR(meth_index);
+static void
+S_add_novel_meth(CFCBindSpecs *self, CFCMethod *method, CFCClass *klass,
+                 int meth_index) {
     const char *meth_name = CFCMethod_get_name(method);
+    const char *sep = meth_index == 0 ? "" : ",\n";
 
     char *full_override_sym;
     if (!CFCMethod_final(method)) {
@@ -387,11 +335,12 @@ S_novel_meth(CFCBindSpecs *self, CFCMethod *method, CFCClass *klass,
     char *def
         = CFCUtil_sprintf(pattern, full_offset_sym, meth_name, imp_func,
                           full_override_sym);
+    self->novel_specs = CFCUtil_cat(self->novel_specs, sep, def, NULL);
 
+    FREEMEM(def);
     FREEMEM(full_offset_sym);
     FREEMEM(imp_func);
     FREEMEM(full_override_sym);
-    return def;
 }
 
 static char*
@@ -412,9 +361,8 @@ S_parent_offset(CFCBindSpecs *self, CFCMethod *method, CFCClass *klass,
     else {
         parent_offset = CFCUtil_strdup("NULL");
 
-        const char *class_var = CFCClass_full_class_var(klass);
-        char pattern[] = "    %s_%s_METHS[%d].parent_offset = &%s;\n";
-        char *code = CFCUtil_sprintf(pattern, class_var, meth_type, meth_index,
+        char pattern[] = "    %s_specs[%d].parent_offset = &%s;\n";
+        char *code = CFCUtil_sprintf(pattern, meth_type, meth_index,
                                      parent_offset_sym);
         self->init_code = CFCUtil_cat(self->init_code, code, NULL);
         FREEMEM(code);
@@ -425,12 +373,14 @@ S_parent_offset(CFCBindSpecs *self, CFCMethod *method, CFCClass *klass,
     return parent_offset;
 }
 
-static char*
-S_overridden_meth(CFCBindSpecs *self, CFCMethod *method, CFCClass *klass,
-                  int meth_index) {
+static void
+S_add_overridden_meth(CFCBindSpecs *self, CFCMethod *method, CFCClass *klass,
+                      int meth_index) {
+    const char *sep = meth_index == 0 ? "" : ",\n";
+
     char *imp_func        = CFCMethod_imp_func(method, klass);
     char *full_offset_sym = CFCMethod_full_offset_sym(method, klass);
-    char *parent_offset   = S_parent_offset(self, method, klass, "OVERRIDDEN",
+    char *parent_offset   = S_parent_offset(self, method, klass, "overridden",
                                             meth_index);
 
     char pattern[] =
@@ -441,18 +391,22 @@ S_overridden_meth(CFCBindSpecs *self, CFCMethod *method, CFCClass *klass,
         "    }";
     char *def
         = CFCUtil_sprintf(pattern, full_offset_sym, parent_offset, imp_func);
+    self->overridden_specs
+        = CFCUtil_cat(self->overridden_specs, sep, def, NULL);
 
+    FREEMEM(def);
     FREEMEM(parent_offset);
     FREEMEM(full_offset_sym);
     FREEMEM(imp_func);
-    return def;
 }
 
-static char*
-S_inherited_meth(CFCBindSpecs *self, CFCMethod *method, CFCClass *klass,
-                 int meth_index) {
+static void
+S_add_inherited_meth(CFCBindSpecs *self, CFCMethod *method, CFCClass *klass,
+                     int meth_index) {
+    const char *sep = meth_index == 0 ? "" : ",\n";
+
     char *full_offset_sym = CFCMethod_full_offset_sym(method, klass);
-    char *parent_offset   = S_parent_offset(self, method, klass, "INHERITED",
+    char *parent_offset   = S_parent_offset(self, method, klass, "inherited",
                                             meth_index);
 
     char pattern[] =
@@ -461,9 +415,10 @@ S_inherited_meth(CFCBindSpecs *self, CFCMethod *method, CFCClass *klass,
         "        %s /* parent_offset */\n"
         "    }";
     char *def = CFCUtil_sprintf(pattern, full_offset_sym, parent_offset);
+    self->inherited_specs = CFCUtil_cat(self->inherited_specs, sep, def, NULL);
 
+    FREEMEM(def);
     FREEMEM(full_offset_sym);
     FREEMEM(parent_offset);
-    return def;
 }
 

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/5c7144b6/runtime/core/Clownfish/Class.c
----------------------------------------------------------------------
diff --git a/runtime/core/Clownfish/Class.c b/runtime/core/Clownfish/Class.c
index 47ada81..474e8a2 100644
--- a/runtime/core/Clownfish/Class.c
+++ b/runtime/core/Clownfish/Class.c
@@ -56,8 +56,10 @@ S_claim_parcel_id(void);
 static LockFreeRegistry *Class_registry;
 
 void
-Class_bootstrap(const ClassSpec *specs, size_t num_specs)
-{
+Class_bootstrap(const cfish_ClassSpec *specs, size_t num_specs,
+                const cfish_NovelMethSpec *novel_specs,
+                const cfish_OverriddenMethSpec *overridden_specs,
+                const cfish_InheritedMethSpec *inherited_specs) {
     int32_t parcel_id = S_claim_parcel_id();
 
     /* Pass 1:
@@ -99,6 +101,9 @@ Class_bootstrap(const ClassSpec *specs, size_t num_specs)
      * - Assign parcel_id.
      * - Initialize method pointers and offsets.
      */
+    uint32_t num_novel      = 0;
+    uint32_t num_overridden = 0;
+    uint32_t num_inherited  = 0;
     for (size_t i = 0; i < num_specs; ++i) {
         const ClassSpec *spec = &specs[i];
         Class *klass  = *spec->klass;
@@ -159,18 +164,19 @@ Class_bootstrap(const ClassSpec *specs, size_t num_specs)
         }
 
         for (size_t i = 0; i < spec->num_inherited_meths; ++i) {
-            const InheritedMethSpec *mspec = &spec->inherited_meth_specs[i];
+            const InheritedMethSpec *mspec = &inherited_specs[num_inherited++];
             *mspec->offset = *mspec->parent_offset;
         }
 
         for (size_t i = 0; i < spec->num_overridden_meths; ++i) {
-            const OverriddenMethSpec *mspec = &spec->overridden_meth_specs[i];
+            const OverriddenMethSpec *mspec
+                = &overridden_specs[num_overridden++];
             *mspec->offset = *mspec->parent_offset;
             Class_Override_IMP(klass, mspec->func, *mspec->offset);
         }
 
         for (size_t i = 0; i < spec->num_novel_meths; ++i) {
-            const NovelMethSpec *mspec = &spec->novel_meth_specs[i];
+            const NovelMethSpec *mspec = &novel_specs[num_novel++];
             *mspec->offset = novel_offset;
             novel_offset += sizeof(cfish_method_t);
             Class_Override_IMP(klass, mspec->func, *mspec->offset);
@@ -183,6 +189,9 @@ Class_bootstrap(const ClassSpec *specs, size_t num_specs)
      * - Inititalize name and method array.
      * - Register class.
      */
+    num_novel      = 0;
+    num_overridden = 0;
+    num_inherited  = 0;
     for (size_t i = 0; i < num_specs; ++i) {
         const ClassSpec *spec = &specs[i];
         Class *klass = *spec->klass;
@@ -193,7 +202,7 @@ Class_bootstrap(const ClassSpec *specs, size_t num_specs)
 
         // Only store novel methods for now.
         for (size_t i = 0; i < spec->num_novel_meths; ++i) {
-            const NovelMethSpec *mspec = &spec->novel_meth_specs[i];
+            const NovelMethSpec *mspec = &novel_specs[num_novel++];
             String *name = SSTR_WRAP_UTF8(mspec->name, strlen(mspec->name));
             Method *method = Method_new(name, mspec->callback_func,
                                         *mspec->offset);

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/5c7144b6/runtime/core/Clownfish/Class.cfh
----------------------------------------------------------------------
diff --git a/runtime/core/Clownfish/Class.cfh b/runtime/core/Clownfish/Class.cfh
index be8520e..733e06e 100644
--- a/runtime/core/Clownfish/Class.cfh
+++ b/runtime/core/Clownfish/Class.cfh
@@ -38,7 +38,10 @@ final class Clownfish::Class inherits Clownfish::Obj {
     inert size_t offset_of_parent;
 
     inert void
-    bootstrap(const cfish_ClassSpec *specs, size_t num_specs);
+    bootstrap(const cfish_ClassSpec *specs, size_t num_specs,
+              const cfish_NovelMethSpec *novel_specs,
+              const cfish_OverriddenMethSpec *overridden_specs,
+              const cfish_InheritedMethSpec *inherited_specs);
 
     /** Return a singleton.  If a Class can be found in the registry based on
      * the supplied class name, it will be returned.  Otherwise, a new Class


[2/4] lucy-clownfish git commit: Don't use cross-DLL pointers in global initialization

Posted by nw...@apache.org.
Don't use cross-DLL pointers in global initialization

Initialize global pointers to objects from other DLLs manually at runtime.
Fixes build of Clownfish projects with MSVC in C mode.

Fixes CLOWNFISH-53.


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

Branch: refs/heads/master
Commit: 05068aabc4425d91f62de6f0205e6a892c954ac0
Parents: 2b3ed29
Author: Nick Wellnhofer <we...@aevum.de>
Authored: Fri Jul 24 13:32:39 2015 +0200
Committer: Nick Wellnhofer <we...@aevum.de>
Committed: Mon Jul 27 18:26:18 2015 +0200

----------------------------------------------------------------------
 compiler/src/CFCBindSpecs.c | 82 ++++++++++++++++++++++++++++++++--------
 1 file changed, 66 insertions(+), 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/05068aab/compiler/src/CFCBindSpecs.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCBindSpecs.c b/compiler/src/CFCBindSpecs.c
index 513806b..ff64eca 100644
--- a/compiler/src/CFCBindSpecs.c
+++ b/compiler/src/CFCBindSpecs.c
@@ -32,6 +32,7 @@ struct CFCBindSpecs {
     char *overridden_specs;
     char *inherited_specs;
     char *class_specs;
+    char *init_code;
 
     int num_novel;
     int num_overridden;
@@ -43,16 +44,20 @@ static char*
 S_ivars_size(CFCClass *klass);
 
 static char*
-S_novel_meth(CFCMethod *method, CFCClass *klass);
+S_novel_meth(CFCBindSpecs *self, CFCMethod *method, CFCClass *klass,
+             int meth_index);
 
 static char*
-S_parent_offset(CFCMethod *method, CFCClass *klass);
+S_parent_offset(CFCBindSpecs *self, CFCMethod *method, CFCClass *klass,
+                const char *meth_type, int meth_index);
 
 static char*
-S_overridden_meth(CFCMethod *method, CFCClass *klass);
+S_overridden_meth(CFCBindSpecs *self, CFCMethod *method, CFCClass *klass,
+                  int meth_index);
 
 static char*
-S_inherited_meth(CFCMethod *method, CFCClass *klass);
+S_inherited_meth(CFCBindSpecs *self, CFCMethod *method, CFCClass *klass,
+                 int meth_index);
 
 static const CFCMeta CFCBINDSPECS_META = {
     "Clownfish::CFC::Binding::Core::Specs",
@@ -72,6 +77,7 @@ CFCBindSpecs_init(CFCBindSpecs *self) {
     self->overridden_specs = CFCUtil_strdup("");
     self->inherited_specs  = CFCUtil_strdup("");
     self->class_specs      = CFCUtil_strdup("");
+    self->init_code        = CFCUtil_strdup("");
 
     return self;
 }
@@ -82,6 +88,7 @@ CFCBindSpecs_destroy(CFCBindSpecs *self) {
     FREEMEM(self->overridden_specs);
     FREEMEM(self->inherited_specs);
     FREEMEM(self->class_specs);
+    FREEMEM(self->init_code);
     CFCBase_destroy((CFCBase*)self);
 }
 
@@ -141,7 +148,23 @@ CFCBindSpecs_add_class(CFCBindSpecs *self, CFCClass *klass) {
         parent_ptr = CFCUtil_strdup("NULL");
     }
     else {
-        parent_ptr = CFCUtil_sprintf("&%s", CFCClass_full_class_var(parent));
+        if (CFCClass_get_parcel(klass) == CFCClass_get_parcel(parent)) {
+            parent_ptr
+                = CFCUtil_sprintf("&%s", CFCClass_full_class_var(parent));
+        }
+        else {
+            parent_ptr = CFCUtil_strdup("NULL");
+
+            const char *class_name = CFCClass_get_name(klass);
+            const char *parent_var = CFCClass_full_class_var(parent);
+            const char *pattern =
+                "    /* %s */\n"
+                "    class_specs[%d].parent = &%s;\n";
+            char *init_code = CFCUtil_sprintf(pattern, class_name,
+                                              self->num_specs, parent_var);
+            self->init_code = CFCUtil_cat(self->init_code, init_code, NULL);
+            FREEMEM(init_code);
+        }
     }
 
     char *novel_specs      = CFCUtil_strdup("");
@@ -158,14 +181,15 @@ CFCBindSpecs_add_class(CFCBindSpecs *self, CFCClass *klass) {
         if (CFCMethod_is_fresh(method, klass)) {
             if (CFCMethod_novel(method)) {
                 const char *sep = num_new_novel == 0 ? "" : ",\n";
-                char *def = S_novel_meth(method, klass);
+                char *def = S_novel_meth(self, method, klass, num_new_novel);
                 novel_specs = CFCUtil_cat(novel_specs, sep, def, NULL);
                 FREEMEM(def);
                 ++num_new_novel;
             }
             else {
                 const char *sep = num_new_overridden == 0 ? "" : ",\n";
-                char *def = S_overridden_meth(method, klass);
+                char *def = S_overridden_meth(self, method, klass,
+                                              num_new_overridden);
                 overridden_specs = CFCUtil_cat(overridden_specs, sep, def,
                                                NULL);
                 FREEMEM(def);
@@ -174,7 +198,8 @@ CFCBindSpecs_add_class(CFCBindSpecs *self, CFCClass *klass) {
         }
         else {
             const char *sep = num_new_inherited == 0 ? "" : ",\n";
-            char *def = S_inherited_meth(method, klass);
+            char *def = S_inherited_meth(self, method, klass,
+                                         num_new_inherited);
             inherited_specs = CFCUtil_cat(inherited_specs, sep, def, NULL);
             FREEMEM(def);
             ++num_new_inherited;
@@ -301,9 +326,11 @@ CFCBindSpecs_init_func_def(CFCBindSpecs *self) {
     const char *pattern =
         "static void\n"
         "S_bootstrap_specs() {\n"
+        "%s"
+        "\n"
         "    cfish_Class_bootstrap(class_specs, %d);\n"
         "}\n";
-    return CFCUtil_sprintf(pattern, self->num_specs);
+    return CFCUtil_sprintf(pattern, self->init_code, self->num_specs);
 }
 
 static char*
@@ -333,7 +360,10 @@ S_ivars_size(CFCClass *klass) {
 }
 
 static char*
-S_novel_meth(CFCMethod *method, CFCClass *klass) {
+S_novel_meth(CFCBindSpecs *self, CFCMethod *method, CFCClass *klass,
+             int meth_index) {
+    CHY_UNUSED_VAR(self);
+    CHY_UNUSED_VAR(meth_index);
     const char *meth_name = CFCMethod_get_name(method);
 
     char *full_override_sym;
@@ -365,25 +395,43 @@ S_novel_meth(CFCMethod *method, CFCClass *klass) {
 }
 
 static char*
-S_parent_offset(CFCMethod *method, CFCClass *klass) {
+S_parent_offset(CFCBindSpecs *self, CFCMethod *method, CFCClass *klass,
+                const char *meth_type, int meth_index) {
     CFCClass *parent = CFCClass_get_parent(klass);
 
     if (!parent) {
         return CFCUtil_strdup("NULL");
     }
 
+    char *parent_offset = NULL;
     char *parent_offset_sym = CFCMethod_full_offset_sym(method, parent);
-    char *parent_offset = CFCUtil_sprintf("&%s", parent_offset_sym);
+
+    if (CFCClass_get_parcel(parent) == CFCClass_get_parcel(klass)) {
+        parent_offset = CFCUtil_sprintf("&%s", parent_offset_sym);
+    }
+    else {
+        parent_offset = CFCUtil_strdup("NULL");
+
+        const char *class_var = CFCClass_full_class_var(klass);
+        char pattern[] = "    %s_%s_METHS[%d].parent_offset = &%s;\n";
+        char *code = CFCUtil_sprintf(pattern, class_var, meth_type, meth_index,
+                                     parent_offset_sym);
+        self->init_code = CFCUtil_cat(self->init_code, code, NULL);
+        FREEMEM(code);
+    }
+
     FREEMEM(parent_offset_sym);
 
     return parent_offset;
 }
 
 static char*
-S_overridden_meth(CFCMethod *method, CFCClass *klass) {
+S_overridden_meth(CFCBindSpecs *self, CFCMethod *method, CFCClass *klass,
+                  int meth_index) {
     char *imp_func        = CFCMethod_imp_func(method, klass);
     char *full_offset_sym = CFCMethod_full_offset_sym(method, klass);
-    char *parent_offset   = S_parent_offset(method, klass);
+    char *parent_offset   = S_parent_offset(self, method, klass, "OVERRIDDEN",
+                                            meth_index);
 
     char pattern[] =
         "    {\n"
@@ -401,9 +449,11 @@ S_overridden_meth(CFCMethod *method, CFCClass *klass) {
 }
 
 static char*
-S_inherited_meth(CFCMethod *method, CFCClass *klass) {
+S_inherited_meth(CFCBindSpecs *self, CFCMethod *method, CFCClass *klass,
+                 int meth_index) {
     char *full_offset_sym = CFCMethod_full_offset_sym(method, klass);
-    char *parent_offset   = S_parent_offset(method, klass);
+    char *parent_offset   = S_parent_offset(self, method, klass, "INHERITED",
+                                            meth_index);
 
     char pattern[] =
         "    {\n"