lucy-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mar...@apache.org
Subject [lucy-commits] svn commit: r1332895 - in /lucy/branches/LUCY-234-struct-ABI: README app.c core.c core.h module.c module.h
Date Wed, 02 May 2012 01:51:01 GMT
Author: marvin
Date: Wed May  2 01:51:00 2012
New Revision: 1332895

URL: http://svn.apache.org/viewvc?rev=1332895&view=rev
Log:
LUCY-234 Brittle object struct ABI

Add a proof-of-concept project illustrating one approach to addressing the
brittle object struct ABI issue, adapting techniques developed from C++.

Added:
    lucy/branches/LUCY-234-struct-ABI/README
    lucy/branches/LUCY-234-struct-ABI/app.c   (with props)
    lucy/branches/LUCY-234-struct-ABI/core.c   (with props)
    lucy/branches/LUCY-234-struct-ABI/core.h   (with props)
    lucy/branches/LUCY-234-struct-ABI/module.c   (with props)
    lucy/branches/LUCY-234-struct-ABI/module.h   (with props)

Added: lucy/branches/LUCY-234-struct-ABI/README
URL: http://svn.apache.org/viewvc/lucy/branches/LUCY-234-struct-ABI/README?rev=1332895&view=auto
==============================================================================
--- lucy/branches/LUCY-234-struct-ABI/README (added)
+++ lucy/branches/LUCY-234-struct-ABI/README Wed May  2 01:51:00 2012
@@ -0,0 +1,209 @@
+========
+SYNOPSIS
+========
+
+Clownfish's current handling of object struct definitions has certain
+drawbacks:
+
+  * If an upstream parcel adds, removes or rearranges its member variables,
+    downstream extensions will break.
+  * Subclasses have direct access to all ancestor class member variables,
+    including those defined in upstream parcels.
+  * The current implementation violates "strict aliasing".
+
+The files in this directory are a proof-of-concept which illustrates one
+possible strategy for addressing these issues, adapting techniques used
+for implementing multiple inheritance in C++.
+
+=======
+DETAILS
+=======
+
+In the current Clownfish implementation, subclasses tack their member
+variables onto the end of the parent struct.
+
+    struct cfish_Obj {
+        cfish_VTable *vtable;
+        cfish_ref_t   ref;
+    };
+    struct Query {
+        cfish_VTable *vtable;
+        cfish_ref_t   ref;
+        float         boost;
+    };
+    struct lucy_TermQuery {
+        cfish_VTable  *vtable;
+        cfish_ref_t    ref;
+        float          boost;
+        cfish_CharBuf *field;
+        cfish_Obj     *term;
+    };
+
+This is true even when the subclass is in a different parcel:
+
+    struct ext_MyTermQuery {
+        cfish_VTable  *vtable;
+        cfish_ref_t    ref;
+        float          boost;
+        cfish_CharBuf *field;
+        cfish_Obj     *term;
+        int32_t        number;
+    };
+
+Laying out subclass structs identically to their ancestors allows us to cast
+the object pointers between different types.
+
+    TermQuery *as_term_query = (TermQuery*)my_term_query;
+    Query     *as_query      = (Query*)my_term_query;
+    printf("As MyTermQuery: %f\n", my_term_query->boost);
+    printf("As TermQuery: %f\n",   as_term_query->boost);
+    printf("As Query: %f\n",       as_query->boost);
+
+However, it also freezes the upstream struct layout.  For example, Lucy
+cannot switch the positions of "term" and "field" within the TermQuery struct
+without causing the downstream extension MyTermQuery to break.
+
+Additionally, the present system violates the C standard's "strict aliasing"
+rules, which state that different data pointer types may not reference the
+same memory location.  Here's an excerpt from a thread on the Python
+developers list where they wrestle with the same issue:
+
+    http://mail.python.org/pipermail/python-dev/2003-July/036909.html
+
+    > Does this mean that code like:
+    > 
+    >     void f (PyObject *a, PyDictObject *b)
+    >     {
+    >         a->ob_refcnt += 1;
+    >         b->ob_refcnt -= 1;
+    >     }
+    >     [...]
+    >         f((PyObject *)somedict, somedict);
+    > 
+    > is disallowed?
+
+    Correct. 
+
+There isn't really a good way for Clownfish to declare the upstream struct
+opaque while tacking new variables onto the end of it:
+
+    // Invalid unless the struct definition for lucy_TermQuery is known.
+    struct ext_MyTermQuery {
+        struct lucy_TermQuery;
+        int32_t number;
+    };
+
+We could pull some funny business with runtime pointer math, but it would make
+writing extensions awkward because struct members cannot be accessed directly.
+
+    struct MyTermQueryData {
+        int32_t number;
+    };
+
+    static inline MyTermQueryData*
+    S_child_data(MyTermQuery *self) {
+        size_t offset = Cfish_VTable_Get_Obj_Alloc_Size(LUCY_TERMQUERY);
+        return (MyTermQueryData*)((char*)self + offset);
+    }
+
+    static int32_t
+    S_MyTermQuery_get_number(MyTermQuery *self) {
+        return S_child_data(self)->number;     // <---------- yuck.
+    }
+
+(Note that certain memory alignment pitfalls are not dealt with in that code
+sample or others which follow.)
+
+However, if we grow the struct definition *backwards*, so that the parent
+struct comes *after* the subclass member variables in memory, the subclass
+gets direct access to its own variables.
+
+    struct ext_MyTermQuery {
+        cfish_VTable *vtable;
+        int32_t       number;
+        // struct lucy_TermQuery superself;  <--- implicit
+    };
+
+    static int32_t
+    S_MyTermQuery_get_number(MyTermQuery *self) {
+       return self->number;     // <---------- idomatic, efficient C
+    }
+
+At runtime, when heap memory is allocated for a MyTermQuery object, the size
+of the parent TermQuery struct is known.  Here's some verbose sample code
+demonstrating how a MyTermQuery object can be initialized:
+
+    size_t size = sizeof(ext_MyTermQuery)
+                  + Cfish_VTable_Get_Obj_Alloc_Size(LUCY_TERMQUERY);
+    ext_MyTermQuery *self = (ext_MyTermQuery*)malloc(size);
+    self->vtable = EXT_MYTERMQUERY;
+    self->number = number;
+    lucy_TermQuery *superself
+        = (lucy_TermQuery*)((char*)self + sizeof(ext_MyTermQuery));
+    superself->vtable = LUCY_TERMQUERY;
+    lucy_TermQuery_init(superself, field, term);
+    return self;
+
+Within a parcel, parent object structs can be embedded directly...
+
+    struct lucy_TermQuery {
+        cfish_VTable  *vtable;
+        float          boost;
+        cfish_CharBuf *field;
+        cfish_Obj     *term;
+        lucy_Query     superself; // <---- explicit
+    };
+
+... which allows subclasses direct access:
+
+    float boost = term_query->superself.boost;
+
+Of course the problem now is that once subclasses no longer duplicate the
+memory layout of their ancestors, a simple cast no longer suffices -- we need
+to use "pointer fixups" a la C++ to make sure that the "self" that gets sent
+to a method has the layout the method needs.
+
+This proof-of-concept project adapts Clownfish-style OFFSET vars to encode
+both the method offset and fixup information.  The "pointer fixup" goes in the
+upper 32-bits, and the method offset goes in the lower 32 bits.
+
+    static inline void
+    Dog_speak(Dog *self) {
+        const uint64_t offsets = Dog_speak_OFFSETS;
+        void *const view = (char*)self + (int32_t)(offsets >> 32);
+        char *const method_address = *(char**)self + (uint32_t)offsets;
+        Dog_speak_t method = *((Dog_speak_t*)method_address);
+        method(view);
+    }
+
+For more information, see the source files.
+
+PRO:
+
+  * Upstream parcels can add, remove, or rearrange member variables at will
+    without breaking the ABI.
+  * Our basic object model will no longer violate strict aliasing rules.  We
+    may eventually be able to compile without -fno-strict-aliasing and reap
+    the optimization benefits.
+  * Encapsulation-friendly.  A subclass only has direct access to the member
+    vars of ancestor classes defined within the same parcel. 
+ 
+CON:
+
+  * Increased complexity, though that complexity is mostly hidden away in
+    CFC and autogenerated code.
+  * Increased object memory footprint: 1 pointer for every ancestor.  (We
+    should be able to cut this down to "1 pointer for each ancestor with
+    member variables".)
+  * Each method invocation now has a couple more ops.
+  * Additional boot code.
+  * More OFFSET vars: we're back to needing approximately one for each
+    method/invocant pairing.
+  * Changes to Lucy code will be required in addition to the changes to CFC.
+
+The additional ops per method invocation and startup costs should be measured,
+but hopefully the method invocation ops will prove negligible on a modern
+pipelining processor -- the memory fetch costs per invocation have not
+changed.
+
+

Added: lucy/branches/LUCY-234-struct-ABI/app.c
URL: http://svn.apache.org/viewvc/lucy/branches/LUCY-234-struct-ABI/app.c?rev=1332895&view=auto
==============================================================================
--- lucy/branches/LUCY-234-struct-ABI/app.c (added)
+++ lucy/branches/LUCY-234-struct-ABI/app.c Wed May  2 01:51:00 2012
@@ -0,0 +1,46 @@
+/* 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 <stdio.h>
+#include "core.h"
+#include "module.h"
+
+int main() {
+    Core_bootstrap();
+    Module_bootstrap();
+
+    Dog *fido = Dog_new("Fido");
+    printf("This is my dog, Fido:\n    ");
+    Dog_speak(fido);
+    printf("Here, Fido!\n    ");
+    Dog_ignore_name(fido);
+    printf("OK, never mind then.  Bye Fido!\n\n");
+    Dog_destroy(fido);
+    
+    Boxer *drago = Boxer_new("Drago");
+    printf("This is my my friend's dog, Drago:\n    ");
+    Boxer_speak(drago);
+    printf("Here, Drago!\n    ");
+    Boxer_ignore_name(drago);
+    printf("OK, never mind.\nDrago is a boxer.\n    ");
+    Boxer_drool(drago);
+    printf("Bye, Drago!\n");
+    Boxer_destroy(drago);
+
+    Module_tear_down();
+    Core_tear_down();
+}
+

Propchange: lucy/branches/LUCY-234-struct-ABI/app.c
------------------------------------------------------------------------------
    svn:eol-style = native

Added: lucy/branches/LUCY-234-struct-ABI/core.c
URL: http://svn.apache.org/viewvc/lucy/branches/LUCY-234-struct-ABI/core.c?rev=1332895&view=auto
==============================================================================
--- lucy/branches/LUCY-234-struct-ABI/core.c (added)
+++ lucy/branches/LUCY-234-struct-ABI/core.c Wed May  2 01:51:00 2012
@@ -0,0 +1,234 @@
+/* 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "core.h"
+
+struct Object {
+    MetaClass *metaclass;
+};
+
+struct MetaClass {
+    MetaClass *metaclass;
+    MetaClass *parent;
+    char *name;
+    size_t obj_alloc_size;
+    size_t num_methods;
+    size_t method_count;
+    Object superself;
+};
+
+uint64_t Obj_destroy_OFFSETS;
+static void
+S_Obj_destroy(Object *self) {
+    ptrdiff_t fixup = (ptrdiff_t)self->metaclass->obj_alloc_size
+                      - (ptrdiff_t)sizeof(Object);
+    char *ptr = (char*)self - fixup;
+    free(ptr);
+}
+
+/************************************************************************/
+
+// Methods are allocated immediately after the end of the MetaClass struct.
+method_t*
+S_methods(MetaClass *self) {
+    return (method_t*)((char*)self + sizeof(MetaClass));
+}
+
+uint64_t MetaClass_destroy_OFFSETS;
+static void
+S_MetaClass_destroy(MetaClass *self);
+
+uint64_t MetaClass_make_obj_OFFSETS;
+static void*
+S_MetaClass_make_obj(MetaClass *self);
+
+uint64_t MetaClass_add_novel_method_OFFSETS;
+static uint64_t
+S_MetaClass_add_novel_method(MetaClass *self, method_t method);
+
+uint64_t MetaClass_override_method_OFFSETS;
+static uint64_t
+S_MetaClass_override_method(MetaClass *self, method_t method, uint64_t offsets);
+
+uint64_t MetaClass_inherit_method_OFFSETS;
+static uint64_t
+S_MetaClass_inherit_method(MetaClass *self, uint64_t offsets);
+
+uint64_t MetaClass_get_num_methods_OFFSETS;
+static size_t
+S_MetaClass_get_num_methods(MetaClass *self);
+
+uint64_t MetaClass_get_obj_alloc_size_OFFSETS;
+static size_t
+S_MetaClass_get_obj_alloc_size(MetaClass *self);
+
+MetaClass *cMETACLASS = NULL;
+MetaClass *cOBJECT    = NULL;
+
+void
+Core_bootstrap(void) {
+    // Init Object's MetaClass.
+    cOBJECT = MetaClass_new(NULL, "Object", sizeof(Object), 1);
+    Obj_destroy_OFFSETS
+        = S_MetaClass_add_novel_method(cOBJECT, (method_t)S_Obj_destroy);
+
+    // Init MetaClass's MetaClass.
+    cMETACLASS = MetaClass_new(cOBJECT, "MetaClass", sizeof(MetaClass), 8);
+    MetaClass_destroy_OFFSETS
+        = S_MetaClass_add_novel_method(cMETACLASS, (method_t)S_MetaClass_destroy);
+    MetaClass_make_obj_OFFSETS
+        = S_MetaClass_add_novel_method(cMETACLASS, (method_t)S_MetaClass_make_obj);
+    MetaClass_add_novel_method_OFFSETS
+        = S_MetaClass_add_novel_method(cMETACLASS, (method_t)S_MetaClass_add_novel_method);
+    MetaClass_override_method_OFFSETS
+        = S_MetaClass_add_novel_method(cMETACLASS, (method_t)S_MetaClass_override_method);
+    MetaClass_inherit_method_OFFSETS
+        = S_MetaClass_add_novel_method(cMETACLASS, (method_t)S_MetaClass_inherit_method);
+    MetaClass_get_num_methods_OFFSETS
+        = S_MetaClass_add_novel_method(cMETACLASS, (method_t)S_MetaClass_get_num_methods);
+    MetaClass_get_obj_alloc_size_OFFSETS
+        = S_MetaClass_add_novel_method(cMETACLASS, (method_t)S_MetaClass_get_obj_alloc_size);
+
+    // Hack around circular dependency.
+    cOBJECT->metaclass = cMETACLASS;
+}
+
+void
+Core_tear_down(void) {
+    S_MetaClass_destroy(cOBJECT);
+    S_MetaClass_destroy(cMETACLASS);
+}
+
+static void
+S_dummy_method(void *self) {
+    (void)self;
+    abort();
+}
+
+MetaClass*
+MetaClass_new(MetaClass *parent, const char *name, size_t obj_alloc_size,
+              size_t num_methods) {
+    size_t size = sizeof(MetaClass) + sizeof(method_t) * num_methods;
+    MetaClass *self      = (MetaClass*)calloc(size, 1);
+    self->metaclass      = cMETACLASS;
+    self->name           = strdup(name);
+    self->num_methods    = num_methods;
+    self->method_count   = 0;
+    self->obj_alloc_size = obj_alloc_size;
+    self->parent         = parent;
+    self->superself.metaclass = cMETACLASS;
+
+    // Dupe parent's method pointers, use a dummy placeholder for the rest.
+    method_t *methods = S_methods(self);
+    if (parent) {
+        method_t *parent_methods = S_methods(parent);
+        while (self->method_count < parent->method_count) {
+            methods[self->method_count] = parent_methods[self->method_count];
+            self->method_count++;
+        }
+    }
+    for (size_t i = self->method_count; i < self->num_methods; i++) {
+        methods[i] = S_dummy_method;
+    }
+
+    return self;
+}
+
+static void
+S_MetaClass_destroy(MetaClass *self) {
+    free(self->name);
+    free(self);
+}
+
+static void*
+S_MetaClass_make_obj(MetaClass *self) {
+    Object *obj = (Object*)calloc(1, self->obj_alloc_size);
+    MetaClass *ancestor = self;
+    Object *view = obj;
+    while (ancestor) {
+        view->metaclass = self;
+        if (ancestor->parent) {
+            size_t fixup = ancestor->obj_alloc_size
+                           - ancestor->parent->obj_alloc_size;
+            view = (Object*)((char*)view + fixup);
+        }
+        ancestor = ancestor->parent;
+    }
+    return obj;
+}
+
+static uint64_t
+S_MetaClass_add_novel_method(MetaClass *self, method_t method) {
+    if (self->method_count >= self->num_methods) {
+        abort();
+    }
+
+    // Store the method pointer at the next location.
+    size_t offset = sizeof(MetaClass) + self->method_count * sizeof(method_t);
+    union { char *char_ptr; method_t *func_ptr; } pointer;
+    pointer.char_ptr = ((char*)self) + offset;
+    pointer.func_ptr[0] = method;
+    self->method_count++;
+
+    // Encode method vtable offset in the lower 32 bits.  The upper 32-bits,
+    // used to encode the "self" pointer fixup, are left all zeroes because no
+    // fixup is necessary for a "fresh" method implementation.
+    if (offset > UINT32_MAX) {
+        abort(); // Guard against unlikely integer overflow.
+    }
+    return offset;
+}
+
+static uint64_t 
+S_MetaClass_override_method(MetaClass *self, method_t method,
+                            uint64_t offsets) {
+    // Store the supplied method pointer at the specified location.
+    union { char *char_ptr; method_t *func_ptr; } pointer;
+    pointer.char_ptr = ((char*)self) + (uint32_t)offsets;
+    pointer.func_ptr[0] = method;
+
+    // Return an offsets var with the method offset in the lower 32 bits, and
+    // the top 32 bits all zeros to encode a fixup of 0 for this "fresh"
+    // method.
+    return (offsets & 0xFFFFFFFF);
+}
+
+static uint64_t
+S_MetaClass_inherit_method(MetaClass *self, uint64_t offsets) {
+    // Encode "self" pointer fixup in top 32 bits of OFFSETS var.
+    int32_t fixup = (int32_t)(offsets >> 32);
+    fixup += (self->obj_alloc_size - self->parent->obj_alloc_size);
+    int64_t new_offsets = ((int64_t)fixup) << 32;
+
+    // Encode method vtable offset in lower 32 bits.
+    new_offsets |= (offsets & 0xFFFFFFFF);
+
+    return new_offsets;
+}
+
+static size_t
+S_MetaClass_get_num_methods(MetaClass *self) {
+    return self->num_methods;
+}
+
+static size_t
+S_MetaClass_get_obj_alloc_size(MetaClass *self) {
+    return self->obj_alloc_size;
+}

Propchange: lucy/branches/LUCY-234-struct-ABI/core.c
------------------------------------------------------------------------------
    svn:eol-style = native

Added: lucy/branches/LUCY-234-struct-ABI/core.h
URL: http://svn.apache.org/viewvc/lucy/branches/LUCY-234-struct-ABI/core.h?rev=1332895&view=auto
==============================================================================
--- lucy/branches/LUCY-234-struct-ABI/core.h (added)
+++ lucy/branches/LUCY-234-struct-ABI/core.h Wed May  2 01:51:00 2012
@@ -0,0 +1,181 @@
+/* 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.
+ */
+
+#ifndef CORE_H
+#define CORE_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+// Generic method pointer.
+typedef void
+(*method_t)(void *self);
+
+/** Boostrap the core.
+ */
+void
+Core_bootstrap(void);
+
+/** Clean up after Core_bootstrap().
+ */
+void
+Core_tear_down(void);
+
+/** Base object type.
+ */
+typedef struct Object Object;
+
+/** Destructor.
+ */
+typedef void 
+(*Obj_destroy_t)(Object *self);
+extern uint64_t Obj_destroy_OFFSETS;
+static inline void
+Obj_destroy(Object *self) {
+    const uint64_t offsets = Obj_destroy_OFFSETS;
+    void *const view = (char*)self + (int32_t)(offsets >> 32);
+    char *const method_address = *(char**)self + (uint32_t)offsets;
+    Obj_destroy_t method = *((Obj_destroy_t*)method_address);
+    method(view);
+}
+
+/** Class data, including virtual method table.
+ */
+typedef struct MetaClass MetaClass;
+
+// Core MetaClasses.
+extern MetaClass *cMETACLASS;
+extern MetaClass *cOBJECT;
+
+static inline method_t
+MetaClass_method_pointer(MetaClass *self, int64_t offsets) {
+    char *const method_address = *(char**)self + (uint32_t)offsets;
+    return *((method_t*)method_address);
+}
+
+/** Constructor.
+ */
+MetaClass*
+MetaClass_new(MetaClass *superclass, const char *name, size_t obj_alloc_size,
+              size_t num_methods);
+
+/** Destructor.
+ */
+typedef void 
+(*MetaClass_destroy_t)(MetaClass *self);
+extern uint64_t MetaClass_destroy_OFFSETS;
+static inline void
+MetaClass_destroy(MetaClass *self) {
+    const uint64_t offsets = MetaClass_destroy_OFFSETS;
+    void *const view = (char*)self + (int32_t)(offsets >> 32);
+    char *const method_address = *(char**)self + (uint32_t)offsets;
+    MetaClass_destroy_t method = *((MetaClass_destroy_t*)method_address);
+    method(view);
+}
+
+/** Allocate a new object.
+ */
+typedef void*
+(*MetaClass_make_obj_t)(MetaClass *self);
+extern uint64_t MetaClass_make_obj_OFFSETS;
+static inline void*
+MetaClass_make_obj(MetaClass *self) {
+    const uint64_t offsets = MetaClass_make_obj_OFFSETS;
+    void *const view = (char*)self + (int32_t)(offsets >> 32);
+    char *const method_address = *(char**)self + (uint32_t)offsets;
+    MetaClass_make_obj_t method = *((MetaClass_make_obj_t*)method_address);
+    return method(view);
+}
+
+/** Add a new method to the MetaClass.  Return the offsets data needed to invoke
+ * the method.
+ */
+typedef uint64_t
+(*MetaClass_add_novel_method_t)(MetaClass *self, method_t method);
+extern uint64_t MetaClass_add_novel_method_OFFSETS;
+static inline uint64_t
+MetaClass_add_novel_method(MetaClass *self, method_t method) {
+    const uint64_t offsets = MetaClass_add_novel_method_OFFSETS;
+    void *const view = (char*)self + (int32_t)(offsets >> 32);
+    char *const method_address = *(char**)self + (uint32_t)offsets;
+    MetaClass_add_novel_method_t meth = *((MetaClass_add_novel_method_t*)method_address);
+    return meth(view, method);
+}
+
+/** Override an existing method, installing <code>method</code> at the
+ * location specified by <code>offsets</code>.  Return the offsets data needed
+ * to invoke the method.
+ */
+typedef uint64_t 
+(*MetaClass_override_method_t)(MetaClass *self, method_t method, uint64_t offsets);
+extern uint64_t MetaClass_override_method_OFFSETS;
+static inline uint64_t
+MetaClass_override_method(MetaClass *self, method_t method, uint64_t offsets) {
+    const uint64_t offs = MetaClass_override_method_OFFSETS;
+    void *const view = (char*)self + (int32_t)(offs >> 32);
+    char *const method_address = *(char**)self + (uint32_t)offs;
+    MetaClass_override_method_t meth = *((MetaClass_override_method_t*)method_address);
+    return meth(view, method, offsets);
+}
+
+/** Inherit a method from a parent class and generate the necessary offset
+ * invocation data.
+ *
+ * NOTE: This task will be performed by autogenerated code in production.
+ */
+typedef uint64_t
+(*MetaClass_inherit_method_t)(MetaClass *self, uint64_t offsets);
+extern uint64_t MetaClass_inherit_method_OFFSETS;
+static inline uint64_t
+MetaClass_inherit_method(MetaClass *self, uint64_t offsets) {
+    const uint64_t offs = MetaClass_inherit_method_OFFSETS;
+    void *const view = (char*)self + (int32_t)(offs >> 32);
+    char *const method_address = *(char**)self + (uint32_t)offs;
+    MetaClass_inherit_method_t method = *((MetaClass_inherit_method_t*)method_address);
+    return method(view, offsets);
+}
+
+/** Return the number of methods that the VTable will have when it is
+ * finished initializing.
+ */
+typedef size_t
+(*MetaClass_get_num_methods_t)(MetaClass *self);
+extern uint64_t MetaClass_get_num_methods_OFFSETS;
+static inline size_t 
+MetaClass_get_num_methods(MetaClass *self) {
+    const uint64_t offsets = MetaClass_get_num_methods_OFFSETS;
+    void *const view = (char*)self + (int32_t)(offsets >> 32);
+    char *const method_address = *(char**)self + (uint32_t)offsets;
+    MetaClass_get_num_methods_t method = *((MetaClass_get_num_methods_t*)method_address);
+    return method(view);
+}
+
+/** Return the size of the an object belonging to the specified class.
+ */
+typedef size_t
+(*MetaClass_get_obj_alloc_size_t)(MetaClass *self);
+extern uint64_t MetaClass_get_obj_alloc_size_OFFSETS;
+static inline size_t 
+MetaClass_get_obj_alloc_size(MetaClass *self) {
+    const uint64_t offsets = MetaClass_get_obj_alloc_size_OFFSETS;
+    void *const view = (char*)self + (int32_t)(offsets >> 32);
+    char *const method_address = *(char**)self + (uint32_t)offsets;
+    MetaClass_get_obj_alloc_size_t method = *((MetaClass_get_obj_alloc_size_t*)method_address);
+    return method(view);
+}
+
+#endif /* CORE_H */
+

Propchange: lucy/branches/LUCY-234-struct-ABI/core.h
------------------------------------------------------------------------------
    svn:eol-style = native

Added: lucy/branches/LUCY-234-struct-ABI/module.c
URL: http://svn.apache.org/viewvc/lucy/branches/LUCY-234-struct-ABI/module.c?rev=1332895&view=auto
==============================================================================
--- lucy/branches/LUCY-234-struct-ABI/module.c (added)
+++ lucy/branches/LUCY-234-struct-ABI/module.c Wed May  2 01:51:00 2012
@@ -0,0 +1,162 @@
+/* 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "module.h"
+
+struct Animal {
+    MetaClass *metaclass;
+    void *superself;
+};
+
+struct Dog {
+    MetaClass *metaclass;
+    char *name;
+    Animal superself;
+};
+
+struct Boxer {
+    MetaClass *metaclass;
+    Dog superself;
+};
+
+MetaClass *cANIMAL = NULL;
+MetaClass *cDOG    = NULL;
+MetaClass *cBOXER  = NULL;
+
+uint64_t Animal_destroy_OFFSETS;
+uint64_t Dog_destroy_OFFSETS;
+uint64_t Boxer_destroy_OFFSETS;
+
+uint64_t Animal_speak_OFFSETS;
+uint64_t Dog_speak_OFFSETS;
+uint64_t Boxer_speak_OFFSETS;
+
+uint64_t Dog_ignore_name_OFFSETS;
+uint64_t Boxer_ignore_name_OFFSETS;
+
+uint64_t Boxer_drool_OFFSETS;
+
+Animal*
+Animal_init(Animal *self) {
+    return self;
+}
+
+static void
+S_Animal_speak(Animal *self) {
+    (void)self;
+    printf("*noise*\n");
+}
+
+Dog*
+Dog_new(const char *name) {
+    Dog *self = MetaClass_make_obj(cDOG);
+    return Dog_init(self, name);
+}
+
+Dog*
+Dog_init(Dog *self, const char *name) {
+    Animal_init(&self->superself);
+    self->name = strdup(name);
+    return self;
+}
+
+static void
+S_Dog_destroy(Dog *self) {
+    free(self->name);
+    Animal_destroy_t super_destroy =
+        (Animal_destroy_t)MetaClass_method_pointer(cANIMAL, Animal_destroy_OFFSETS);
+    void *view = (char*)&self->superself + (Animal_destroy_OFFSETS >> 32);
+    super_destroy(view);
+}
+
+static void
+S_Dog_speak(Dog *self) {
+    (void)self;
+    printf("Woof!\n");
+}
+
+static void
+S_Dog_ignore_name(Dog *self) {
+    printf("My name isn't \"%s\", it's \"cookie\".\n", self->name);
+}
+
+Boxer*
+Boxer_new(const char *name) {
+    Boxer *self = (Boxer*)MetaClass_make_obj(cBOXER);
+    return Boxer_init(self, name);
+}
+
+Boxer*
+Boxer_init(Boxer *self, const char *name) {
+    Dog_init(&self->superself, name);
+    return self;
+}
+
+static void
+S_Boxer_drool(Dog *self) {
+    (void)self;
+    printf("*slobber*\n");
+}
+
+/**********************************************************************/
+
+void
+Module_bootstrap() {
+    size_t num_methods = MetaClass_get_num_methods(cOBJECT);
+    size_t base_size   = MetaClass_get_obj_alloc_size(cOBJECT) - sizeof(void*);
+
+    // Animal
+    num_methods += 1; // speak
+    cANIMAL = MetaClass_new(cOBJECT, "Animal", sizeof(Animal) + base_size,
+                            num_methods);
+    Animal_destroy_OFFSETS
+        = MetaClass_inherit_method(cANIMAL, Obj_destroy_OFFSETS);
+    Animal_speak_OFFSETS
+        = MetaClass_add_novel_method(cANIMAL, (method_t)S_Animal_speak);
+
+    // Dog
+    num_methods += 1; // ignore_name
+    cDOG = MetaClass_new(cANIMAL, "Dog", sizeof(Dog) + base_size, num_methods);
+    Dog_destroy_OFFSETS
+        = MetaClass_override_method(cDOG, (method_t)S_Dog_destroy, Animal_destroy_OFFSETS);
+    Dog_speak_OFFSETS
+        = MetaClass_override_method(cDOG, (method_t)S_Dog_speak, Animal_speak_OFFSETS);
+    Dog_ignore_name_OFFSETS
+        = MetaClass_add_novel_method(cDOG, (method_t)S_Dog_ignore_name);
+
+    // Boxer
+    num_methods += 1; // drool
+    cBOXER = MetaClass_new(cDOG, "Boxer", sizeof(Boxer) + base_size, num_methods);
+    Boxer_destroy_OFFSETS
+        = MetaClass_inherit_method(cBOXER, Dog_destroy_OFFSETS);
+    Boxer_speak_OFFSETS
+        = MetaClass_inherit_method(cBOXER, Dog_speak_OFFSETS);
+    Boxer_ignore_name_OFFSETS
+        = MetaClass_inherit_method(cBOXER, Dog_ignore_name_OFFSETS);
+    Boxer_drool_OFFSETS
+        = MetaClass_add_novel_method(cBOXER, (method_t)S_Boxer_drool);
+}
+
+void
+Module_tear_down() {
+    MetaClass_destroy(cBOXER);
+    MetaClass_destroy(cDOG);
+    MetaClass_destroy(cANIMAL);
+}

Propchange: lucy/branches/LUCY-234-struct-ABI/module.c
------------------------------------------------------------------------------
    svn:eol-style = native

Added: lucy/branches/LUCY-234-struct-ABI/module.h
URL: http://svn.apache.org/viewvc/lucy/branches/LUCY-234-struct-ABI/module.h?rev=1332895&view=auto
==============================================================================
--- lucy/branches/LUCY-234-struct-ABI/module.h (added)
+++ lucy/branches/LUCY-234-struct-ABI/module.h Wed May  2 01:51:00 2012
@@ -0,0 +1,168 @@
+/* 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.
+ */
+
+#ifndef MODULE_H
+#define MODULE_H
+
+#include "core.h"
+
+typedef struct Animal Animal;
+typedef struct Dog    Dog;
+typedef struct Boxer  Boxer;
+
+extern MetaClass *cANIMAL;
+extern MetaClass *cDOG;
+extern MetaClass *cBOXER;
+
+void
+Module_bootstrap(void);
+
+void
+Module_tear_down(void);
+
+Animal*
+Animal_init(Animal *self);
+
+typedef void 
+(*Animal_destroy_t)(Animal *self);
+extern uint64_t Animal_destroy_OFFSETS;
+static inline void
+Animal_destroy(Animal *self) {
+    const uint64_t offsets = Animal_destroy_OFFSETS;
+    void *const view = (char*)self + (int32_t)(offsets >> 32);
+    char *const method_address = *(char**)self + (uint32_t)offsets;
+    Animal_destroy_t method = *((Animal_destroy_t*)method_address);
+    method(view);
+}
+
+typedef void 
+(*Animal_speak_t)(Animal *self);
+extern uint64_t Animal_speak_OFFSETS;
+static inline void
+Animal_speak(Animal *self) {
+    const uint64_t offsets = Animal_speak_OFFSETS;
+    void *const view = (char*)self + (int32_t)(offsets >> 32);
+    char *const method_address = *(char**)self + (uint32_t)offsets;
+    Animal_speak_t method = *((Animal_speak_t*)method_address);
+    method(view);
+}
+
+Dog*
+Dog_new(const char *name);
+
+Dog*
+Dog_init(Dog *self, const char *name);
+
+typedef void 
+(*Dog_destroy_t)(Dog *self);
+extern uint64_t Dog_destroy_OFFSETS;
+static inline void
+Dog_destroy(Dog *self) {
+    const uint64_t offsets = Dog_destroy_OFFSETS;
+    void *const view = (char*)self + (int32_t)(offsets >> 32);
+    char *const method_address = *(char**)self + (uint32_t)offsets;
+    Dog_destroy_t method = *((Dog_destroy_t*)method_address);
+    method(view);
+}
+
+static inline void
+Dog_destroy_NEXT(Dog *self) {
+    const uint64_t offsets = Dog_destroy_OFFSETS;
+    void *const view = (char*)self + (int32_t)(offsets >> 32);
+    char *const method_address = *(char**)self + (uint32_t)offsets;
+    Dog_destroy_t method = *((Dog_destroy_t*)method_address);
+    method(view);
+}
+
+typedef void 
+(*Dog_speak_t)(Dog *self);
+extern uint64_t Dog_speak_OFFSETS;
+static inline void
+Dog_speak(Dog *self) {
+    const uint64_t offsets = Dog_speak_OFFSETS;
+    void *const view = (char*)self + (int32_t)(offsets >> 32);
+    char *const method_address = *(char**)self + (uint32_t)offsets;
+    Dog_speak_t method = *((Dog_speak_t*)method_address);
+    method(view);
+}
+
+typedef void 
+(*Dog_ignore_name_t)(Dog *self);
+extern uint64_t Dog_ignore_name_OFFSETS;
+static inline void
+Dog_ignore_name(Dog *self) {
+    const uint64_t offsets = Dog_ignore_name_OFFSETS;
+    void *const view = (char*)self + (int32_t)(offsets >> 32);
+    char *const method_address = *(char**)self + (uint32_t)offsets;
+    Dog_ignore_name_t method = *((Dog_ignore_name_t*)method_address);
+    method(view);
+}
+
+Boxer*
+Boxer_new(const char *name);
+
+Boxer*
+Boxer_init(Boxer *self, const char *name);
+
+typedef void 
+(*Boxer_destroy_t)(Boxer *self);
+extern uint64_t Boxer_destroy_OFFSETS;
+static inline void
+Boxer_destroy(Boxer *self) {
+    const uint64_t offsets = Boxer_destroy_OFFSETS;
+    void *const view = (char*)self + (int32_t)(offsets >> 32);
+    char *const method_address = *(char**)self + (uint32_t)offsets;
+    Boxer_destroy_t method = *((Boxer_destroy_t*)method_address);
+    method(view);
+}
+
+typedef void 
+(*Boxer_speak_t)(Boxer *self);
+extern uint64_t Boxer_speak_OFFSETS;
+static inline void
+Boxer_speak(Boxer *self) {
+    const uint64_t offsets = Boxer_speak_OFFSETS;
+    void *const view = (char*)self + (int32_t)(offsets >> 32);
+    char *const method_address = *(char**)self + (uint32_t)offsets;
+    Boxer_speak_t method = *((Boxer_speak_t*)method_address);
+    method(view);
+}
+
+typedef void 
+(*Boxer_ignore_name_t)(Boxer *self);
+extern uint64_t Boxer_ignore_name_OFFSETS;
+static inline void
+Boxer_ignore_name(Boxer *self) {
+    const uint64_t offsets = Boxer_ignore_name_OFFSETS;
+    void *const view = (char*)self + (int32_t)(offsets >> 32);
+    char *const method_address = *(char**)self + (uint32_t)offsets;
+    Boxer_ignore_name_t method = *((Boxer_ignore_name_t*)method_address);
+    method(view);
+}
+
+typedef void 
+(*Boxer_drool_t)(Boxer *self);
+extern uint64_t Boxer_drool_OFFSETS;
+static inline void
+Boxer_drool(Boxer *self) {
+    const uint64_t offsets = Boxer_drool_OFFSETS;
+    void *const view = (char*)self + (int32_t)(offsets >> 32);
+    char *const method_address = *(char**)self + (uint32_t)offsets;
+    Boxer_drool_t method = *((Boxer_drool_t*)method_address);
+    method(view);
+}
+
+#endif /* MODULE_H */

Propchange: lucy/branches/LUCY-234-struct-ABI/module.h
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message