1 //
2 //  m3_code.c
3 //
4 //  Created by Steven Massey on 4/19/19.
5 //  Copyright © 2019 Steven Massey. All rights reserved.
6 //
7 
8 #include "m3_code.h"
9 
10 
11 //---------------------------------------------------------------------------------------------------------------------------------
12 
13 
NewCodePage(u32 i_minNumLines)14 IM3CodePage  NewCodePage  (u32 i_minNumLines)
15 {
16     static u32 s_sequence = 0;
17 
18     IM3CodePage page;
19 
20     u32 pageSize = sizeof (M3CodePageHeader) + sizeof (code_t) * i_minNumLines;
21 
22     pageSize = (pageSize + (d_m3CodePageAlignSize-1)) & ~(d_m3CodePageAlignSize-1); // align
23     page = (IM3CodePage)m3_Malloc (pageSize);
24 
25     if (page)
26     {
27         page->info.sequence = ++s_sequence;
28         page->info.numLines = (pageSize - sizeof (M3CodePageHeader)) / sizeof (code_t);
29 
30 #if d_m3RecordBacktraces
31         u32 pageSizeBt = sizeof (M3CodeMappingPage) + sizeof (M3CodeMapEntry) * page->info.numLines;
32         page->info.mapping = (M3CodeMappingPage *)m3_Malloc (pageSizeBt);
33 
34         if (page->info.mapping)
35         {
36             page->info.mapping->size = 0;
37             page->info.mapping->capacity = page->info.numLines;
38         }
39         else
40         {
41             m3_Free (page);
42             return NULL;
43         }
44         page->info.mapping->basePC = GetPageStartPC(page);
45 #endif // d_m3RecordBacktraces
46 
47         m3log (runtime, "new page: %p; seq: %d; bytes: %d; lines: %d", GetPagePC (page), page->info.sequence, pageSize, page->info.numLines);
48     }
49 
50     return page;
51 }
52 
53 
FreeCodePages(IM3CodePage * io_list)54 void  FreeCodePages  (IM3CodePage * io_list)
55 {
56     IM3CodePage page = * io_list;
57 
58     while (page)
59     {
60         m3log (code, "free page: %d; %p; util: %3.1f%%", page->info.sequence, page, 100. * page->info.lineIndex / page->info.numLines);
61 
62         IM3CodePage next = page->info.next;
63 #if d_m3RecordBacktraces
64         m3_Free (page->info.mapping);
65 #endif // d_m3RecordBacktraces
66         m3_Free (page);
67         page = next;
68     }
69 
70     * io_list = NULL;
71 }
72 
73 
NumFreeLines(IM3CodePage i_page)74 u32  NumFreeLines  (IM3CodePage i_page)
75 {
76     d_m3Assert (i_page->info.lineIndex <= i_page->info.numLines);
77 
78     return i_page->info.numLines - i_page->info.lineIndex;
79 }
80 
81 
EmitWord_impl(IM3CodePage i_page,void * i_word)82 void  EmitWord_impl  (IM3CodePage i_page, void * i_word)
83 {                                                                       d_m3Assert (i_page->info.lineIndex+1 <= i_page->info.numLines);
84     i_page->code [i_page->info.lineIndex++] = i_word;
85 }
86 
EmitWord32(IM3CodePage i_page,const u32 i_word)87 void  EmitWord32  (IM3CodePage i_page, const u32 i_word)
88 {                                                                       d_m3Assert (i_page->info.lineIndex+1 <= i_page->info.numLines);
89     * ((u32 *) & i_page->code [i_page->info.lineIndex++]) = i_word;
90 }
91 
EmitWord64(IM3CodePage i_page,const u64 i_word)92 void  EmitWord64  (IM3CodePage i_page, const u64 i_word)
93 {
94 #if M3_SIZEOF_PTR == 4
95                                                                         d_m3Assert (i_page->info.lineIndex+2 <= i_page->info.numLines);
96     * ((u64 *) & i_page->code [i_page->info.lineIndex]) = i_word;
97     i_page->info.lineIndex += 2;
98 #else
99                                                                         d_m3Assert (i_page->info.lineIndex+1 <= i_page->info.numLines);
100     * ((u64 *) & i_page->code [i_page->info.lineIndex]) = i_word;
101     i_page->info.lineIndex += 1;
102 #endif
103 }
104 
105 
106 #if d_m3RecordBacktraces
EmitMappingEntry(IM3CodePage i_page,u32 i_moduleOffset)107 void  EmitMappingEntry  (IM3CodePage i_page, u32 i_moduleOffset)
108 {
109     M3CodeMappingPage * page = i_page->info.mapping;
110                                                                         d_m3Assert (page->size < page->capacity);
111 
112     M3CodeMapEntry * entry = & page->entries[page->size++];
113     pc_t pc = GetPagePC (i_page);
114 
115     entry->pcOffset = pc - page->basePC;
116     entry->moduleOffset = i_moduleOffset;
117 }
118 #endif // d_m3RecordBacktraces
119 
GetPageStartPC(IM3CodePage i_page)120 pc_t  GetPageStartPC  (IM3CodePage i_page)
121 {
122     return & i_page->code [0];
123 }
124 
125 
GetPagePC(IM3CodePage i_page)126 pc_t  GetPagePC  (IM3CodePage i_page)
127 {
128     if (i_page)
129         return & i_page->code [i_page->info.lineIndex];
130     else
131         return NULL;
132 }
133 
134 
PushCodePage(IM3CodePage * i_list,IM3CodePage i_codePage)135 void  PushCodePage  (IM3CodePage * i_list, IM3CodePage i_codePage)
136 {
137     IM3CodePage next = * i_list;
138     i_codePage->info.next = next;
139     * i_list = i_codePage;
140 }
141 
142 
PopCodePage(IM3CodePage * i_list)143 IM3CodePage  PopCodePage  (IM3CodePage * i_list)
144 {
145     IM3CodePage page = * i_list;
146     * i_list = page->info.next;
147     page->info.next = NULL;
148 
149     return page;
150 }
151 
152 
153 
FindCodePageEnd(IM3CodePage i_list,IM3CodePage * o_end)154 u32  FindCodePageEnd  (IM3CodePage i_list, IM3CodePage * o_end)
155 {
156     u32 numPages = 0;
157     * o_end = NULL;
158 
159     while (i_list)
160     {
161         * o_end = i_list;
162         ++numPages;
163         i_list = i_list->info.next;
164     }
165 
166     return numPages;
167 }
168 
169 
CountCodePages(IM3CodePage i_list)170 u32  CountCodePages  (IM3CodePage i_list)
171 {
172     IM3CodePage unused;
173     return FindCodePageEnd (i_list, & unused);
174 }
175 
176 
GetEndCodePage(IM3CodePage i_list)177 IM3CodePage GetEndCodePage  (IM3CodePage i_list)
178 {
179     IM3CodePage end;
180     FindCodePageEnd (i_list, & end);
181 
182     return end;
183 }
184 
185 #if d_m3RecordBacktraces
ContainsPC(IM3CodePage i_page,pc_t i_pc)186 bool  ContainsPC  (IM3CodePage i_page, pc_t i_pc)
187 {
188     return GetPageStartPC (i_page) <= i_pc && i_pc < GetPagePC (i_page);
189 }
190 
191 
MapPCToOffset(IM3CodePage i_page,pc_t i_pc,u32 * o_moduleOffset)192 bool  MapPCToOffset  (IM3CodePage i_page, pc_t i_pc, u32 * o_moduleOffset)
193 {
194     M3CodeMappingPage * mapping = i_page->info.mapping;
195 
196     u32 pcOffset = i_pc - mapping->basePC;
197 
198     u32 left = 0;
199     u32 right = mapping->size;
200 
201     while (left < right)
202     {
203         u32 mid = left + (right - left) / 2;
204 
205         if (mapping->entries[mid].pcOffset < pcOffset)
206         {
207             left = mid + 1;
208         }
209         else if (mapping->entries[mid].pcOffset > pcOffset)
210         {
211             right = mid;
212         }
213         else
214         {
215             *o_moduleOffset = mapping->entries[mid].moduleOffset;
216             return true;
217         }
218     }
219 
220     // Getting here means left is now one more than the element we want.
221     if (left > 0)
222     {
223         left--;
224         *o_moduleOffset = mapping->entries[left].moduleOffset;
225         return true;
226     }
227     else return false;
228 }
229 #endif // d_m3RecordBacktraces
230 
231 //---------------------------------------------------------------------------------------------------------------------------------
232 
233 
234