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 2016/06/01 12:01:57 UTC

[06/13] lucy-clownfish git commit: Rework Perl bootstrap process

Rework Perl bootstrap process

Use static arrays for class and XSUB specifications. Together with
using XS_INTERNAL, this reduces the size of the stripped Perl binary
of Lucy by 200 KB on Linux 32-bit.


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

Branch: refs/heads/master
Commit: 24c305fb03a1363ced98f5b204c910c8379a0140
Parents: 7575292
Author: Nick Wellnhofer <we...@aevum.de>
Authored: Mon May 30 14:21:04 2016 +0200
Committer: Nick Wellnhofer <we...@aevum.de>
Committed: Mon May 30 15:13:26 2016 +0200

----------------------------------------------------------------------
 compiler/src/CFCPerl.c    | 88 ++++++++++++++++++++++++++----------------
 compiler/src/CFCPerlSub.h |  5 +++
 runtime/perl/xs/XSBind.c  | 31 +++++++++++++++
 runtime/perl/xs/XSBind.h  | 22 +++++++++++
 4 files changed, 113 insertions(+), 33 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/24c305fb/compiler/src/CFCPerl.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCPerl.c b/compiler/src/CFCPerl.c
index 551220b..ec8c3b8 100644
--- a/compiler/src/CFCPerl.c
+++ b/compiler/src/CFCPerl.c
@@ -309,7 +309,6 @@ S_write_host_c(CFCPerl *self, CFCParcel *parcel) {
     char        *includes   = CFCUtil_strdup("");
     char        *cb_defs    = CFCUtil_strdup("");
     char        *alias_adds = CFCUtil_strdup("");
-    char        *isa_pushes = CFCUtil_strdup("");
 
     for (size_t i = 0; ordered[i] != NULL; i++) {
         CFCClass *klass = ordered[i];
@@ -359,17 +358,6 @@ S_write_host_c(CFCPerl *self, CFCParcel *parcel) {
             alias_adds = CFCUtil_cat(alias_adds, metadata_code, NULL);
             FREEMEM(metadata_code);
         }
-
-        CFCClass *parent = CFCClass_get_parent(klass);
-        if (parent) {
-            const char *parent_class_name = CFCClass_get_name(parent);
-            isa_pushes
-                = CFCUtil_cat(isa_pushes, "    isa = get_av(\"",
-                              class_name, "::ISA\", 1);\n", NULL);
-            isa_pushes
-                = CFCUtil_cat(isa_pushes, "    av_push(isa, newSVpv(\"", 
-                              parent_class_name, "\", 0));\n", NULL);
-        }
     }
 
     const char pattern[] =
@@ -469,16 +457,12 @@ S_write_host_c(CFCPerl *self, CFCParcel *parcel) {
         "    %sbootstrap_parcel();\n"
         "\n"
         "%s"
-        "\n"
-        "    AV *isa;\n"
-        "%s"
         "}\n"
         "\n"
         "%s";
     char *content
         = CFCUtil_sprintf(pattern, self->c_header, prefix, includes, cb_defs,
-                          prefix, prefix, alias_adds, isa_pushes,
-                          self->c_footer);
+                          prefix, prefix, alias_adds, self->c_footer);
 
     const char *src_dest = CFCHierarchy_get_source_dest(self->hierarchy);
     char *host_c_path = CFCUtil_sprintf("%s" CHY_DIR_SEP "%sperl.c", src_dest,
@@ -487,7 +471,6 @@ S_write_host_c(CFCPerl *self, CFCParcel *parcel) {
     FREEMEM(host_c_path);
 
     FREEMEM(content);
-    FREEMEM(isa_pushes);
     FREEMEM(alias_adds);
     FREEMEM(cb_defs);
     FREEMEM(includes);
@@ -544,7 +527,8 @@ CFCPerl_write_host_code(CFCPerl *self) {
 
 static char*
 S_xs_file_contents(CFCPerl *self, const char *generated_xs,
-                   const char *xs_init, const char *hand_rolled_xs) {
+                   const char *class_specs, const char *xsub_specs,
+                   const char *hand_rolled_xs) {
     char *bootstrap_calls = CFCUtil_strdup("");
     CFCParcel **parcels   = CFCParcel_all_parcels();
     for (size_t i = 0; parcels[i]; ++i) {
@@ -565,9 +549,20 @@ S_xs_file_contents(CFCPerl *self, const char *generated_xs,
         "\n"
         "BOOT:\n"
         "{\n"
+        "    static const cfish_XSBind_ClassSpec class_specs[] = {\n"
+        "%s\n"
+        "    };\n"
+        "    static const cfish_XSBind_XSubSpec xsub_specs[] = {\n"
+        "%s\n"
+        "    };\n"
+        "    size_t num_classes\n"
+        "        = sizeof(class_specs) / sizeof(class_specs[0]);\n"
         "    const char* file = __FILE__;\n"
+        "\n"
         "%s"
-        "%s"
+        "\n"
+        "    cfish_XSBind_bootstrap(aTHX_ num_classes, class_specs,\n"
+        "                           xsub_specs, file);\n"
         "}\n"
         "\n"
         "%s\n"
@@ -575,20 +570,22 @@ S_xs_file_contents(CFCPerl *self, const char *generated_xs,
         "%s";
     char *contents
         = CFCUtil_sprintf(pattern, self->c_header, generated_xs,
-                          self->boot_class, self->boot_class, bootstrap_calls,
-                          xs_init, hand_rolled_xs, self->c_footer);
+                          self->boot_class, self->boot_class, class_specs,
+                          xsub_specs, bootstrap_calls, hand_rolled_xs,
+                          self->c_footer);
 
     FREEMEM(bootstrap_calls);
     return contents;
 }
 
 static char*
-S_add_xs_init(char *xs_init, CFCPerlSub *xsub) {
+S_add_xsub_spec(char *xsub_specs, CFCPerlSub *xsub) {
     const char *c_name = CFCPerlSub_c_name(xsub);
-    const char *perl_name = CFCPerlSub_perl_name(xsub);
-    xs_init = CFCUtil_cat(xs_init, "    newXS(\"", perl_name, "\", ", c_name,
-                          ", file);\n", NULL);
-    return xs_init;
+    const char *alias = CFCPerlSub_get_alias(xsub);
+    const char *sep = xsub_specs[0] == '\0' ? "" : ",\n";
+    xsub_specs = CFCUtil_cat(xsub_specs, sep, "        { \"", alias, "\", ",
+                             c_name, " }", NULL);
+    return xsub_specs;
 }
 
 void
@@ -598,7 +595,8 @@ CFCPerl_write_bindings(CFCPerl *self) {
     CFCPerlClass **registry = CFCPerlClass_registry();
     char *hand_rolled_xs   = CFCUtil_strdup("");
     char *generated_xs     = CFCUtil_strdup("");
-    char *xs_init          = CFCUtil_strdup("");
+    char *class_specs      = CFCUtil_strdup("");
+    char *xsub_specs       = CFCUtil_strdup("");
 
     // Bake the parcel privacy defines into the XS, so it can be compiled
     // without any extra compiler flags.
@@ -640,7 +638,9 @@ CFCPerl_write_bindings(CFCPerl *self) {
 
     for (size_t i = 0; ordered[i] != NULL; i++) {
         CFCClass *klass = ordered[i];
-        if (CFCClass_included(klass)) { continue; }
+        if (CFCClass_included(klass) || CFCClass_inert(klass)) { continue; }
+
+        int num_xsubs = 0;
 
         // Constructors.
         CFCPerlConstructor **constructors
@@ -656,7 +656,8 @@ CFCPerl_write_bindings(CFCPerl *self) {
             FREEMEM(xsub_def);
 
             // Add XSUB initialization at boot.
-            xs_init = S_add_xs_init(xs_init, xsub);
+            xsub_specs = S_add_xsub_spec(xsub_specs, xsub);
+            num_xsubs += 1;
 
             CFCBase_decref((CFCBase*)constructors[j]);
         }
@@ -674,11 +675,30 @@ CFCPerl_write_bindings(CFCPerl *self) {
             FREEMEM(xsub_def);
 
             // Add XSUB initialization at boot.
-            xs_init = S_add_xs_init(xs_init, xsub);
+            xsub_specs = S_add_xsub_spec(xsub_specs, xsub);
+            num_xsubs += 1;
 
             CFCBase_decref((CFCBase*)methods[j]);
         }
         FREEMEM(methods);
+
+        // Append XSBind_ClassSpec entry.
+        const char *class_name = CFCClass_get_name(klass);
+        CFCClass *parent = CFCClass_get_parent(klass);
+        char *parent_name;
+        if (parent) {
+            parent_name = CFCUtil_sprintf("\"%s\"", CFCClass_get_name(parent));
+        }
+        else {
+            parent_name = CFCUtil_strdup("NULL");
+        }
+        char *class_spec = CFCUtil_sprintf("{ \"%s\", %s, %d }", class_name,
+                                           parent_name, num_xsubs);
+        const char *sep = class_specs[0] == '\0' ? "" : ",\n";
+        class_specs = CFCUtil_cat(class_specs, sep, "        ", class_spec,
+                                  NULL);
+        FREEMEM(class_spec);
+        FREEMEM(parent_name);
     }
 
     // Hand-rolled XS.
@@ -689,13 +709,15 @@ CFCPerl_write_bindings(CFCPerl *self) {
 
     // Write out if there have been any changes.
     char *xs_file_contents
-        = S_xs_file_contents(self, generated_xs, xs_init, hand_rolled_xs);
+        = S_xs_file_contents(self, generated_xs, class_specs, xsub_specs,
+                             hand_rolled_xs);
     CFCUtil_write_if_changed(self->xs_path, xs_file_contents,
                              strlen(xs_file_contents));
 
     FREEMEM(xs_file_contents);
     FREEMEM(hand_rolled_xs);
-    FREEMEM(xs_init);
+    FREEMEM(xsub_specs);
+    FREEMEM(class_specs);
     FREEMEM(generated_xs);
     FREEMEM(ordered);
 }

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/24c305fb/compiler/src/CFCPerlSub.h
----------------------------------------------------------------------
diff --git a/compiler/src/CFCPerlSub.h b/compiler/src/CFCPerlSub.h
index 7d33ea2..a68c0f1 100644
--- a/compiler/src/CFCPerlSub.h
+++ b/compiler/src/CFCPerlSub.h
@@ -98,6 +98,11 @@ CFCPerlSub_get_param_list(CFCPerlSub *self);
 const char*
 CFCPerlSub_get_class_name(CFCPerlSub *self);
 
+/** Accessor for alias.
+ */
+const char*
+CFCPerlSub_get_alias(CFCPerlSub *self);
+
 /** Accessor for use_labeled_params.
  */
 int

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/24c305fb/runtime/perl/xs/XSBind.c
----------------------------------------------------------------------
diff --git a/runtime/perl/xs/XSBind.c b/runtime/perl/xs/XSBind.c
index 515e752..4839f98 100644
--- a/runtime/perl/xs/XSBind.c
+++ b/runtime/perl/xs/XSBind.c
@@ -521,6 +521,37 @@ XSBind_undef_arg_error(pTHX_ const char *label) {
     THROW(CFISH_ERR, "'%s' must not be undef", label);
 }
 
+void
+XSBind_bootstrap(pTHX_ size_t num_classes,
+                 const XSBind_ClassSpec *class_specs,
+                 const XSBind_XSubSpec *xsub_specs,
+                 const char *file) {
+    size_t xsub_idx = 0;
+
+    for (size_t i = 0; i < num_classes; i++) {
+        const XSBind_ClassSpec *class_spec = &class_specs[i];
+
+        // Set up @ISA array.
+        if (class_spec->parent_name) {
+            cfish_String *isa_name
+                = cfish_Str_newf("%s::ISA", class_spec->name);
+            AV *isa = get_av(CFISH_Str_Get_Ptr8(isa_name), 1);
+            av_push(isa, newSVpv(class_spec->parent_name, 0));
+            CFISH_DECREF(isa_name);
+        }
+
+        // Register XSUBs.
+        for (uint32_t j = 0; j < class_spec->num_methods; j++) {
+            const XSBind_XSubSpec *xsub_spec = &xsub_specs[xsub_idx++];
+
+            cfish_String *xsub_name
+                = cfish_Str_newf("%s::%s", class_spec->name, xsub_spec->alias);
+            newXS(CFISH_Str_Get_Ptr8(xsub_name), xsub_spec->xsub, file);
+            CFISH_DECREF(xsub_name);
+        }
+    }
+}
+
 /***************************************************************************
  * The routines below are declared within the Clownfish core but left
  * unimplemented and must be defined for each host language.

http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/24c305fb/runtime/perl/xs/XSBind.h
----------------------------------------------------------------------
diff --git a/runtime/perl/xs/XSBind.h b/runtime/perl/xs/XSBind.h
index 03ee676..32a9e69 100644
--- a/runtime/perl/xs/XSBind.h
+++ b/runtime/perl/xs/XSBind.h
@@ -44,6 +44,17 @@
 extern "C" {
 #endif
 
+typedef struct cfish_XSBind_ClassSpec {
+    const char *name;
+    const char *parent_name;
+    uint32_t    num_methods;
+} cfish_XSBind_ClassSpec;
+
+typedef struct cfish_XSBind_XSubSpec {
+    const char *alias;
+    XSUBADDR_t  xsub;
+} cfish_XSBind_XSubSpec;
+
 typedef struct cfish_XSBind_ParamSpec {
     const char *label;
     uint16_t    label_len;
@@ -203,6 +214,14 @@ cfish_XSBind_invalid_args_error(pTHX_ CV *cv, const char *param_list);
 CFISH_VISIBLE void
 cfish_XSBind_undef_arg_error(pTHX_ const char *label);
 
+/** Initialize ISA relations and XSUBs.
+ */
+CFISH_VISIBLE void
+cfish_XSBind_bootstrap(pTHX_ size_t num_classes,
+                       const cfish_XSBind_ClassSpec *class_specs,
+                       const cfish_XSBind_XSubSpec *xsub_specs,
+                       const char *file);
+
 #define XSBIND_PARAM(key, required) \
     { key, (int16_t)sizeof("" key) - 1, (char)required }
 
@@ -212,6 +231,8 @@ cfish_XSBind_undef_arg_error(pTHX_ const char *label);
  * full symbols nevertheless in case someone else defines e.g. a function
  * named "XSBind_sv_defined".)
  */
+#define XSBind_ClassSpec               cfish_XSBind_ClassSpec
+#define XSBind_XSubSpec                cfish_XSBind_XSubSpec
 #define XSBind_ParamSpec               cfish_XSBind_ParamSpec
 #define XSBind_new_blank_obj           cfish_XSBind_new_blank_obj
 #define XSBind_foster_obj              cfish_XSBind_foster_obj
@@ -230,6 +251,7 @@ cfish_XSBind_undef_arg_error(pTHX_ const char *label);
 #define XSBind_arg_to_cfish_nullable   cfish_XSBind_arg_to_cfish_nullable
 #define XSBind_invalid_args_error      cfish_XSBind_invalid_args_error
 #define XSBind_undef_arg_error         cfish_XSBind_undef_arg_error
+#define XSBind_bootstrap               cfish_XSBind_bootstrap
 
 /* Strip the prefix from some common ClownFish symbols where we know there's
  * no conflict with Perl.  It's a little inconsistent to do this rather than