+static HandleChunkElem*
+chunk_element (HandleChunk *chunk, int idx)
+{
+ return &chunk->elems[idx];
+}
+
+static HandleChunkElem*
+handle_to_chunk_element (MonoObjectHandle o)
+{
+ return (HandleChunkElem*)o;
+}
+
+/* Given a HandleChunkElem* search through the current handle stack to find its chunk and offset. */
+static HandleChunk*
+chunk_element_to_chunk_idx (HandleStack *stack, HandleChunkElem *elem, int *out_idx)
+{
+ HandleChunk *top = stack->top;
+ HandleChunk *cur = stack->bottom;
+
+ *out_idx = 0;
+
+ while (cur != NULL) {
+ HandleChunkElem *front = &cur->elems [0];
+ HandleChunkElem *back = &cur->elems [cur->size];
+
+ if (front <= elem && elem < back) {
+ *out_idx = (int)(elem - front);
+ return cur;
+ }
+
+ if (cur == top)
+ break; /* didn't find it. */
+ cur = cur->next;
+ }
+ return NULL;
+}
+
+#ifdef MONO_HANDLE_TRACK_OWNER
+#ifdef HAVE_BACKTRACE_SYMBOLS
+#define SET_BACKTRACE(btaddrs) do { \
+ backtrace(btaddrs, 7); \
+ } while (0)
+#else
+#define SET_BACKTRACE(btaddrs) 0
+#endif
+#define SET_OWNER(chunk,idx) do { (chunk)->elems[(idx)].owner = owner; SET_BACKTRACE (&((chunk)->elems[(idx)].backtrace_ips[0])); } while (0)
+#else
+#define SET_OWNER(chunk,idx) do { } while (0)
+#endif
+
+#ifdef MONO_HANDLE_TRACK_SP
+#define SET_SP(handles,chunk,idx) do { (chunk)->elems[(idx)].alloc_sp = handles->stackmark_sp; } while (0)
+#else
+#define SET_SP(handles,chunk,idx) do { } while (0)
+#endif
+
+#ifdef MONO_HANDLE_TRACK_SP
+void
+mono_handle_chunk_leak_check (HandleStack *handles) {
+ if (handles->stackmark_sp) {
+ /* walk back from the top to the topmost non-empty chunk */
+ HandleChunk *c = handles->top;
+ while (c && c->size <= 0 && c != handles->bottom) {
+ c = c->prev;
+ }
+ if (c == NULL || c->size == 0)
+ return;
+ g_assert (c && c->size > 0);
+ HandleChunkElem *e = chunk_element (c, c->size - 1);
+ if (e->alloc_sp < handles->stackmark_sp) {
+ /* If we get here, the topmost object on the handle stack was
+ * allocated from a function that is deeper in the call stack than
+ * the most recent HANDLE_FUNCTION_ENTER. That means it was
+ * probably not wrapped in a HANDLE_FUNCTION_ENTER/_RETURN pair
+ * and will never be reclaimed. */
+ g_warning ("Handle %p (object = %p) (allocated from \"%s\") is leaking.\n", e, e->o,
+#ifdef MONO_HANDLE_TRACK_OWNER
+ e->owner
+#else
+ "<unknown owner>"
+#endif
+ );
+ }
+ }
+}
+#endif
+