+static void
+stream_init (MonoDynamicStream *sh)
+{
+ sh->index = 0;
+ sh->alloc_size = 4096;
+ sh->data = g_malloc (4096);
+
+ /* So offsets are > 0 */
+ sh->index ++;
+}
+
+static void
+make_room_in_stream (MonoDynamicStream *stream, int size)
+{
+ if (size <= stream->alloc_size)
+ return;
+
+ while (stream->alloc_size <= size) {
+ if (stream->alloc_size < 4096)
+ stream->alloc_size = 4096;
+ else
+ stream->alloc_size *= 2;
+ }
+
+ stream->data = g_realloc (stream->data, stream->alloc_size);
+}
+
+static guint32
+add_stream_data (MonoDynamicStream *stream, const char *data, guint32 len)
+{
+ guint32 idx;
+
+ make_room_in_stream (stream, stream->index + len);
+ memcpy (stream->data + stream->index, data, len);
+ idx = stream->index;
+ stream->index += len;
+ return idx;
+}
+
+/*
+ * add_to_blob:
+ *
+ * Add data to the binary blob inside the aot image. Returns the offset inside the
+ * blob where the data was stored.
+ */
+static guint32
+add_to_blob (MonoAotCompile *acfg, guint8 *data, guint32 data_len)
+{
+ if (acfg->blob.alloc_size == 0)
+ stream_init (&acfg->blob);
+
+ return add_stream_data (&acfg->blob, (char*)data, data_len);
+}
+
+/*
+ * emit_offset_table:
+ *
+ * Emit a table of increasing offsets in a compact form using differential encoding.
+ * There is an index entry for each GROUP_SIZE number of entries. The greater the
+ * group size, the more compact the table becomes, but the slower it becomes to compute
+ * a given entry. Returns the size of the table.
+ */
+static guint32
+emit_offset_table (MonoAotCompile *acfg, int noffsets, int group_size, gint32 *offsets)
+{
+ gint32 current_offset;
+ int i, buf_size, ngroups, index_entry_size;
+ guint8 *p, *buf;
+ guint32 *index_offsets;
+
+ ngroups = (noffsets + (group_size - 1)) / group_size;
+
+ index_offsets = g_new0 (guint32, ngroups);
+
+ buf_size = noffsets * 4;
+ p = buf = g_malloc0 (buf_size);
+
+ current_offset = 0;
+ for (i = 0; i < noffsets; ++i) {
+ //printf ("D: %d -> %d\n", i, offsets [i]);
+ if ((i % group_size) == 0) {
+ index_offsets [i / group_size] = p - buf;
+ /* Emit the full value for these entries */
+ encode_value (offsets [i], p, &p);
+ } else {
+ /* The offsets are allowed to be non-increasing */
+ //g_assert (offsets [i] >= current_offset);
+ encode_value (offsets [i] - current_offset, p, &p);
+ }
+ current_offset = offsets [i];
+ }
+
+ if (ngroups && index_offsets [ngroups - 1] < 65000)
+ index_entry_size = 2;
+ else
+ index_entry_size = 4;
+
+ /* Emit the header */
+ emit_int32 (acfg, noffsets);
+ emit_int32 (acfg, group_size);
+ emit_int32 (acfg, ngroups);
+ emit_int32 (acfg, index_entry_size);
+
+ /* Emit the index */
+ for (i = 0; i < ngroups; ++i) {
+ if (index_entry_size == 2)
+ emit_int16 (acfg, index_offsets [i]);
+ else
+ emit_int32 (acfg, index_offsets [i]);
+ }
+
+ /* Emit the data */
+ emit_bytes (acfg, buf, p - buf);
+
+ return (int)(p - buf) + (ngroups * 4);
+}
+