loci: move per-obj function pointers to global tables

This saves 32 bytes per of_object.
diff --git a/c_gen/templates/_push_wire_types.c b/c_gen/templates/_push_wire_types.c
index fd2536c..96a9111 100644
--- a/c_gen/templates/_push_wire_types.c
+++ b/c_gen/templates/_push_wire_types.c
@@ -25,7 +25,7 @@
 :: # EPL for the specific language governing permissions and limitations
 :: # under the EPL.
 ::
-static void
+void
 ${data.class_name}_push_wire_types(of_object_t *obj)
 {
     unsigned char *buf = OF_OBJECT_BUFFER_INDEX(obj, 0);
diff --git a/c_gen/templates/loci_class_metadata.c b/c_gen/templates/loci_class_metadata.c
new file mode 100644
index 0000000..1aca773
--- /dev/null
+++ b/c_gen/templates/loci_class_metadata.c
@@ -0,0 +1,51 @@
+:: # Copyright 2014, Big Switch Networks, Inc.
+:: #
+:: # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+:: # the following special exception:
+:: #
+:: # LOXI Exception
+:: #
+:: # As a special exception to the terms of the EPL, you may distribute libraries
+:: # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+:: # that copyright and licensing notices generated by LoxiGen are not altered or removed
+:: # from the LoxiGen Libraries and the notice provided below is (i) included in
+:: # the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+:: # documentation for the LoxiGen Libraries, if distributed in binary form.
+:: #
+:: # Notice: "Copyright 2014, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+:: #
+:: # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+:: # a copy of the EPL at:
+:: #
+:: # http://www.eclipse.org/legal/epl-v10.html
+:: #
+:: # 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
+:: # EPL for the specific language governing permissions and limitations
+:: # under the EPL.
+::
+:: include('_copyright.c')
+:: import loxi_globals
+
+/****************************************************************
+ *
+ * loci_class_metadata.c
+ *
+ * Tables with information for each class
+ *
+ ****************************************************************/
+
+#include "loci_log.h"
+#include <loci/loci.h>
+
+struct loci_class_metadata loci_class_metadata[OF_OBJECT_COUNT] = {
+:: for data in class_metadata:
+    [${data.name.upper()}] = {
+        .wire_length_get=${data.wire_length_get},
+        .wire_length_set=${data.wire_length_set},
+        .wire_type_get=${data.wire_type_get},
+        .wire_type_set=${data.wire_type_set},
+    },
+:: #endfor
+};
diff --git a/c_gen/templates/loci_class_metadata.h b/c_gen/templates/loci_class_metadata.h
new file mode 100644
index 0000000..37962e3
--- /dev/null
+++ b/c_gen/templates/loci_class_metadata.h
@@ -0,0 +1,63 @@
+:: # Copyright 2014, Big Switch Networks, Inc.
+:: #
+:: # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
+:: # the following special exception:
+:: #
+:: # LOXI Exception
+:: #
+:: # As a special exception to the terms of the EPL, you may distribute libraries
+:: # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
+:: # that copyright and licensing notices generated by LoxiGen are not altered or removed
+:: # from the LoxiGen Libraries and the notice provided below is (i) included in
+:: # the LoxiGen Libraries, if distributed in source code form and (ii) included in any
+:: # documentation for the LoxiGen Libraries, if distributed in binary form.
+:: #
+:: # Notice: "Copyright 2014, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
+:: #
+:: # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
+:: # a copy of the EPL at:
+:: #
+:: # http://www.eclipse.org/legal/epl-v10.html
+:: #
+:: # 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
+:: # EPL for the specific language governing permissions and limitations
+:: # under the EPL.
+::
+:: include('_copyright.c')
+::
+#ifndef __LOCI_CLASS_METADATA_H__
+#define __LOCI_CLASS_METADATA_H__
+
+typedef void (*of_wire_length_get_f)(of_object_t *obj, int *bytes);
+typedef void (*of_wire_length_set_f)(of_object_t *obj, int bytes);
+typedef void (*of_wire_type_get_f)(of_object_t *obj, of_object_id_t *id);
+typedef void (*of_wire_type_set_f)(of_object_t *obj);
+
+struct loci_class_metadata {
+    of_wire_length_get_f wire_length_get;
+    of_wire_length_set_f wire_length_set;
+    of_wire_type_get_f wire_type_get;
+    of_wire_type_set_f wire_type_set;
+};
+
+extern struct loci_class_metadata loci_class_metadata[OF_OBJECT_COUNT];
+
+static inline void
+of_object_wire_length_set(of_object_t *obj, int bytes)
+{
+    if (loci_class_metadata[obj->object_id].wire_length_set) {
+        loci_class_metadata[obj->object_id].wire_length_set(obj, bytes);
+    }
+}
+
+static inline void
+of_object_wire_type_set(of_object_t *obj)
+{
+    if (loci_class_metadata[obj->object_id].wire_type_set) {
+        loci_class_metadata[obj->object_id].wire_type_set(obj);
+    }
+}
+
+#endif
diff --git a/c_gen/templates/loci_classes.h b/c_gen/templates/loci_classes.h
index 12c07d1..c5147cb 100644
--- a/c_gen/templates/loci_classes.h
+++ b/c_gen/templates/loci_classes.h
@@ -33,6 +33,7 @@
 
 :: for uclass in loxi_globals.unified.classes:
 void ${uclass.name}_wire_object_id_get(of_object_t *obj, of_object_id_t *id);
+void ${uclass.name}_push_wire_types(of_object_t *obj);
 :: #endfor
 
 ${legacy_code}
diff --git a/c_gen/templates/of_object.c b/c_gen/templates/of_object.c
index 28c00cc..6f20658 100644
--- a/c_gen/templates/of_object.c
+++ b/c_gen/templates/of_object.c
@@ -410,13 +410,8 @@
                         child->length);
 
     /* Update the wire length and type if needed */
