You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucy.apache.org by ma...@apache.org on 2013/07/14 02:14:47 UTC

[lucy-commits] [1/7] git commit: refs/heads/ivars-wip1 - Fixup Lucy Test classes IVARS glitches.

Updated Branches:
  refs/heads/ivars-wip1 1e3d2bcce -> 38ad55831


Fixup Lucy Test classes IVARS glitches.

(Will be folded into earlier commit before merging to master.)


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

Branch: refs/heads/ivars-wip1
Commit: 296609723f680be019858cc0abaade014090363a
Parents: e733e2a
Author: Marvin Humphrey <ma...@rectangular.com>
Authored: Fri Jul 12 19:32:08 2013 -0700
Committer: Marvin Humphrey <ma...@rectangular.com>
Committed: Sat Jul 13 15:17:27 2013 -0700

----------------------------------------------------------------------
 core/Lucy/Test/Search/TestQueryParserLogic.c | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy/blob/29660972/core/Lucy/Test/Search/TestQueryParserLogic.c
----------------------------------------------------------------------
diff --git a/core/Lucy/Test/Search/TestQueryParserLogic.c b/core/Lucy/Test/Search/TestQueryParserLogic.c
index a467c59..5bc51e9 100644
--- a/core/Lucy/Test/Search/TestQueryParserLogic.c
+++ b/core/Lucy/Test/Search/TestQueryParserLogic.c
@@ -899,7 +899,8 @@ TestQPLogic_run(TestQueryParserLogic *self, TestBatchRunner *runner) {
     // Run logical tests with default boolop of OR.
     for (i = 0; logical_test_funcs[i] != NULL; i++) {
         Lucy_TestQPLogic_Logical_Test_t test_func = logical_test_funcs[i];
-        TestQueryParserIVARS *test_case = TestQP_IVARS(test_func(BOOLOP_OR));
+        TestQueryParser *test_case_obj = test_func(BOOLOP_OR);
+        TestQueryParserIVARS *test_case = TestQP_IVARS(test_case_obj);
         Query *tree     = QParser_Tree(or_parser, test_case->query_string);
         Query *parsed   = QParser_Parse(or_parser, test_case->query_string);
         Hits  *hits     = IxSearcher_Hits(searcher, (Obj*)parsed, 0, 10, NULL);
@@ -911,13 +912,14 @@ TestQPLogic_run(TestQueryParserLogic *self, TestBatchRunner *runner) {
         DECREF(hits);
         DECREF(parsed);
         DECREF(tree);
-        DECREF(test_case);
+        DECREF(test_case_obj);
     }
 
     // Run logical tests with default boolop of AND.
     for (i = 0; logical_test_funcs[i] != NULL; i++) {
         Lucy_TestQPLogic_Logical_Test_t test_func = logical_test_funcs[i];
-        TestQueryParserIVARS *test_case = TestQP_IVARS(test_func(BOOLOP_AND));
+        TestQueryParser *test_case_obj = test_func(BOOLOP_AND);
+        TestQueryParserIVARS *test_case = TestQP_IVARS(test_case_obj);
         Query *tree     = QParser_Tree(and_parser, test_case->query_string);
         Query *parsed   = QParser_Parse(and_parser, test_case->query_string);
         Hits  *hits     = IxSearcher_Hits(searcher, (Obj*)parsed, 0, 10, NULL);
@@ -929,13 +931,14 @@ TestQPLogic_run(TestQueryParserLogic *self, TestBatchRunner *runner) {
         DECREF(hits);
         DECREF(parsed);
         DECREF(tree);
-        DECREF(test_case);
+        DECREF(test_case_obj);
     }
 
     // Run tests for QParser_Prune().
     for (i = 0; prune_test_funcs[i] != NULL; i++) {
         Lucy_TestQPLogic_Prune_Test_t test_func = prune_test_funcs[i];
-        TestQueryParserIVARS *test_case = TestQP_IVARS(test_func());
+        TestQueryParser *test_case_obj = test_func();
+        TestQueryParserIVARS *test_case = TestQP_IVARS(test_case_obj);
         CharBuf *qstring = test_case->tree
                            ? Query_To_String(test_case->tree)
                            : CB_new_from_trusted_utf8("(NULL)", 6);
@@ -956,7 +959,7 @@ TestQPLogic_run(TestQueryParserLogic *self, TestBatchRunner *runner) {
         DECREF(expanded);
         DECREF(pruned);
         DECREF(qstring);
-        DECREF(test_case);
+        DECREF(test_case_obj);
     }
 
     DECREF(and_parser);


[lucy-commits] [6/7] git commit: refs/heads/ivars-wip1 - Access IVARS struct using global offset.

Posted by ma...@apache.org.
Access IVARS struct using global offset.

Instead of performing a simple cast to convert the object struct pointer
to an IVARS struct pointer, add a global offset variable.  For now, the
offset is always 0.


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

Branch: refs/heads/ivars-wip1
Commit: 06d86f18167751ea3bb72749d40d768bb19baa4d
Parents: 353b579
Author: Marvin Humphrey <ma...@rectangular.com>
Authored: Thu Jul 11 17:29:50 2013 -0700
Committer: Marvin Humphrey <ma...@rectangular.com>
Committed: Sat Jul 13 16:59:00 2013 -0700

----------------------------------------------------------------------
 clownfish/compiler/src/CFCBindClass.c | 53 ++++++++++++++++++++----------
 1 file changed, 35 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy/blob/06d86f18/clownfish/compiler/src/CFCBindClass.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCBindClass.c b/clownfish/compiler/src/CFCBindClass.c
index e63b9d4..a431d26 100644
--- a/clownfish/compiler/src/CFCBindClass.c
+++ b/clownfish/compiler/src/CFCBindClass.c
@@ -152,28 +152,37 @@ S_to_c_header_inert(CFCBindClass *self) {
 }
 
 static char*
-S_ivars_hack(CFCBindClass *self) {
-    const char *full_struct = CFCClass_full_struct_sym(self->client);
-    const char *full_ivars  = CFCClass_full_ivars_struct(self->client);
-    const char *short_ivars = CFCClass_short_ivars_struct(self->client);
-    const char *prefix      = CFCClass_get_prefix(self->client);
-    const char *PREFIX      = CFCClass_get_PREFIX(self->client);
-    const char *class_cnick = CFCClass_get_cnick(self->client);
+S_ivars_func(CFCBindClass *self) {
+    CFCClass *client = self->client;
+    const char *full_type    = CFCClass_full_struct_sym(client);
+    const char *full_func    = CFCClass_full_ivars_func(client);
+    const char *short_func   = CFCClass_short_ivars_func(client);
+    const char *full_struct  = CFCClass_full_ivars_struct(client);
+    const char *short_struct = CFCClass_short_ivars_struct(client);
+    const char *full_offset  = CFCClass_full_ivars_offset(client);
+    const char *PREFIX       = CFCClass_get_PREFIX(client);
     char pattern[] =
+        "extern size_t %s;\n"
         "typedef struct %s %s;\n"
         "static CHY_INLINE %s*\n"
-        "%s%s_IVARS(%s *self) {\n"
-        "   return (%s*)self;\n"
+        "%s(%s *self) {\n"
+        "   char *ptr = (char*)self + %s;\n"
+        "   return (%s*)ptr;\n"
         "}\n"
         "#ifdef %sUSE_SHORT_NAMES\n"
         "  #define %s %s\n"
-        "  #define %s_IVARS %s%s_IVARS\n"
+        "  #define %s %s\n"
         "#endif\n";
-    char *content
-        = CFCUtil_sprintf(pattern, full_ivars, full_ivars, full_ivars, prefix,
-                          class_cnick, full_struct, full_ivars, PREFIX,
-                          short_ivars, full_ivars, class_cnick, prefix,
-                          class_cnick);
+    char *content = CFCUtil_sprintf(pattern,
+                                    full_offset,
+                                    full_struct, full_struct,
+                                    full_struct,
+                                    full_func, full_type,
+                                    full_offset,
+                                    full_struct,
+                                    PREFIX,
+                                    short_struct, full_struct,
+                                    short_func, full_func);
     return content;
 }
 
@@ -183,7 +192,7 @@ S_to_c_header_dynamic(CFCBindClass *self) {
     const char *vt_var          = CFCClass_full_vtable_var(self->client);
     const char *prefix          = CFCClass_get_prefix(self->client);
     const char *PREFIX          = CFCClass_get_PREFIX(self->client);
-    char *ivars                 = S_ivars_hack(self);
+    char *ivars                 = S_ivars_func(self);
     char *struct_def            = S_struct_definition(self);
     char *parent_include        = S_parent_include(self);
     char *sub_declarations      = S_sub_declarations(self);
@@ -265,6 +274,8 @@ CFCBindClass_to_c_data(CFCBindClass *self) {
         return CFCUtil_strdup(CFCClass_get_autocode(client));
     }
 
+    const char *ivars_offset = CFCClass_full_ivars_offset(client);
+
     const char *autocode  = CFCClass_get_autocode(client);
     const char *vt_var    = CFCClass_full_vtable_var(client);
 
@@ -321,6 +332,12 @@ CFCBindClass_to_c_data(CFCBindClass *self) {
     }
 
     const char pattern[] =
+        "/* Offset from the top of the object at which the IVARS struct\n"
+        " * can be found.\n"
+        " */\n"
+        "\n"
+        "size_t %s;\n"
+        "\n"
         "/* Offsets for method pointers, measured in bytes, from the top\n"
         " * of this class's vtable.\n"
         " */\n"
@@ -348,8 +365,8 @@ CFCBindClass_to_c_data(CFCBindClass *self) {
         "\n"
         "%s\n"
         "\n";
-    char *code = CFCUtil_sprintf(pattern, offsets, method_defs, ms_var, vt_var,
-                                 autocode);
+    char *code = CFCUtil_sprintf(pattern, ivars_offset, offsets, method_defs,
+                                 ms_var, vt_var, autocode);
 
     FREEMEM(fresh_methods);
     FREEMEM(offsets);


[lucy-commits] [4/7] git commit: refs/heads/ivars-wip1 - Fixup Lucy Store classes IVARS glitches.

Posted by ma...@apache.org.
Fixup Lucy Store classes IVARS glitches.

(Will be folded into earlier commit before merging to master.)


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

Branch: refs/heads/ivars-wip1
Commit: 98dbab2a0fcd66273c3e38097651ccb71c5bf999
Parents: 2966097
Author: Marvin Humphrey <ma...@rectangular.com>
Authored: Fri Jul 12 19:34:11 2013 -0700
Committer: Marvin Humphrey <ma...@rectangular.com>
Committed: Sat Jul 13 15:17:28 2013 -0700

----------------------------------------------------------------------
 core/Lucy/Store/InStream.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy/blob/98dbab2a/core/Lucy/Store/InStream.c
----------------------------------------------------------------------
diff --git a/core/Lucy/Store/InStream.c b/core/Lucy/Store/InStream.c
index 467bb64..caf286e 100644
--- a/core/Lucy/Store/InStream.c
+++ b/core/Lucy/Store/InStream.c
@@ -133,7 +133,8 @@ InStream_reopen(InStream *self, const CharBuf *filename, int64_t offset,
               offset, len, FH_Length(ivars->file_handle));
     }
 
-    InStream *other = (InStream*)VTable_Make_Obj(ivars->vtable);
+    VTable *vtable = InStream_Get_VTable(self);
+    InStream *other = (InStream*)VTable_Make_Obj(vtable);
     InStreamIVARS *const ovars = InStream_IVARS(other);
     InStream_do_open(other, (Obj*)ivars->file_handle);
     if (filename != NULL) { CB_Mimic(ovars->filename, (Obj*)filename); }
@@ -147,7 +148,8 @@ InStream_reopen(InStream *self, const CharBuf *filename, int64_t offset,
 InStream*
 InStream_clone(InStream *self) {
     InStreamIVARS *const ivars = InStream_IVARS(self);
-    InStream *twin = (InStream*)VTable_Make_Obj(ivars->vtable);
+    VTable *vtable = InStream_Get_VTable(self);
+    InStream *twin = (InStream*)VTable_Make_Obj(vtable);
     InStream_do_open(twin, (Obj*)ivars->file_handle);
     InStream_Seek(twin, SI_tell(self));
     return twin;


[lucy-commits] [5/7] git commit: refs/heads/ivars-wip1 - Cache some IVARS symbols within CFCClass.

Posted by ma...@apache.org.
Cache some IVARS symbols within CFCClass.


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

Branch: refs/heads/ivars-wip1
Commit: 353b579fea50152adb93fda2fdc01eb532cf5426
Parents: 98dbab2
Author: Marvin Humphrey <ma...@rectangular.com>
Authored: Sat Jul 13 16:16:48 2013 -0700
Committer: Marvin Humphrey <ma...@rectangular.com>
Committed: Sat Jul 13 16:48:49 2013 -0700

----------------------------------------------------------------------
 clownfish/compiler/src/CFCBindClass.c |  6 ++--
 clownfish/compiler/src/CFCClass.c     | 47 +++++++++++++++++++++++-------
 clownfish/compiler/src/CFCClass.h     | 25 ++++++++++++++--
 3 files changed, 62 insertions(+), 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy/blob/353b579f/clownfish/compiler/src/CFCBindClass.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCBindClass.c b/clownfish/compiler/src/CFCBindClass.c
index 452b58f..e63b9d4 100644
--- a/clownfish/compiler/src/CFCBindClass.c
+++ b/clownfish/compiler/src/CFCBindClass.c
@@ -154,8 +154,8 @@ S_to_c_header_inert(CFCBindClass *self) {
 static char*
 S_ivars_hack(CFCBindClass *self) {
     const char *full_struct = CFCClass_full_struct_sym(self->client);
-    const char *full_ivars  = CFCClass_full_ivars_name(self->client);
-    const char *short_ivars = CFCClass_short_ivars_name(self->client);
+    const char *full_ivars  = CFCClass_full_ivars_struct(self->client);
+    const char *short_ivars = CFCClass_short_ivars_struct(self->client);
     const char *prefix      = CFCClass_get_prefix(self->client);
     const char *PREFIX      = CFCClass_get_PREFIX(self->client);
     const char *class_cnick = CFCClass_get_cnick(self->client);
@@ -367,7 +367,7 @@ S_struct_definition(CFCBindClass *self) {
         struct_sym = CFCClass_full_struct_sym(self->client);
     }
     else {
-        struct_sym = CFCClass_full_ivars_name(self->client);
+        struct_sym = CFCClass_full_ivars_struct(self->client);
     }
 
     CFCVariable **member_vars = CFCClass_member_vars(self->client);

http://git-wip-us.apache.org/repos/asf/lucy/blob/353b579f/clownfish/compiler/src/CFCClass.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCClass.c b/clownfish/compiler/src/CFCClass.c
index 7426ab3..a2eba89 100644
--- a/clownfish/compiler/src/CFCClass.c
+++ b/clownfish/compiler/src/CFCClass.c
@@ -77,8 +77,11 @@ struct CFCClass {
     int is_inert;
     char *struct_sym;
     char *full_struct_sym;
-    char *ivars_name;
-    char *full_ivars_name;
+    char *ivars_struct;
+    char *full_ivars_struct;
+    char *ivars_func;
+    char *full_ivars_func;
+    char *full_ivars_offset;
     char *short_vtable_var;
     char *full_vtable_var;
     char *privacy_symbol;
@@ -169,9 +172,13 @@ CFCClass_do_create(CFCClass *self, struct CFCParcel *parcel,
         self->short_vtable_var[i] = toupper(self->struct_sym[i]);
     }
     self->short_vtable_var[struct_sym_len] = '\0';
-    self->full_struct_sym = CFCUtil_sprintf("%s%s", prefix, self->struct_sym);
-    self->ivars_name      = CFCUtil_sprintf("%sIVARS", self->struct_sym);
-    self->full_ivars_name = CFCUtil_sprintf("%sIVARS", self->full_struct_sym);
+    self->full_struct_sym   = CFCUtil_sprintf("%s%s", prefix, self->struct_sym);
+    self->ivars_struct      = CFCUtil_sprintf("%sIVARS", self->struct_sym);
+    self->full_ivars_struct = CFCUtil_sprintf("%sIVARS", self->full_struct_sym);
+    self->ivars_func        = CFCUtil_sprintf("%s_IVARS", CFCClass_get_cnick(self));
+    self->full_ivars_func   = CFCUtil_sprintf("%s%s_IVARS", prefix,
+                                              CFCClass_get_cnick(self));
+    self->full_ivars_offset = CFCUtil_sprintf("%s_OFFSET", self->full_ivars_func);
     size_t full_struct_sym_len = strlen(self->full_struct_sym);
     self->full_vtable_var = (char*)MALLOCATE(full_struct_sym_len + 1);
     for (i = 0; self->full_struct_sym[i] != '\0'; i++) {
@@ -235,8 +242,11 @@ CFCClass_destroy(CFCClass *self) {
     FREEMEM(self->autocode);
     FREEMEM(self->parent_class_name);
     FREEMEM(self->struct_sym);
-    FREEMEM(self->ivars_name);
-    FREEMEM(self->full_ivars_name);
+    FREEMEM(self->ivars_struct);
+    FREEMEM(self->full_ivars_struct);
+    FREEMEM(self->ivars_func);
+    FREEMEM(self->full_ivars_func);
+    FREEMEM(self->full_ivars_offset);
     FREEMEM(self->short_vtable_var);
     FREEMEM(self->full_struct_sym);
     FREEMEM(self->full_vtable_var);
@@ -786,13 +796,28 @@ CFCClass_full_struct_sym(CFCClass *self) {
 }
 
 const char*
-CFCClass_short_ivars_name(CFCClass *self) {
-    return self->ivars_name;
+CFCClass_short_ivars_struct(CFCClass *self) {
+    return self->ivars_struct;
 }
 
 const char*
-CFCClass_full_ivars_name(CFCClass *self) {
-    return self->full_ivars_name;
+CFCClass_full_ivars_struct(CFCClass *self) {
+    return self->full_ivars_struct;
+}
+
+const char*
+CFCClass_short_ivars_func(CFCClass *self) {
+    return self->ivars_func;
+}
+
+const char*
+CFCClass_full_ivars_func(CFCClass *self) {
+    return self->full_ivars_func;
+}
+
+const char*
+CFCClass_full_ivars_offset(CFCClass *self) {
+    return self->full_ivars_offset;
 }
 
 const char*

http://git-wip-us.apache.org/repos/asf/lucy/blob/353b579f/clownfish/compiler/src/CFCClass.h
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCClass.h b/clownfish/compiler/src/CFCClass.h
index d45e883..3d4d680 100644
--- a/clownfish/compiler/src/CFCClass.h
+++ b/clownfish/compiler/src/CFCClass.h
@@ -246,11 +246,32 @@ CFCClass_get_struct_sym(CFCClass *self);
 const char*
 CFCClass_full_struct_sym(CFCClass *self);
 
+/** IVARS struct name, not including parcel prefix.
+ */
+const char*
+CFCClass_short_ivars_struct(CFCClass *self);
+
+/** Fully qualified IVARS struct name including parcel prefix.
+ */
 const char*
-CFCClass_short_ivars_name(CFCClass *self);
+CFCClass_full_ivars_struct(CFCClass *self);
 
+/** Name of the function used to access IVARS, not including parcel prefix.
+ */
+const char*
+CFCClass_short_ivars_func(CFCClass *self);
+
+/** Fully qualified name of the function used to access IVARS including parcel
+ * prefix.
+ */
+const char*
+CFCClass_full_ivars_func(CFCClass *self);
+
+/** Fully qualified name of the offset variable at which the IVARS may be
+ * found, including parcel prefix.
+ */
 const char*
-CFCClass_full_ivars_name(CFCClass *self);
+CFCClass_full_ivars_offset(CFCClass *self);
 
 /** The short name of the global VTable object for this class.
  */


[lucy-commits] [3/7] git commit: refs/heads/ivars-wip1 - Move BBSortEx out of TestLucy back under Lucy.

Posted by ma...@apache.org.
Move BBSortEx out of TestLucy back under Lucy.

BBSortEx is a test-only class, but it uses member vars defined in
SortEx.  That's a problem once we cut off access to member vars defined
in another parcel, so move it back under Lucy for the time being.


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

Branch: refs/heads/ivars-wip1
Commit: ee006ebb73e02e72443350fdabc617cd38ee7aaf
Parents: 1e3d2bc
Author: Marvin Humphrey <ma...@rectangular.com>
Authored: Fri Jul 12 19:14:18 2013 -0700
Committer: Marvin Humphrey <ma...@rectangular.com>
Committed: Sat Jul 13 15:17:27 2013 -0700

----------------------------------------------------------------------
 core/Lucy/Test/Util/BBSortEx.c           | 176 --------------------------
 core/Lucy/Test/Util/BBSortEx.cfh         |  58 ---------
 core/Lucy/Util/BBSortEx.c                | 176 ++++++++++++++++++++++++++
 core/Lucy/Util/BBSortEx.cfh              |  58 +++++++++
 perl/buildlib/Lucy/Build/Binding/Misc.pm |  60 ---------
 perl/buildlib/Lucy/Build/Binding/Util.pm |  60 +++++++++
 perl/lib/Lucy/Test/Util/BBSortEx.pm      |  25 ----
 perl/lib/Lucy/Util/BBSortEx.pm           |  25 ++++
 perl/t/015-sort_external.t               |  22 ++--
 perl/t/028-sortexrun.t                   |   2 +-
 10 files changed, 331 insertions(+), 331 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy/blob/ee006ebb/core/Lucy/Test/Util/BBSortEx.c
----------------------------------------------------------------------
diff --git a/core/Lucy/Test/Util/BBSortEx.c b/core/Lucy/Test/Util/BBSortEx.c
deleted file mode 100644
index 0e17b42..0000000
--- a/core/Lucy/Test/Util/BBSortEx.c
+++ /dev/null
@@ -1,176 +0,0 @@
-/* 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.
- */
-
-#define C_TESTLUCY_BBSORTEX
-#define TESTLUCY_USE_SHORT_NAMES
-#include "Lucy/Util/ToolSet.h"
-
-#include "Lucy/Test/Util/BBSortEx.h"
-
-#include "Lucy/Index/Segment.h"
-#include "Lucy/Store/InStream.h"
-#include "Lucy/Store/Folder.h"
-#include "Lucy/Store/OutStream.h"
-
-BBSortEx*
-BBSortEx_new(uint32_t mem_threshold, VArray *external) {
-    BBSortEx *self = (BBSortEx*)VTable_Make_Obj(BBSORTEX);
-    return BBSortEx_init(self, mem_threshold, external);
-}
-
-BBSortEx*
-BBSortEx_init(BBSortEx *self, uint32_t mem_threshold, VArray *external) {
-    SortEx_init((SortExternal*)self, sizeof(Obj*));
-    BBSortExIVARS *const ivars = BBSortEx_IVARS(self);
-    ivars->external_tick = 0;
-    ivars->external = (VArray*)INCREF(external);
-    ivars->mem_consumed = 0;
-    BBSortEx_Set_Mem_Thresh(self, mem_threshold);
-    return self;
-}
-
-void
-BBSortEx_destroy(BBSortEx *self) {
-    BBSortExIVARS *const ivars = BBSortEx_IVARS(self);
-    DECREF(ivars->external);
-    SUPER_DESTROY(self, BBSORTEX);
-}
-
-void
-BBSortEx_clear_cache(BBSortEx *self) {
-    BBSortExIVARS *const ivars = BBSortEx_IVARS(self);
-    Obj **const cache = (Obj**)ivars->cache;
-    for (uint32_t i = ivars->cache_tick, max = ivars->cache_max; i < max; i++) {
-        DECREF(cache[i]);
-    }
-    ivars->mem_consumed = 0;
-    BBSortEx_Clear_Cache_t super_clear_cache
-        = SUPER_METHOD_PTR(BBSORTEX, TestLucy_BBSortEx_Clear_Cache);
-    super_clear_cache(self);
-}
-
-void
-BBSortEx_feed(BBSortEx *self, void *data) {
-    BBSortExIVARS *const ivars = BBSortEx_IVARS(self);
-    BBSortEx_Feed_t super_feed
-        = SUPER_METHOD_PTR(BBSORTEX, TestLucy_BBSortEx_Feed);
-    super_feed(self, data);
-
-    // Flush() if necessary.
-    ByteBuf *bytebuf = (ByteBuf*)CERTIFY(*(ByteBuf**)data, BYTEBUF);
-    ivars->mem_consumed += BB_Get_Size(bytebuf);
-    if (ivars->mem_consumed >= ivars->mem_thresh) {
-        BBSortEx_Flush(self);
-    }
-}
-
-void
-BBSortEx_flush(BBSortEx *self) {
-    BBSortExIVARS *const ivars = BBSortEx_IVARS(self);
-    uint32_t     cache_count = ivars->cache_max - ivars->cache_tick;
-    Obj        **cache = (Obj**)ivars->cache;
-    VArray      *elems;
-
-    if (!cache_count) { return; }
-    else              { elems = VA_new(cache_count); }
-
-    // Sort, then create a new run.
-    BBSortEx_Sort_Cache(self);
-    for (uint32_t i = ivars->cache_tick; i < ivars->cache_max; i++) {
-        VA_Push(elems, cache[i]);
-    }
-    BBSortEx *run = BBSortEx_new(0, elems);
-    DECREF(elems);
-    BBSortEx_Add_Run(self, (SortExternal*)run);
-
-    // Blank the cache vars.
-    ivars->cache_tick += cache_count;
-    BBSortEx_Clear_Cache(self);
-}
-
-uint32_t
-BBSortEx_refill(BBSortEx *self) {
-    BBSortExIVARS *const ivars = BBSortEx_IVARS(self);
-
-    // Make sure cache is empty, then set cache tick vars.
-    if (ivars->cache_max - ivars->cache_tick > 0) {
-        THROW(ERR, "Refill called but cache contains %u32 items",
-              ivars->cache_max - ivars->cache_tick);
-    }
-    ivars->cache_tick = 0;
-    ivars->cache_max  = 0;
-
-    // Read in elements.
-    while (1) {
-        ByteBuf *elem = NULL;
-
-        if (ivars->mem_consumed >= ivars->mem_thresh) {
-            ivars->mem_consumed = 0;
-            break;
-        }
-        else if (ivars->external_tick >= VA_Get_Size(ivars->external)) {
-            break;
-        }
-        else {
-            elem = (ByteBuf*)VA_Fetch(ivars->external, ivars->external_tick);
-            ivars->external_tick++;
-            // Should be + sizeof(ByteBuf), but that's ok.
-            ivars->mem_consumed += BB_Get_Size(elem);
-        }
-
-        if (ivars->cache_max == ivars->cache_cap) {
-            BBSortEx_Grow_Cache(self,
-                                Memory_oversize(ivars->cache_max + 1, ivars->width));
-        }
-        Obj **cache = (Obj**)ivars->cache;
-        cache[ivars->cache_max++] = INCREF(elem);
-    }
-
-    return ivars->cache_max;
-}
-
-void
-BBSortEx_flip(BBSortEx *self) {
-    BBSortExIVARS *const ivars = BBSortEx_IVARS(self);
-    uint32_t run_mem_thresh = 65536;
-
-    BBSortEx_Flush(self);
-
-    // Recalculate the approximate mem allowed for each run.
-    uint32_t num_runs = VA_Get_Size(ivars->runs);
-    if (num_runs) {
-        run_mem_thresh = (ivars->mem_thresh / 2) / num_runs;
-        if (run_mem_thresh < 65536) {
-            run_mem_thresh = 65536;
-        }
-    }
-
-    for (uint32_t i = 0; i < num_runs; i++) {
-        BBSortEx *run = (BBSortEx*)VA_Fetch(ivars->runs, i);
-        BBSortEx_Set_Mem_Thresh(run, run_mem_thresh);
-    }
-
-    // OK to fetch now.
-    ivars->flipped = true;
-}
-
-int
-BBSortEx_compare(BBSortEx *self, void *va, void *vb) {
-    UNUSED_VAR(self);
-    return BB_compare((ByteBuf**)va, (ByteBuf**)vb);
-}
-
-

http://git-wip-us.apache.org/repos/asf/lucy/blob/ee006ebb/core/Lucy/Test/Util/BBSortEx.cfh
----------------------------------------------------------------------
diff --git a/core/Lucy/Test/Util/BBSortEx.cfh b/core/Lucy/Test/Util/BBSortEx.cfh
deleted file mode 100644
index 1978085..0000000
--- a/core/Lucy/Test/Util/BBSortEx.cfh
+++ /dev/null
@@ -1,58 +0,0 @@
-/* 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.
- */
-
-parcel TestLucy;
-
-/** SortExternal for ByteBufs.
- */
-
-class Lucy::Test::Util::BBSortEx
-    inherits Lucy::Util::SortExternal {
-
-    VArray   *external;
-    uint32_t  external_tick;
-    uint32_t  mem_consumed;
-
-    inert BBSortEx*
-    new(uint32_t mem_thresh = 0x1000000, VArray *external = NULL);
-
-    inert BBSortEx*
-    init(BBSortEx *self, uint32_t mem_thresh = 0x1000000,
-        VArray *external = NULL);
-
-    void
-    Feed(BBSortEx *self, void *data);
-
-    void
-    Flush(BBSortEx *self);
-
-    uint32_t
-    Refill(BBSortEx *self);
-
-    void
-    Clear_Cache(BBSortEx *self);
-
-    void
-    Flip(BBSortEx *self);
-
-    int
-    Compare(BBSortEx *self, void *va, void *vb);
-
-    public void
-    Destroy(BBSortEx *self);
-}
-
-

http://git-wip-us.apache.org/repos/asf/lucy/blob/ee006ebb/core/Lucy/Util/BBSortEx.c
----------------------------------------------------------------------
diff --git a/core/Lucy/Util/BBSortEx.c b/core/Lucy/Util/BBSortEx.c
new file mode 100644
index 0000000..d42ca55
--- /dev/null
+++ b/core/Lucy/Util/BBSortEx.c
@@ -0,0 +1,176 @@
+/* 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.
+ */
+
+#define C_LUCY_BBSORTEX
+#define LUCY_USE_SHORT_NAMES
+#include "Lucy/Util/ToolSet.h"
+
+#include "Lucy/Util/BBSortEx.h"
+
+#include "Lucy/Index/Segment.h"
+#include "Lucy/Store/InStream.h"
+#include "Lucy/Store/Folder.h"
+#include "Lucy/Store/OutStream.h"
+
+BBSortEx*
+BBSortEx_new(uint32_t mem_threshold, VArray *external) {
+    BBSortEx *self = (BBSortEx*)VTable_Make_Obj(BBSORTEX);
+    return BBSortEx_init(self, mem_threshold, external);
+}
+
+BBSortEx*
+BBSortEx_init(BBSortEx *self, uint32_t mem_threshold, VArray *external) {
+    SortEx_init((SortExternal*)self, sizeof(Obj*));
+    BBSortExIVARS *const ivars = BBSortEx_IVARS(self);
+    ivars->external_tick = 0;
+    ivars->external = (VArray*)INCREF(external);
+    ivars->mem_consumed = 0;
+    BBSortEx_Set_Mem_Thresh(self, mem_threshold);
+    return self;
+}
+
+void
+BBSortEx_destroy(BBSortEx *self) {
+    BBSortExIVARS *const ivars = BBSortEx_IVARS(self);
+    DECREF(ivars->external);
+    SUPER_DESTROY(self, BBSORTEX);
+}
+
+void
+BBSortEx_clear_cache(BBSortEx *self) {
+    BBSortExIVARS *const ivars = BBSortEx_IVARS(self);
+    Obj **const cache = (Obj**)ivars->cache;
+    for (uint32_t i = ivars->cache_tick, max = ivars->cache_max; i < max; i++) {
+        DECREF(cache[i]);
+    }
+    ivars->mem_consumed = 0;
+    BBSortEx_Clear_Cache_t super_clear_cache
+        = SUPER_METHOD_PTR(BBSORTEX, Lucy_BBSortEx_Clear_Cache);
+    super_clear_cache(self);
+}
+
+void
+BBSortEx_feed(BBSortEx *self, void *data) {
+    BBSortExIVARS *const ivars = BBSortEx_IVARS(self);
+    BBSortEx_Feed_t super_feed
+        = SUPER_METHOD_PTR(BBSORTEX, Lucy_BBSortEx_Feed);
+    super_feed(self, data);
+
+    // Flush() if necessary.
+    ByteBuf *bytebuf = (ByteBuf*)CERTIFY(*(ByteBuf**)data, BYTEBUF);
+    ivars->mem_consumed += BB_Get_Size(bytebuf);
+    if (ivars->mem_consumed >= ivars->mem_thresh) {
+        BBSortEx_Flush(self);
+    }
+}
+
+void
+BBSortEx_flush(BBSortEx *self) {
+    BBSortExIVARS *const ivars = BBSortEx_IVARS(self);
+    uint32_t     cache_count = ivars->cache_max - ivars->cache_tick;
+    Obj        **cache = (Obj**)ivars->cache;
+    VArray      *elems;
+
+    if (!cache_count) { return; }
+    else              { elems = VA_new(cache_count); }
+
+    // Sort, then create a new run.
+    BBSortEx_Sort_Cache(self);
+    for (uint32_t i = ivars->cache_tick; i < ivars->cache_max; i++) {
+        VA_Push(elems, cache[i]);
+    }
+    BBSortEx *run = BBSortEx_new(0, elems);
+    DECREF(elems);
+    BBSortEx_Add_Run(self, (SortExternal*)run);
+
+    // Blank the cache vars.
+    ivars->cache_tick += cache_count;
+    BBSortEx_Clear_Cache(self);
+}
+
+uint32_t
+BBSortEx_refill(BBSortEx *self) {
+    BBSortExIVARS *const ivars = BBSortEx_IVARS(self);
+
+    // Make sure cache is empty, then set cache tick vars.
+    if (ivars->cache_max - ivars->cache_tick > 0) {
+        THROW(ERR, "Refill called but cache contains %u32 items",
+              ivars->cache_max - ivars->cache_tick);
+    }
+    ivars->cache_tick = 0;
+    ivars->cache_max  = 0;
+
+    // Read in elements.
+    while (1) {
+        ByteBuf *elem = NULL;
+
+        if (ivars->mem_consumed >= ivars->mem_thresh) {
+            ivars->mem_consumed = 0;
+            break;
+        }
+        else if (ivars->external_tick >= VA_Get_Size(ivars->external)) {
+            break;
+        }
+        else {
+            elem = (ByteBuf*)VA_Fetch(ivars->external, ivars->external_tick);
+            ivars->external_tick++;
+            // Should be + sizeof(ByteBuf), but that's ok.
+            ivars->mem_consumed += BB_Get_Size(elem);
+        }
+
+        if (ivars->cache_max == ivars->cache_cap) {
+            BBSortEx_Grow_Cache(self,
+                                Memory_oversize(ivars->cache_max + 1, ivars->width));
+        }
+        Obj **cache = (Obj**)ivars->cache;
+        cache[ivars->cache_max++] = INCREF(elem);
+    }
+
+    return ivars->cache_max;
+}
+
+void
+BBSortEx_flip(BBSortEx *self) {
+    BBSortExIVARS *const ivars = BBSortEx_IVARS(self);
+    uint32_t run_mem_thresh = 65536;
+
+    BBSortEx_Flush(self);
+
+    // Recalculate the approximate mem allowed for each run.
+    uint32_t num_runs = VA_Get_Size(ivars->runs);
+    if (num_runs) {
+        run_mem_thresh = (ivars->mem_thresh / 2) / num_runs;
+        if (run_mem_thresh < 65536) {
+            run_mem_thresh = 65536;
+        }
+    }
+
+    for (uint32_t i = 0; i < num_runs; i++) {
+        BBSortEx *run = (BBSortEx*)VA_Fetch(ivars->runs, i);
+        BBSortEx_Set_Mem_Thresh(run, run_mem_thresh);
+    }
+
+    // OK to fetch now.
+    ivars->flipped = true;
+}
+
+int
+BBSortEx_compare(BBSortEx *self, void *va, void *vb) {
+    UNUSED_VAR(self);
+    return BB_compare((ByteBuf**)va, (ByteBuf**)vb);
+}
+
+

http://git-wip-us.apache.org/repos/asf/lucy/blob/ee006ebb/core/Lucy/Util/BBSortEx.cfh
----------------------------------------------------------------------
diff --git a/core/Lucy/Util/BBSortEx.cfh b/core/Lucy/Util/BBSortEx.cfh
new file mode 100644
index 0000000..41f72ea
--- /dev/null
+++ b/core/Lucy/Util/BBSortEx.cfh
@@ -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.
+ */
+
+parcel Lucy;
+
+/** SortExternal for ByteBufs.
+ */
+
+class Lucy::Util::BBSortEx
+    inherits Lucy::Util::SortExternal {
+
+    VArray   *external;
+    uint32_t  external_tick;
+    uint32_t  mem_consumed;
+
+    inert BBSortEx*
+    new(uint32_t mem_thresh = 0x1000000, VArray *external = NULL);
+
+    inert BBSortEx*
+    init(BBSortEx *self, uint32_t mem_thresh = 0x1000000,
+        VArray *external = NULL);
+
+    void
+    Feed(BBSortEx *self, void *data);
+
+    void
+    Flush(BBSortEx *self);
+
+    uint32_t
+    Refill(BBSortEx *self);
+
+    void
+    Clear_Cache(BBSortEx *self);
+
+    void
+    Flip(BBSortEx *self);
+
+    int
+    Compare(BBSortEx *self, void *va, void *vb);
+
+    public void
+    Destroy(BBSortEx *self);
+}
+
+

http://git-wip-us.apache.org/repos/asf/lucy/blob/ee006ebb/perl/buildlib/Lucy/Build/Binding/Misc.pm
----------------------------------------------------------------------
diff --git a/perl/buildlib/Lucy/Build/Binding/Misc.pm b/perl/buildlib/Lucy/Build/Binding/Misc.pm
index 3a779c0..19036d9 100644
--- a/perl/buildlib/Lucy/Build/Binding/Misc.pm
+++ b/perl/buildlib/Lucy/Build/Binding/Misc.pm
@@ -25,7 +25,6 @@ sub bind_all {
     $class->bind_lucy;
     $class->bind_test;
     $class->bind_testschema;
-    $class->bind_bbsortex;
 }
 
 sub inherit_metadata {
@@ -216,64 +215,5 @@ sub bind_testschema {
     Clownfish::CFC::Binding::Perl::Class->register($binding);
 }
 
-sub bind_bbsortex {
-    my @hand_rolled = qw(
-        Fetch
-        Peek
-        Feed
-    );
-    my $xs_code = <<'END_XS_CODE';
-MODULE = Lucy    PACKAGE = Lucy::Test::Util::BBSortEx
-
-SV*
-fetch(self)
-    testlucy_BBSortEx *self;
-CODE:
-{
-    void *address = TestLucy_BBSortEx_Fetch(self);
-    if (address) {
-        RETVAL = XSBind_cfish_to_perl(*(cfish_Obj**)address);
-        CFISH_DECREF(*(cfish_Obj**)address);
-    }
-    else {
-        RETVAL = newSV(0);
-    }
-}
-OUTPUT: RETVAL
-
-SV*
-peek(self)
-    testlucy_BBSortEx *self;
-CODE:
-{
-    void *address = TestLucy_BBSortEx_Peek(self);
-    if (address) {
-        RETVAL = XSBind_cfish_to_perl(*(cfish_Obj**)address);
-    }
-    else {
-        RETVAL = newSV(0);
-    }
-}
-OUTPUT: RETVAL
-
-void
-feed(self, bb)
-    testlucy_BBSortEx *self;
-    cfish_ByteBuf *bb;
-CODE:
-    CFISH_INCREF(bb);
-    TestLucy_BBSortEx_Feed(self, &bb);
-
-END_XS_CODE
-
-    my $binding = Clownfish::CFC::Binding::Perl::Class->new(
-        parcel     => "TestLucy",
-        class_name => "Lucy::Test::Util::BBSortEx",
-    );
-    $binding->append_xs($xs_code);
-
-    Clownfish::CFC::Binding::Perl::Class->register($binding);
-}
-
 1;
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/ee006ebb/perl/buildlib/Lucy/Build/Binding/Util.pm
----------------------------------------------------------------------
diff --git a/perl/buildlib/Lucy/Build/Binding/Util.pm b/perl/buildlib/Lucy/Build/Binding/Util.pm
index df3ee31..a64c58b 100644
--- a/perl/buildlib/Lucy/Build/Binding/Util.pm
+++ b/perl/buildlib/Lucy/Build/Binding/Util.pm
@@ -21,6 +21,7 @@ $VERSION = eval $VERSION;
 
 sub bind_all {
     my $class = shift;
+    $class->bind_bbsortex;
     $class->bind_debug;
     $class->bind_freezer;
     $class->bind_indexfilenames;
@@ -30,6 +31,65 @@ sub bind_all {
     $class->bind_stepper;
 }
 
+sub bind_bbsortex {
+    my @hand_rolled = qw(
+        Fetch
+        Peek
+        Feed
+    );
+    my $xs_code = <<'END_XS_CODE';
+MODULE = Lucy    PACKAGE = Lucy::Util::BBSortEx
+
+SV*
+fetch(self)
+    lucy_BBSortEx *self;
+CODE:
+{
+    void *address = Lucy_BBSortEx_Fetch(self);
+    if (address) {
+        RETVAL = XSBind_cfish_to_perl(*(cfish_Obj**)address);
+        CFISH_DECREF(*(cfish_Obj**)address);
+    }
+    else {
+        RETVAL = newSV(0);
+    }
+}
+OUTPUT: RETVAL
+
+SV*
+peek(self)
+    lucy_BBSortEx *self;
+CODE:
+{
+    void *address = Lucy_BBSortEx_Peek(self);
+    if (address) {
+        RETVAL = XSBind_cfish_to_perl(*(cfish_Obj**)address);
+    }
+    else {
+        RETVAL = newSV(0);
+    }
+}
+OUTPUT: RETVAL
+
+void
+feed(self, bb)
+    lucy_BBSortEx *self;
+    cfish_ByteBuf *bb;
+CODE:
+    CFISH_INCREF(bb);
+    Lucy_BBSortEx_Feed(self, &bb);
+
+END_XS_CODE
+
+    my $binding = Clownfish::CFC::Binding::Perl::Class->new(
+        parcel     => "Lucy",
+        class_name => "Lucy::Util::BBSortEx",
+    );
+    $binding->append_xs($xs_code);
+
+    Clownfish::CFC::Binding::Perl::Class->register($binding);
+}
+
 sub bind_debug {
     my $xs_code = <<'END_XS_CODE';
 MODULE = Lucy   PACKAGE = Lucy::Util::Debug

http://git-wip-us.apache.org/repos/asf/lucy/blob/ee006ebb/perl/lib/Lucy/Test/Util/BBSortEx.pm
----------------------------------------------------------------------
diff --git a/perl/lib/Lucy/Test/Util/BBSortEx.pm b/perl/lib/Lucy/Test/Util/BBSortEx.pm
deleted file mode 100644
index 5c968f7..0000000
--- a/perl/lib/Lucy/Test/Util/BBSortEx.pm
+++ /dev/null
@@ -1,25 +0,0 @@
-# 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.
-
-package Lucy::Test::Util::BBSortEx;
-use Lucy;
-our $VERSION = '0.003000';
-$VERSION = eval $VERSION;
-
-1;
-
-__END__
-
-

http://git-wip-us.apache.org/repos/asf/lucy/blob/ee006ebb/perl/lib/Lucy/Util/BBSortEx.pm
----------------------------------------------------------------------
diff --git a/perl/lib/Lucy/Util/BBSortEx.pm b/perl/lib/Lucy/Util/BBSortEx.pm
new file mode 100644
index 0000000..cbba688
--- /dev/null
+++ b/perl/lib/Lucy/Util/BBSortEx.pm
@@ -0,0 +1,25 @@
+# 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.
+
+package Lucy::Util::BBSortEx;
+use Lucy;
+our $VERSION = '0.003000';
+$VERSION = eval $VERSION;
+
+1;
+
+__END__
+
+

http://git-wip-us.apache.org/repos/asf/lucy/blob/ee006ebb/perl/t/015-sort_external.t
----------------------------------------------------------------------
diff --git a/perl/t/015-sort_external.t b/perl/t/015-sort_external.t
index 4d8bdad..134e7c7 100644
--- a/perl/t/015-sort_external.t
+++ b/perl/t/015-sort_external.t
@@ -23,7 +23,7 @@ use bytes qw();
 
 my ( $sortex, $cache, @orig, @sort_output );
 
-$sortex = Lucy::Test::Util::BBSortEx->new( mem_thresh => 4 );
+$sortex = Lucy::Util::BBSortEx->new( mem_thresh => 4 );
 $sortex->feed( new_bytebuf('c') );
 is( $sortex->cache_count, 1, "feed elem into cache" );
 
@@ -42,7 +42,7 @@ is( $sortex->cache_count, 0,
 #is( $sortex->get_num_runs, 1, "run added" );
 
 my @bytebufs = map { new_bytebuf($_) } qw( x y z );
-my $run = Lucy::Test::Util::BBSortEx->new( external => \@bytebufs );
+my $run = Lucy::Util::BBSortEx->new( external => \@bytebufs );
 $sortex->add_run($run);
 $sortex->flip;
 @orig = qw( a b c d x y z );
@@ -53,7 +53,7 @@ is_deeply( \@sort_output, \@orig, "Add_Run" );
 @orig        = ();
 @sort_output = ();
 
-$sortex = Lucy::Test::Util::BBSortEx->new( mem_thresh => 4 );
+$sortex = Lucy::Util::BBSortEx->new( mem_thresh => 4 );
 $sortex->feed( new_bytebuf('c') );
 $sortex->clear_cache;
 is( $sortex->cache_count, 0, "Clear_Cache" );
@@ -72,7 +72,7 @@ is_deeply( \@sort_output, \@orig,
 @orig        = ();
 @sort_output = ();
 
-$sortex = Lucy::Test::Util::BBSortEx->new;
+$sortex = Lucy::Util::BBSortEx->new;
 @orig   = ( 'a' .. 'z' );
 $sortex->feed( new_bytebuf($_) ) for shuffle(@orig);
 $sortex->flip;
@@ -83,7 +83,7 @@ is_deeply( \@sort_output, \@orig, "sort letters" );
 @orig        = ();
 @sort_output = ();
 
-$sortex = Lucy::Test::Util::BBSortEx->new;
+$sortex = Lucy::Util::BBSortEx->new;
 @orig   = qw( a a a b c d x x x x x x y y );
 $sortex->feed( new_bytebuf($_) ) for shuffle(@orig);
 $sortex->flip;
@@ -94,7 +94,7 @@ is_deeply( \@sort_output, \@orig, "sort repeated letters" );
 @orig        = ();
 @sort_output = ();
 
-$sortex = Lucy::Test::Util::BBSortEx->new;
+$sortex = Lucy::Util::BBSortEx->new;
 @orig = ( '', '', 'a' .. 'z' );
 $sortex->feed( new_bytebuf($_) ) for shuffle(@orig);
 $sortex->flip;
@@ -105,7 +105,7 @@ is_deeply( \@sort_output, \@orig, "sort letters and empty strings" );
 @orig        = ();
 @sort_output = ();
 
-$sortex = Lucy::Test::Util::BBSortEx->new( mem_thresh => 30 );
+$sortex = Lucy::Util::BBSortEx->new( mem_thresh => 30 );
 @orig = 'a' .. 'z';
 $sortex->feed( new_bytebuf($_) ) for shuffle(@orig);
 $sortex->flip;
@@ -116,7 +116,7 @@ is_deeply( \@sort_output, \@orig, "... with an absurdly low mem_thresh" );
 @orig        = ();
 @sort_output = ();
 
-$sortex = Lucy::Test::Util::BBSortEx->new( mem_thresh => 1 );
+$sortex = Lucy::Util::BBSortEx->new( mem_thresh => 1 );
 @orig = 'a' .. 'z';
 $sortex->feed( new_bytebuf($_) ) for shuffle(@orig);
 $sortex->flip;
@@ -127,13 +127,13 @@ is_deeply( \@sort_output, \@orig, "... with an even lower mem_thresh" );
 @orig        = ();
 @sort_output = ();
 
-$sortex = Lucy::Test::Util::BBSortEx->new;
+$sortex = Lucy::Util::BBSortEx->new;
 $sortex->flip;
 @sort_output = $sortex->fetch;
 is_deeply( \@sort_output, [undef], "Sorting nothing returns undef" );
 @sort_output = ();
 
-$sortex = Lucy::Test::Util::BBSortEx->new( mem_thresh => 5_000 );
+$sortex = Lucy::Util::BBSortEx->new( mem_thresh => 5_000 );
 @orig = map { pack( 'N', $_ ) } ( 0 .. 11_000 );
 $sortex->feed( new_bytebuf($_) ) for shuffle(@orig);
 $sortex->flip;
@@ -143,7 +143,7 @@ while ( defined( my $item = $sortex->fetch ) ) {
 is_deeply( \@sort_output, \@orig, "Sorting packed integers..." );
 @sort_output = ();
 
-$sortex = Lucy::Test::Util::BBSortEx->new( mem_thresh => 15_000 );
+$sortex = Lucy::Util::BBSortEx->new( mem_thresh => 15_000 );
 @orig = ();
 for my $iter ( 0 .. 1_000 ) {
     my $string = '';

http://git-wip-us.apache.org/repos/asf/lucy/blob/ee006ebb/perl/t/028-sortexrun.t
----------------------------------------------------------------------
diff --git a/perl/t/028-sortexrun.t b/perl/t/028-sortexrun.t
index 64b9ef7..a9a075b 100644
--- a/perl/t/028-sortexrun.t
+++ b/perl/t/028-sortexrun.t
@@ -24,7 +24,7 @@ use Clownfish qw( to_perl );
 
 my $letters = Clownfish::VArray->new( capacity => 26 );
 $letters->push( Clownfish::ByteBuf->new($_) ) for 'a' .. 'z';
-my $run = Lucy::Test::Util::BBSortEx->new( external => $letters );
+my $run = Lucy::Util::BBSortEx->new( external => $letters );
 $run->set_mem_thresh(5);
 
 my $num_in_cache = $run->refill;


[lucy-commits] [2/7] git commit: refs/heads/ivars-wip1 - Avoid non-parcel member access in TestLucy.

Posted by ma...@apache.org.
Avoid non-parcel member access in TestLucy.

Use various techniques to avoid accessing member vars defined in other
parcels.


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

Branch: refs/heads/ivars-wip1
Commit: e733e2af8c8c0f2fc352ab70159e9c544bbddfc0
Parents: ee006eb
Author: Marvin Humphrey <ma...@rectangular.com>
Authored: Fri Jul 12 19:18:18 2013 -0700
Committer: Marvin Humphrey <ma...@rectangular.com>
Committed: Sat Jul 13 15:17:27 2013 -0700

----------------------------------------------------------------------
 core/Lucy/Test/Search/TestQueryParserLogic.c |  2 +-
 core/Lucy/Test/Search/TestSortSpec.c         |  7 +-----
 core/Lucy/Test/TestSchema.c                  | 26 +++++++++++++----------
 core/Lucy/Test/TestSchema.cfh                |  6 ++++--
 4 files changed, 21 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy/blob/e733e2af/core/Lucy/Test/Search/TestQueryParserLogic.c
----------------------------------------------------------------------
diff --git a/core/Lucy/Test/Search/TestQueryParserLogic.c b/core/Lucy/Test/Search/TestQueryParserLogic.c
index 2507fce..a467c59 100644
--- a/core/Lucy/Test/Search/TestQueryParserLogic.c
+++ b/core/Lucy/Test/Search/TestQueryParserLogic.c
@@ -858,7 +858,7 @@ static Lucy_TestQPLogic_Prune_Test_t prune_test_funcs[] = {
 
 static Folder*
 S_create_index() {
-    Schema     *schema  = (Schema*)TestSchema_new();
+    Schema     *schema  = (Schema*)TestSchema_new(false);
     RAMFolder  *folder  = RAMFolder_new(NULL);
     VArray     *doc_set = TestUtils_doc_set();
     Indexer    *indexer = Indexer_new(schema, (Obj*)folder, NULL, 0);

http://git-wip-us.apache.org/repos/asf/lucy/blob/e733e2af/core/Lucy/Test/Search/TestSortSpec.c
----------------------------------------------------------------------
diff --git a/core/Lucy/Test/Search/TestSortSpec.c b/core/Lucy/Test/Search/TestSortSpec.c
index 990ac9d..1a7df6d 100644
--- a/core/Lucy/Test/Search/TestSortSpec.c
+++ b/core/Lucy/Test/Search/TestSortSpec.c
@@ -153,12 +153,7 @@ TestReverseType_init(TestReverseType *self) {
 TestReverseType*
 TestReverseType_init2(TestReverseType *self, float boost, bool indexed,
                       bool stored, bool sortable) {
-    FType_init((FieldType*)self);
-    TestReverseTypeIVARS *const ivars = TestReverseType_IVARS(self);
-    ivars->boost      = boost;
-    ivars->indexed    = indexed;
-    ivars->stored     = stored;
-    ivars->sortable   = sortable;
+    Int32Type_init2((Int32Type*)self, boost, indexed, stored, sortable);
     return self;
 }
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/e733e2af/core/Lucy/Test/TestSchema.c
----------------------------------------------------------------------
diff --git a/core/Lucy/Test/TestSchema.c b/core/Lucy/Test/TestSchema.c
index 2507bfb..6c28296 100644
--- a/core/Lucy/Test/TestSchema.c
+++ b/core/Lucy/Test/TestSchema.c
@@ -27,16 +27,18 @@
 #include "Lucy/Plan/Architecture.h"
 
 TestSchema*
-TestSchema_new() {
+TestSchema_new(bool use_alt_arch) {
     TestSchema *self = (TestSchema*)VTable_Make_Obj(TESTSCHEMA);
-    return TestSchema_init(self);
+    return TestSchema_init(self, use_alt_arch);
 }
 
 TestSchema*
-TestSchema_init(TestSchema *self) {
+TestSchema_init(TestSchema *self, bool use_alt_arch) {
     StandardTokenizer *tokenizer = StandardTokenizer_new();
     FullTextType *type = FullTextType_new((Analyzer*)tokenizer);
 
+    TestSchema_IVARS(self)->use_alt_arch = use_alt_arch;
+
     Schema_init((Schema*)self);
     FullTextType_Set_Highlightable(type, true);
     CharBuf *content = (CharBuf*)ZCB_WRAP_STR("content", 7);
@@ -49,8 +51,12 @@ TestSchema_init(TestSchema *self) {
 
 Architecture*
 TestSchema_architecture(TestSchema *self) {
-    UNUSED_VAR(self);
-    return (Architecture*)TestArch_new();
+    if (TestSchema_IVARS(self)->use_alt_arch) {
+        return Arch_new();
+    }
+    else {
+        return (Architecture*)TestArch_new();
+    }
 }
 
 TestBatchSchema*
@@ -60,9 +66,9 @@ TestBatchSchema_new() {
 
 static void
 test_Equals(TestBatchRunner *runner) {
-    TestSchema *schema = TestSchema_new();
-    TestSchema *arch_differs = TestSchema_new();
-    TestSchema *spec_differs = TestSchema_new();
+    TestSchema *schema = TestSchema_new(false);
+    TestSchema *arch_differs = TestSchema_new(true);
+    TestSchema *spec_differs = TestSchema_new(false);
     CharBuf    *content      = (CharBuf*)ZCB_WRAP_STR("content", 7);
     FullTextType *type = (FullTextType*)TestSchema_Fetch_Type(spec_differs,
                                                               content);
@@ -73,8 +79,6 @@ test_Equals(TestBatchRunner *runner) {
     TEST_FALSE(runner, TestSchema_Equals(schema, (Obj*)spec_differs),
                "Equals spoiled by differing FieldType");
 
-    DECREF(TestSchema_IVARS(arch_differs)->arch);
-    TestSchema_IVARS(arch_differs)->arch = Arch_new();
     TEST_FALSE(runner, TestSchema_Equals(schema, (Obj*)arch_differs),
                "Equals spoiled by differing Architecture");
 
@@ -85,7 +89,7 @@ test_Equals(TestBatchRunner *runner) {
 
 static void
 test_Dump_and_Load(TestBatchRunner *runner) {
-    TestSchema *schema = TestSchema_new();
+    TestSchema *schema = TestSchema_new(false);
     Obj        *dump   = (Obj*)TestSchema_Dump(schema);
     TestSchema *loaded = (TestSchema*)Obj_Load(dump, dump);
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/e733e2af/core/Lucy/Test/TestSchema.cfh
----------------------------------------------------------------------
diff --git a/core/Lucy/Test/TestSchema.cfh b/core/Lucy/Test/TestSchema.cfh
index c422435..00ee5d2 100644
--- a/core/Lucy/Test/TestSchema.cfh
+++ b/core/Lucy/Test/TestSchema.cfh
@@ -23,11 +23,13 @@ parcel TestLucy;
  */
 
 class Lucy::Test::TestSchema inherits Lucy::Plan::Schema {
+    bool use_alt_arch;
+
     inert incremented TestSchema*
-    new();
+    new(bool use_alt_arch);
 
     inert TestSchema*
-    init(TestSchema *self);
+    init(TestSchema *self, bool use_alt_arch);
 
     public incremented Architecture*
     Architecture(TestSchema *self);


[lucy-commits] [7/7] git commit: refs/heads/ivars-wip1 - Limit IVARS structs to members in this parcel.

Posted by ma...@apache.org.
Limit IVARS structs to members in this parcel.

Remove member variables declared in classes from other parcels from the
IVARS structs.  Modify IVARS_OFFSET variables to be non-zero, finishing
the implementation.

Add a dynamically assigned integer parcel_id to VTable which is used to
differentiate which classes belong to different parcels.  At some point
this might be superseded by an actual parcel object of some kind.


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

Branch: refs/heads/ivars-wip1
Commit: 38ad558311c6a8ec89e1827b8f8aff6fe9818a82
Parents: 06d86f1
Author: Marvin Humphrey <ma...@rectangular.com>
Authored: Fri Jul 12 17:22:12 2013 -0700
Committer: Marvin Humphrey <ma...@rectangular.com>
Committed: Sat Jul 13 17:13:19 2013 -0700

----------------------------------------------------------------------
 clownfish/compiler/src/CFCBindClass.c       | 49 ++++++++++++++++--------
 clownfish/compiler/src/CFCBindCore.c        |  3 +-
 clownfish/compiler/src/CFCClass.c           |  5 +++
 clownfish/compiler/src/CFCClass.h           |  3 ++
 clownfish/runtime/core/Clownfish/VTable.c   | 43 ++++++++++++++++++++-
 clownfish/runtime/core/Clownfish/VTable.cfh |  1 +
 6 files changed, 86 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy/blob/38ad5583/clownfish/compiler/src/CFCBindClass.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCBindClass.c b/clownfish/compiler/src/CFCBindClass.c
index a431d26..59c9093 100644
--- a/clownfish/compiler/src/CFCBindClass.c
+++ b/clownfish/compiler/src/CFCBindClass.c
@@ -26,6 +26,7 @@
 #include "CFCFunction.h"
 #include "CFCMethod.h"
 #include "CFCParamList.h"
+#include "CFCParcel.h"
 #include "CFCType.h"
 #include "CFCVariable.h"
 #include "CFCUtil.h"
@@ -378,19 +379,32 @@ CFCBindClass_to_c_data(CFCBindClass *self) {
 // Create the definition for the instantiable object struct.
 static char*
 S_struct_definition(CFCBindClass *self) {
+    CFCClass *const client = self->client;
     const char *struct_sym;
-    const char *prefix = CFCClass_get_prefix(self->client);
+    const char *prefix = CFCClass_get_prefix(client);
     if (strcmp(prefix, "cfish_") == 0) {
-        struct_sym = CFCClass_full_struct_sym(self->client);
+        struct_sym = CFCClass_full_struct_sym(client);
     }
     else {
-        struct_sym = CFCClass_full_ivars_struct(self->client);
+        struct_sym = CFCClass_full_ivars_struct(client);
     }
 
-    CFCVariable **member_vars = CFCClass_member_vars(self->client);
-    char *member_decs = CFCUtil_strdup("");
+    // Count the number of member variables declared in ancestor classes
+    // outside this package so that we can skip over them.
+    int num_non_package_members = 0;
+    CFCParcel *parcel = CFCClass_get_parcel(client);
+    CFCClass *ancestor = CFCClass_get_parent(client);
+    while (ancestor && CFCClass_get_parcel(ancestor) == parcel) {
+        ancestor = CFCClass_get_parent(ancestor);
+    }
+    if (ancestor) {
+        num_non_package_members = CFCClass_num_member_vars(ancestor);
+    }
 
-    for (int i = 0; member_vars[i] != NULL; i++) {
+    // Add all member variables declared by classes in this package.
+    CFCVariable **member_vars = CFCClass_member_vars(client);
+    char *member_decs = CFCUtil_strdup("");
+    for (int i = num_non_package_members; member_vars[i] != NULL; i++) {
         const char *member_dec = CFCVariable_local_declaration(member_vars[i]);
         size_t needed = strlen(member_decs) + strlen(member_dec) + 10;
         member_decs = (char*)REALLOCATE(member_decs, needed);
@@ -410,10 +424,13 @@ char*
 CFCBindClass_spec_def(CFCBindClass *self) {
     CFCClass *client = self->client;
 
-    CFCClass    *parent     = CFCClass_get_parent(client);
-    const char  *class_name = CFCClass_get_class_name(client);
-    const char  *vt_var     = CFCClass_full_vtable_var(client);
-    const char  *struct_sym = CFCClass_full_struct_sym(client);
+    CFCClass   *parent       = CFCClass_get_parent(client);
+    const char *class_name   = CFCClass_get_class_name(client);
+    const char *vt_var       = CFCClass_full_vtable_var(client);
+    const char *struct_sym   = CFCClass_full_struct_sym(client);
+    const char *ivars_struct = CFCClass_full_ivars_struct(client);
+    const char *prefix       = CFCClass_get_prefix(client);
+    const char *class_cnick  = CFCClass_get_cnick(client);
 
     // Create a pointer to the parent class's vtable.
     char *parent_ref;
@@ -436,23 +453,23 @@ CFCBindClass_spec_def(CFCBindClass *self) {
     FREEMEM(fresh_methods);
     const char *ms_var = num_fresh ? self->method_specs_var : "NULL";
 
-    // Hack to get size of object.  TODO: This will have to be replaced by
-    // dynamic initialization.
-    char *ivars_or_not = strcmp(CFCClass_get_prefix(client), "cfish_") == 0
-                         ? "" : "IVARS";
+    const char *ivars_or_not = strcmp(prefix, "cfish_") == 0
+                               ? struct_sym : ivars_struct;
+    const char *ivars_offset_name = CFCClass_full_ivars_offset(client);
 
     char pattern[] =
         "    {\n"
         "        &%s, /* vtable */\n"
         "        %s, /* parent */\n"
         "        \"%s\", /* name */\n"
-        "        sizeof(%s%s), /* obj_alloc_size */\n"
+        "        sizeof(%s), /* ivars_size */\n"
+        "        &%s, /* ivars_offset_ptr */\n"
         "        %d, /* num_fresh */\n"
         "        %d, /* num_novel */\n"
         "        %s /* method_specs */\n"
         "    }";
     char *code = CFCUtil_sprintf(pattern, vt_var, parent_ref, class_name,
-                                 struct_sym, ivars_or_not,
+                                 ivars_or_not, ivars_offset_name,
                                  num_fresh, num_novel, ms_var);
 
     FREEMEM(parent_ref);

http://git-wip-us.apache.org/repos/asf/lucy/blob/38ad5583/clownfish/compiler/src/CFCBindCore.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCBindCore.c b/clownfish/compiler/src/CFCBindCore.c
index 91721a2..7abc4c2 100644
--- a/clownfish/compiler/src/CFCBindCore.c
+++ b/clownfish/compiler/src/CFCBindCore.c
@@ -235,7 +235,8 @@ S_write_parcel_h(CFCBindCore *self, CFCParcel *parcel) {
         "    cfish_VTable     **vtable;\n"
         "    cfish_VTable     **parent;\n"
         "    const char        *name;\n"
-        "    size_t             obj_alloc_size;\n"
+        "    size_t             ivars_size;\n"
+        "    size_t            *ivars_offset_ptr;\n"
         "    size_t             num_fresh;\n"
         "    size_t             num_novel;\n"
         "    cfish_MethodSpec  *method_specs;\n"

http://git-wip-us.apache.org/repos/asf/lucy/blob/38ad5583/clownfish/compiler/src/CFCClass.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCClass.c b/clownfish/compiler/src/CFCClass.c
index a2eba89..ec65c6a 100644
--- a/clownfish/compiler/src/CFCClass.c
+++ b/clownfish/compiler/src/CFCClass.c
@@ -726,6 +726,11 @@ CFCClass_member_vars(CFCClass *self) {
     return self->member_vars;
 }
 
+size_t
+CFCClass_num_member_vars(CFCClass *self) {
+    return self->num_member_vars;
+}
+
 CFCVariable**
 CFCClass_inert_vars(CFCClass *self) {
     return self->inert_vars;

http://git-wip-us.apache.org/repos/asf/lucy/blob/38ad5583/clownfish/compiler/src/CFCClass.h
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCClass.h b/clownfish/compiler/src/CFCClass.h
index 3d4d680..e247e3d 100644
--- a/clownfish/compiler/src/CFCClass.h
+++ b/clownfish/compiler/src/CFCClass.h
@@ -199,6 +199,9 @@ CFCClass_num_methods(CFCClass *self);
 struct CFCVariable**
 CFCClass_member_vars(CFCClass *self);
 
+size_t
+CFCClass_num_member_vars(CFCClass *self);
+
 /** Return an array of all inert (shared, class) variables.
  */
 struct CFCVariable**

http://git-wip-us.apache.org/repos/asf/lucy/blob/38ad5583/clownfish/runtime/core/Clownfish/VTable.c
----------------------------------------------------------------------
diff --git a/clownfish/runtime/core/Clownfish/VTable.c b/clownfish/runtime/core/Clownfish/VTable.c
index f278527..268664c 100644
--- a/clownfish/runtime/core/Clownfish/VTable.c
+++ b/clownfish/runtime/core/Clownfish/VTable.c
@@ -46,20 +46,42 @@ S_scrunch_charbuf(CharBuf *source, CharBuf *target);
 static Method*
 S_find_method(VTable *self, const char *meth_name);
 
+static int32_t
+S_claim_parcel_id(void);
+
 LockFreeRegistry *VTable_registry = NULL;
 
 void
 VTable_bootstrap(VTableSpec *specs, size_t num_specs)
 {
+    int32_t parcel_id = S_claim_parcel_id();
+
     /* Pass 1:
+     * - Initialize IVARS_OFFSET.
      * - Allocate memory.
      * - Initialize parent, flags, obj_alloc_size, vt_alloc_size.
+     * - Assign parcel_id.
      * - Initialize method pointers.
      */
     for (size_t i = 0; i < num_specs; ++i) {
         VTableSpec *spec   = &specs[i];
         VTable     *parent = spec->parent ? *spec->parent : NULL;
 
+        size_t ivars_offset = 0;
+        if (spec->ivars_offset_ptr != NULL) {
+            if (parent) {
+                VTable *ancestor = parent;
+                while (ancestor && ancestor->parcel_id == parcel_id) {
+                    ancestor = ancestor->parent;
+                }
+                ivars_offset = ancestor ? ancestor->obj_alloc_size : 0;
+                *spec->ivars_offset_ptr = ivars_offset;
+            }
+            else {
+                *spec->ivars_offset_ptr = 0;
+            }
+        }
+
         size_t vt_alloc_size = parent
                                ? parent->vt_alloc_size
                                : offsetof(VTable, method_ptrs);
@@ -67,8 +89,9 @@ VTable_bootstrap(VTableSpec *specs, size_t num_specs)
         VTable *vtable = (VTable*)Memory_wrapped_calloc(vt_alloc_size, 1);
 
         vtable->parent         = parent;
+        vtable->parcel_id      = parcel_id;
         vtable->flags          = 0;
-        vtable->obj_alloc_size = spec->obj_alloc_size;
+        vtable->obj_alloc_size = ivars_offset + spec->ivars_size;
         vtable->vt_alloc_size  = vt_alloc_size;
 
         if (parent) {
@@ -392,4 +415,22 @@ S_find_method(VTable *self, const char *name) {
     return NULL;
 }
 
+static size_t parcel_count;
+
+static int32_t
+S_claim_parcel_id(void) {
+    // TODO: use ordinary cas rather than cas_ptr.
+    union { size_t num; void *ptr; } old_value;
+    union { size_t num; void *ptr; } new_value;
+
+    bool succeeded = false;
+    do {
+        old_value.num = parcel_count;
+        new_value.num = old_value.num + 1;
+        succeeded = Atomic_cas_ptr((void*volatile*)&parcel_count,
+                                   old_value.ptr, new_value.ptr);
+    } while (!succeeded);
+
+    return new_value.num;
+}
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/38ad5583/clownfish/runtime/core/Clownfish/VTable.cfh
----------------------------------------------------------------------
diff --git a/clownfish/runtime/core/Clownfish/VTable.cfh b/clownfish/runtime/core/Clownfish/VTable.cfh
index 3c19d37..6d62f44 100644
--- a/clownfish/runtime/core/Clownfish/VTable.cfh
+++ b/clownfish/runtime/core/Clownfish/VTable.cfh
@@ -28,6 +28,7 @@ class Clownfish::VTable inherits Clownfish::Obj {
     VTable            *parent;
     CharBuf           *name;
     uint32_t           flags;
+    int32_t            parcel_id;
     size_t             obj_alloc_size;
     size_t             vt_alloc_size;
     VArray            *methods;