summaryrefslogtreecommitdiff
path: root/package/mpatrol/mpatrol-unwindcache.patch
blob: 3234d5c8172b61301c92925b3b571166bdfc4c7b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
Patch to improve MIPS call stack unwind performance by caching the results
of code reading.
by Dan Howell <dahowell@directv.com>

diff -urN mpatrol-uclibc/src/stack.c mpatrol-unwindcache/src/stack.c
--- mpatrol-uclibc/src/stack.c	2006-06-22 15:39:04.000000000 -0700
+++ mpatrol-unwindcache/src/stack.c	2006-06-22 15:42:20.000000000 -0700
@@ -68,6 +68,7 @@
 #define ucontext asm_ucontext
 #include <asm/ucontext.h>
 #undef ucontext
+#include "heap.h"
 #endif /* ARCH */
 #endif /* SYSTEM */
 #endif /* TARGET */
@@ -280,6 +281,136 @@
 
 #if !MP_BUILTINSTACK_SUPPORT && !MP_LIBRARYSTACK_SUPPORT
 #if TARGET == TARGET_UNIX && ARCH == ARCH_MIPS
+/* Set up a tree to cache the results of code searching to determine the
+   location of the return address for each code point encountered. */
+
+/* An unwind node belongs to a binary search tree of nodes, ordered by
+ * code address, and contains call stack unwinding details for a given
+ * code address. An internal index node stores details of a single memory
+ * block allocated for unwind node slots.
+ */
+typedef union unwindnode
+{
+    struct
+    {
+        treenode node;   /* internal tree node */
+        void *block;     /* pointer to block of memory */
+        size_t size;     /* size of block of memory */
+    }
+    index;
+    struct
+    {
+        treenode node;   /* tree node */
+        long p;          /* return address offset in the stack */
+        long m;          /* frame pointer offset in stack */
+        long s;          /* stack pointer offset from previous frame */
+        unsigned long a; /* flags */
+    }
+    data;
+}
+unwindnode;
+
+/* An unwindhead holds the table of address node slots as well as the
+ * internal list of memory blocks allocated for address node slots.
+ */
+typedef struct unwindhead
+{
+    heaphead heap;       /* pointer to heap */
+    slottable table;     /* table of address nodes */
+    treeroot itree;      /* internal list of memory blocks */
+    treeroot dtree;      /* tree for sorting */
+    size_t size;         /* memory used by internal blocks */
+    char init;           /* initialization flag */
+}
+unwindhead;
+
+static unwindhead unwindcache;
+
+/* Initialise the fields of an unwindhead so that there are no allocated,
+ * freed or free blocks.
+ */
+
+static
+void
+newunwindcache(void)
+{
+    struct { char x; unwindnode y; } z;
+    long n;
+
+    __mp_newheap(&unwindcache.heap);
+    /* Determine the minimum alignment for an unwind node on this
+     * system and force the alignment to be a power of two.  This
+     * information is used when initialising the slot table.
+     */
+    n = (char *) &z.y - &z.x;
+    __mp_newslots(&unwindcache.table, sizeof(unwindnode), __mp_poweroftwo(n));
+    __mp_newtree(&unwindcache.itree);
+    __mp_newtree(&unwindcache.dtree);
+    unwindcache.size = 0;
+    unwindcache.init = 1;
+}
+
+
+/* Forget all unwind information.
+ */
+
+static
+void
+deleteunwindcache(void)
+{
+    /* We don't need to explicitly free any memory as this is dealt with
+     * at a lower level by the heap manager.
+     */
+    __mp_deleteheap(&unwindcache.heap);
+    unwindcache.table.free = NULL;
+    unwindcache.table.size = 0;
+    __mp_newtree(&unwindcache.itree);
+    __mp_newtree(&unwindcache.dtree);
+    unwindcache.size = 0;
+    unwindcache.init = 0;
+}
+
+
+/* Allocate a new unwind node.
+ */
+
+static
+unwindnode *
+getunwindnode(void)
+{
+    unwindnode *n;
+    heapnode *p;
+
+    /* If we have no more allocation node slots left then we must allocate
+     * some more memory for them.  An extra MP_ALLOCFACTOR pages of memory
+     * should suffice.
+     */
+    if ((n = (unwindnode *) __mp_getslot(&unwindcache.table)) == NULL)
+    {
+        if ((p = __mp_heapalloc(&unwindcache.heap, unwindcache.heap.memory.page * MP_ALLOCFACTOR,
+              unwindcache.table.entalign, 1)) == NULL)
+            return NULL;
+        __mp_initslots(&unwindcache.table, p->block, p->size);
+        n = (unwindnode *) __mp_getslot(&unwindcache.table);
+        __mp_treeinsert(&unwindcache.itree, &n->index.node, (unsigned long) p->block);
+        n->index.block = p->block;
+        n->index.size = p->size;
+        unwindcache.size += p->size;
+        n = (unwindnode *) __mp_getslot(&unwindcache.table);
+    }
+    return n;
+}
+
+/* Search for the unwind node associated with a given address.
+ */
+static
+unwindnode *
+findunwindnode(unsigned long p)
+{
+    return (unwindnode *) __mp_search(unwindcache.dtree.root, p);
+}
+
+
 /* Determine the stack pointer and return address of the previous stack frame
  * by performing code reading.
  */
@@ -289,8 +420,9 @@
 unwind(frameinfo *f)
 {
     long p, m, s;
-    unsigned long a, i, q, t, b, r;
+    unsigned long a, i, q, t, b, r, k;
     unsigned short l, u;
+    unwindnode *n = NULL;
 
     s = -1;
     p = m = 0;
@@ -322,7 +454,23 @@
 #endif
     /* Save initial code-reading starting point.
      */
-    r = f->ra;
+    r = k = f->ra;
+    /* Create the cache if not yet created.
+     */
+    if (!unwindcache.init)
+    {
+        newunwindcache();
+        __mp_atexit(deleteunwindcache);
+    }
+    if ((n = findunwindnode(f->ra)) != NULL)
+    {
+        /* We've been here before, so get the cached information.
+         */
+        p = n->data.p;
+        m = n->data.m;
+        s = n->data.s;
+        a = n->data.a;
+    }
     /* Search for the return address offset in the stack frame.
      */
     while (!((a & RA_OFFSET) && (a & SP_OFFSET)) && (f->ra < q))
@@ -478,6 +626,19 @@
         return 1;
     }
 #endif
+    if (n == NULL)
+    {
+        if ((n = getunwindnode()) != NULL)
+        {
+            /* Cache the information we just got in the tree.
+             */
+            n->data.p = p;
+            n->data.m = m;
+            n->data.s = s;
+            n->data.a = a;
+            __mp_treeinsert(&unwindcache.dtree, &n->data.node, k);
+        }
+    }
     if (a & SP_IN_FP)
         f->sp = f->fp;
     if (m > 0)