-    if (child->wire_length_set) {
-        child->wire_length_set(child, child->length);
-    }
-
-    if (child->wire_type_set) {
-        child->wire_type_set(child);
-    }
+    of_object_wire_length_set(child, child->length);
+    of_object_wire_type_set(child);
 
     /* Update the parent's length */
     of_object_parent_length_update(parent, child->length);
@@ -568,9 +563,7 @@
     while (obj != NULL) {
         LOCI_ASSERT(count++ < _MAX_PARENT_ITERATIONS);
         obj->length += delta;
-        if (obj->wire_length_set != NULL) {
-            obj->wire_length_set(obj, obj->length);
-        }
+        of_object_wire_length_set(obj, obj->length);
 #ifndef NDEBUG
         wbuf = obj->wire_object.wbuf;
 #endif
@@ -605,9 +598,9 @@
 of_object_wire_init(of_object_t *obj, of_object_id_t base_object_id,
                     int max_len)
 {
-    if (obj->wire_type_get != NULL) {
+    if (loci_class_metadata[obj->object_id].wire_type_get != NULL) {
         of_object_id_t id;
-        obj->wire_type_get(obj, &id);
+        loci_class_metadata[obj->object_id].wire_type_get(obj, &id);
         if (!of_wire_id_valid(id, base_object_id)) {
             return OF_ERROR_PARSE;
         }
@@ -615,9 +608,9 @@
         /* Call the init function for this object type; do not push to wire */
         of_object_init_map[id]((of_object_t *)(obj), obj->version, -1, 0);
     }
-    if (obj->wire_length_get != NULL) {
+    if (loci_class_metadata[obj->object_id].wire_length_get != NULL) {
         int length;
-        obj->wire_length_get(obj, &length);
+        loci_class_metadata[obj->object_id].wire_length_get(obj, &length);
         if (length < 0 || (max_len > 0 && length > max_len)) {
             return OF_ERROR_PARSE;
         }
diff --git a/c_gen/templates/of_object.h b/c_gen/templates/of_object.h
index 72480c8..ba73a92 100644
--- a/c_gen/templates/of_object.h
+++ b/c_gen/templates/of_object.h
@@ -48,24 +48,6 @@
 #include <loci/of_message.h>
 #include <loci/of_wire_buf.h>
 
-/*
- * Generic accessors:
- *
- * Many objects have a length represented in the wire buffer
- * wire_length_get and wire_length_set access these values directly on the
- * wire.
- *
- * Many objects have a length represented in the wire buffer
- * wire_length_get and wire_length_set access these values directly on the
- * wire.
- *
- * FIXME: TBD if wire_length_set and wire_type_set are required.
- */
-typedef void (*of_wire_length_get_f)(of_object_t *obj, int *bytes);
-typedef void (*of_wire_length_set_f)(of_object_t *obj, int bytes);
-typedef void (*of_wire_type_get_f)(of_object_t *obj, of_object_id_t *id);
-typedef void (*of_wire_type_set_f)(of_object_t *obj);
-
 /****************************************************************
  * General list operations: first, next, append_setup, append_advance
  ****************************************************************/
@@ -138,15 +120,6 @@
      */
     int length;
     of_version_t version;
-
-    /*
-     * Many objects have a length and/or type represented in the wire buffer
-     * These accessors get and set those value when present.  Treat as private.
-     */
-    of_wire_length_get_f wire_length_get;
-    of_wire_length_set_f wire_length_set;
-    of_wire_type_get_f wire_type_get;
-    of_wire_type_set_f wire_type_set;
 };
 
 struct of_object_storage_s {