/home/travis/build/MoarVM/MoarVM/src/core/bytecodedump.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include "moar.h" |
2 | | |
3 | 0 | #define line_length 1024 |
4 | | MVM_FORMAT(printf, 4, 5) |
5 | | static void append_string(char **out, MVMuint32 *size, |
6 | 0 | MVMuint32 *length, char *str, ...) { |
7 | 0 | char string[line_length]; |
8 | 0 | MVMuint32 len; |
9 | 0 | va_list args; |
10 | 0 | va_start(args, str); |
11 | 0 |
|
12 | 0 | vsnprintf(string, line_length, str, args); |
13 | 0 | va_end(args); |
14 | 0 |
|
15 | 0 | len = strlen(string); |
16 | 0 | if (*length + len > *size) { |
17 | 0 | while (*length + len > *size) |
18 | 0 | *size = *size * 2; |
19 | 0 | *out = MVM_realloc(*out, *size); |
20 | 0 | } |
21 | 0 |
|
22 | 0 | memcpy(*out + *length, string, len); |
23 | 0 | *length = *length + len; |
24 | 0 | } |
25 | | |
26 | 0 | static const char * get_typename(MVMuint16 type) { |
27 | 0 | switch(type) { |
28 | 0 | case MVM_reg_int8 : return "int8"; |
29 | 0 | case MVM_reg_int16: return "int16"; |
30 | 0 | case MVM_reg_int32: return "int32"; |
31 | 0 | case MVM_reg_int64: return "int"; |
32 | 0 | case MVM_reg_num32: return "num32"; |
33 | 0 | case MVM_reg_num64: return "num"; |
34 | 0 | case MVM_reg_str : return "str"; |
35 | 0 | case MVM_reg_obj : return "obj"; |
36 | 0 | case MVM_reg_uint8 : return "uint8"; |
37 | 0 | case MVM_reg_uint16: return "uint16"; |
38 | 0 | case MVM_reg_uint32: return "uint32"; |
39 | 0 | case MVM_reg_uint64: return "uint"; |
40 | 0 | default : fprintf(stderr, "unknown type %d\n", type); |
41 | 0 | return "UNKNOWN"; |
42 | 0 | } |
43 | 0 | } |
44 | | |
45 | 0 | #define a(...) append_string(&o,&s,&l, __VA_ARGS__) |
46 | | /* Macros for getting things from the bytecode stream. */ |
47 | | /* GET_REG is defined differently here from interp.c */ |
48 | | #define GET_I8(pc, idx) *((MVMint8 *)((pc) + (idx))) |
49 | | #define GET_REG(pc, idx) *((MVMuint16 *)((pc) + (idx))) |
50 | | #define GET_I16(pc, idx) *((MVMint16 *)((pc) + (idx))) |
51 | 0 | #define GET_UI16(pc, idx) *((MVMuint16 *)((pc) + (idx))) |
52 | | #define GET_I32(pc, idx) *((MVMint32 *)((pc) + (idx))) |
53 | 0 | #define GET_UI32(pc, idx) *((MVMuint32 *)((pc) + (idx))) |
54 | | #define GET_N32(pc, idx) *((MVMnum32 *)((pc) + (idx))) |
55 | | |
56 | | enum { |
57 | | MVM_val_branch_target = 1, |
58 | | MVM_val_op_boundary = 2 |
59 | | }; |
60 | | |
61 | 0 | static MVMStaticFrame * get_frame(MVMThreadContext *tc, MVMCompUnit *cu, int idx) { |
62 | 0 | return ((MVMCode *)cu->body.coderefs[idx])->body.sf; |
63 | 0 | } |
64 | | |
65 | 0 | static void bytecode_dump_frame_internal(MVMThreadContext *tc, MVMStaticFrame *frame, MVMSpeshCandidate *maybe_candidate, MVMuint8 *frame_cur_op, char ***frame_lexicals, char **oo, MVMuint32 *os, MVMuint32 *ol) { |
66 | 0 | /* since "references" are not a thing in C, keep a local copy of these |
67 | 0 | * and update the passed-in pointers at the end of the function */ |
68 | 0 | char *o = *oo; |
69 | 0 | MVMuint32 s = *os; |
70 | 0 | MVMuint32 l = *ol; |
71 | 0 |
|
72 | 0 | MVMuint32 i, j, k; |
73 | 0 |
|
74 | 0 | /* mostly stolen from validation.c */ |
75 | 0 | MVMStaticFrame *static_frame = frame; |
76 | 0 | MVMuint32 bytecode_size = maybe_candidate ? maybe_candidate->bytecode_size : static_frame->body.bytecode_size; |
77 | 0 | MVMuint8 *bytecode_start = maybe_candidate ? maybe_candidate->bytecode : static_frame->body.bytecode; |
78 | 0 | MVMuint8 *bytecode_end = bytecode_start + bytecode_size; |
79 | 0 | /* current position in the bytestream */ |
80 | 0 | MVMuint8 *cur_op = bytecode_start; |
81 | 0 | /* positions in the bytestream that are starts of ops and goto targets */ |
82 | 0 | MVMuint8 *labels = MVM_calloc(1, bytecode_size); |
83 | 0 | MVMuint32 *jumps = MVM_calloc(1, sizeof(MVMuint32) * bytecode_size); |
84 | 0 | char **lines = MVM_malloc(sizeof(char *) * bytecode_size); |
85 | 0 | MVMuint32 *linelocs = MVM_malloc(sizeof(MVMuint32) * bytecode_size); |
86 | 0 | MVMuint32 lineno = 0; |
87 | 0 | MVMuint32 lineloc; |
88 | 0 | MVMuint16 op_num; |
89 | 0 | const MVMOpInfo *op_info; |
90 | 0 | MVMuint32 operand_size = 0; |
91 | 0 | unsigned char op_rw; |
92 | 0 | unsigned char op_type; |
93 | 0 | unsigned char op_flags; |
94 | 0 | MVMOpInfo tmp_extop_info; |
95 | 0 | /* stash the outer output buffer */ |
96 | 0 | MVMuint32 sP = s; |
97 | 0 | MVMuint32 lP = l; |
98 | 0 | char *oP = o; |
99 | 0 | char *tmpstr; |
100 | 0 | char mark_this_line = 0; |
101 | 0 | MVMCompUnit *cu = static_frame->body.cu; |
102 | 0 |
|
103 | 0 | while (cur_op < bytecode_end - 1) { |
104 | 0 |
|
105 | 0 | /* allocate a line buffer */ |
106 | 0 | s = 200; |
107 | 0 | l = 0; |
108 | 0 | o = MVM_calloc(s, sizeof(char)); |
109 | 0 |
|
110 | 0 | lineloc = cur_op - bytecode_start; |
111 | 0 | /* mark that this line starts at this point in the bytestream */ |
112 | 0 | linelocs[lineno] = lineloc; |
113 | 0 | /* mark that this point in the bytestream is an op boundary */ |
114 | 0 | labels[lineloc] |= MVM_val_op_boundary; |
115 | 0 |
|
116 | 0 |
|
117 | 0 | mark_this_line = 0; |
118 | 0 | if (frame_cur_op) { |
119 | 0 | if (frame_cur_op == cur_op || frame_cur_op == cur_op + 2) { |
120 | 0 | mark_this_line = 1; |
121 | 0 | } |
122 | 0 | } |
123 | 0 |
|
124 | 0 | if (mark_this_line) { |
125 | 0 | a("-> "); |
126 | 0 | } else { |
127 | 0 | a(" "); |
128 | 0 | } |
129 | 0 |
|
130 | 0 | op_num = *((MVMint16 *)cur_op); |
131 | 0 | cur_op += 2; |
132 | 0 | if (op_num < MVM_OP_EXT_BASE) { |
133 | 0 | op_info = MVM_op_get_op(op_num); |
134 | 0 | a("%-18s ", op_info->name); |
135 | 0 | } |
136 | 0 | else { |
137 | 0 | MVMint16 ext_op_num = op_num - MVM_OP_EXT_BASE; |
138 | 0 | if (ext_op_num < cu->body.num_extops) { |
139 | 0 | MVMExtOpRecord r = cu->body.extops[ext_op_num]; |
140 | 0 | MVMuint8 j; |
141 | 0 | memset(&tmp_extop_info, 0, sizeof(MVMOpInfo)); |
142 | 0 | tmp_extop_info.name = MVM_string_utf8_encode_C_string(tc, r.name); |
143 | 0 | memcpy(tmp_extop_info.operands, r.operand_descriptor, 8); |
144 | 0 | for (j = 0; j < 8; j++) |
145 | 0 | if (tmp_extop_info.operands[j]) |
146 | 0 | tmp_extop_info.num_operands++; |
147 | 0 | else |
148 | 0 | break; |
149 | 0 | op_info = &tmp_extop_info; |
150 | 0 | a("%-12s ", tmp_extop_info.name); |
151 | 0 | MVM_free((void *)tmp_extop_info.name); |
152 | 0 | tmp_extop_info.name = NULL; |
153 | 0 | } |
154 | 0 | else { |
155 | 0 | MVM_exception_throw_adhoc(tc, "Extension op %d out of range", (int)op_num); |
156 | 0 | } |
157 | 0 | } |
158 | 0 |
|
159 | 0 | for (i = 0; i < op_info->num_operands; i++) { |
160 | 0 | if (i) a(", "); |
161 | 0 | op_flags = op_info->operands[i]; |
162 | 0 | op_rw = op_flags & MVM_operand_rw_mask; |
163 | 0 | op_type = op_flags & MVM_operand_type_mask; |
164 | 0 |
|
165 | 0 | if (op_rw == MVM_operand_literal) { |
166 | 0 | switch (op_type) { |
167 | 0 | case MVM_operand_int8: |
168 | 0 | operand_size = 1; |
169 | 0 | a("%"PRId8, GET_I8(cur_op, 0)); |
170 | 0 | break; |
171 | 0 | case MVM_operand_int16: |
172 | 0 | operand_size = 2; |
173 | 0 | a("%"PRId16, GET_I16(cur_op, 0)); |
174 | 0 | break; |
175 | 0 | case MVM_operand_int32: |
176 | 0 | operand_size = 4; |
177 | 0 | a("%"PRId32, GET_I32(cur_op, 0)); |
178 | 0 | break; |
179 | 0 | case MVM_operand_int64: |
180 | 0 | operand_size = 8; |
181 | 0 | a("%"PRId64, MVM_BC_get_I64(cur_op, 0)); |
182 | 0 | break; |
183 | 0 | case MVM_operand_uint8: |
184 | 0 | operand_size = 1; |
185 | 0 | a("%"PRIu8, GET_I8(cur_op, 0)); |
186 | 0 | break; |
187 | 0 | case MVM_operand_uint16: |
188 | 0 | operand_size = 2; |
189 | 0 | a("%"PRIu16, GET_I16(cur_op, 0)); |
190 | 0 | break; |
191 | 0 | case MVM_operand_uint32: |
192 | 0 | operand_size = 4; |
193 | 0 | a("%"PRIu32, GET_I32(cur_op, 0)); |
194 | 0 | break; |
195 | 0 | case MVM_operand_uint64: |
196 | 0 | operand_size = 8; |
197 | 0 | a("%"PRIu64, MVM_BC_get_I64(cur_op, 0)); |
198 | 0 | break; |
199 | 0 | case MVM_operand_num32: |
200 | 0 | operand_size = 4; |
201 | 0 | a("%f", GET_N32(cur_op, 0)); |
202 | 0 | break; |
203 | 0 | case MVM_operand_num64: |
204 | 0 | operand_size = 8; |
205 | 0 | a("%f", MVM_BC_get_N64(cur_op, 0)); |
206 | 0 | break; |
207 | 0 | case MVM_operand_callsite: |
208 | 0 | operand_size = 2; |
209 | 0 | a("Callsite_%"PRIu16, GET_UI16(cur_op, 0)); |
210 | 0 | break; |
211 | 0 | case MVM_operand_coderef: |
212 | 0 | operand_size = 2; |
213 | 0 | a("Frame_%"PRIu16, GET_UI16(cur_op, 0)); |
214 | 0 | break; |
215 | 0 | case MVM_operand_str: |
216 | 0 | operand_size = 4; |
217 | 0 | tmpstr = MVM_string_utf8_encode_C_string( |
218 | 0 | tc, MVM_cu_string(tc, cu, GET_UI32(cur_op, 0))); |
219 | 0 | /* XXX C-string-literal escape the \ and ' |
220 | 0 | and line breaks and non-ascii someday */ |
221 | 0 | a("'%s'", tmpstr); |
222 | 0 | MVM_free(tmpstr); |
223 | 0 | break; |
224 | 0 | case MVM_operand_ins: |
225 | 0 | operand_size = 4; |
226 | 0 | /* luckily all the ins operands are at the end |
227 | 0 | of op operands, so I can wait to resolve the label |
228 | 0 | to the end. */ |
229 | 0 | labels[GET_UI32(cur_op, 0)] |= MVM_val_branch_target; |
230 | 0 | jumps[lineno] = GET_UI32(cur_op, 0); |
231 | 0 | break; |
232 | 0 | case MVM_operand_obj: |
233 | 0 | /* not sure what a literal object is */ |
234 | 0 | operand_size = 4; |
235 | 0 | break; |
236 | 0 | case MVM_operand_spesh_slot: |
237 | 0 | operand_size = 2; |
238 | 0 | a("sslot(%d)", GET_UI16(cur_op, 0)); |
239 | 0 | break; |
240 | 0 | default: |
241 | 0 | fprintf(stderr, "what is an operand of type %d??\n", op_type); |
242 | 0 | abort(); /* never reached, silence compiler warnings */ |
243 | 0 | } |
244 | 0 | } |
245 | 0 | else if (op_rw == MVM_operand_read_reg || op_rw == MVM_operand_write_reg) { |
246 | 0 | /* register operand */ |
247 | 0 | MVMuint8 frame_has_inlines = maybe_candidate && maybe_candidate->num_inlines ? 1 : 0; |
248 | 0 | MVMuint16 *local_types = frame_has_inlines ? maybe_candidate->local_types : frame->body.local_types; |
249 | 0 | MVMuint16 num_locals = frame_has_inlines ? maybe_candidate->num_locals : frame->body.num_locals; |
250 | 0 | operand_size = 2; |
251 | 0 | a("loc_%u_%s", GET_REG(cur_op, 0), |
252 | 0 | get_typename(local_types[GET_REG(cur_op, 0)])); |
253 | 0 | } |
254 | 0 | else if (op_rw == MVM_operand_read_lex || op_rw == MVM_operand_write_lex) { |
255 | 0 | /* lexical operand */ |
256 | 0 | MVMuint16 idx, frames, m; |
257 | 0 | MVMStaticFrame *applicable_frame = static_frame; |
258 | 0 |
|
259 | 0 | operand_size = 4; |
260 | 0 | idx = GET_UI16(cur_op, 0); |
261 | 0 | frames = GET_UI16(cur_op, 2); |
262 | 0 |
|
263 | 0 | m = frames; |
264 | 0 | while (m > 0) { |
265 | 0 | applicable_frame = applicable_frame->body.outer; |
266 | 0 | m--; |
267 | 0 | } |
268 | 0 | /* inefficient, I know. should use a hash. */ |
269 | 0 | for (m = 0; m < cu->body.num_frames; m++) { |
270 | 0 | if (get_frame(tc, cu, m) == applicable_frame) { |
271 | 0 | char *lexname = frame_lexicals ? frame_lexicals[m][idx] : "lex??"; |
272 | 0 | a("lex_Frame_%u_%s_%s", m, lexname, |
273 | 0 | get_typename(applicable_frame->body.lexical_types[idx])); |
274 | 0 | } |
275 | 0 | } |
276 | 0 | } |
277 | 0 | cur_op += operand_size; |
278 | 0 | } |
279 | 0 |
|
280 | 0 | lines[lineno++] = o; |
281 | 0 | } |
282 | 0 | { |
283 | 0 | MVMuint32 *linelabels = MVM_calloc(lineno, sizeof(MVMuint32)); |
284 | 0 | MVMuint32 byte_offset = 0; |
285 | 0 | MVMuint32 line_number = 0; |
286 | 0 | MVMuint32 label_number = 1; |
287 | 0 | MVMuint32 *annotations = MVM_calloc(lineno, sizeof(MVMuint32)); |
288 | 0 |
|
289 | 0 | for (; byte_offset < bytecode_size; byte_offset++) { |
290 | 0 | if (labels[byte_offset] & MVM_val_branch_target) { |
291 | 0 | /* found a byte_offset where a label should be. |
292 | 0 | now crawl up through the lines to find which line starts there */ |
293 | 0 | while (linelocs[line_number] != byte_offset) line_number++; |
294 | 0 | linelabels[line_number] = label_number++; |
295 | 0 | } |
296 | 0 | } |
297 | 0 | o = oP; |
298 | 0 | l = lP; |
299 | 0 | s = sP; |
300 | 0 |
|
301 | 0 | i = 0; |
302 | 0 | /* resolve annotation line numbers */ |
303 | 0 | for (j = 0; j < frame->body.num_annotations; j++) { |
304 | 0 | MVMuint32 ann_offset = GET_UI32(frame->body.annotations_data, j*12); |
305 | 0 | for (; i < lineno; i++) { |
306 | 0 | if (linelocs[i] == ann_offset) { |
307 | 0 | annotations[i] = j + 1; |
308 | 0 | break; |
309 | 0 | } |
310 | 0 | } |
311 | 0 | } |
312 | 0 |
|
313 | 0 | for (j = 0; j < lineno; j++) { |
314 | 0 | if (annotations[j]) { |
315 | 0 | MVMuint16 shi = GET_UI16(frame->body.annotations_data + 4, (annotations[j] - 1)*12); |
316 | 0 | tmpstr = MVM_string_utf8_encode_C_string( |
317 | 0 | tc, MVM_cu_string(tc, cu, shi < cu->body.num_strings ? shi : 0)); |
318 | 0 | a(" annotation: %s:%u\n", tmpstr, GET_UI32(frame->body.annotations_data, (annotations[j] - 1)*12 + 8)); |
319 | 0 | MVM_free(tmpstr); |
320 | 0 | } |
321 | 0 | if (linelabels[j]) |
322 | 0 | a(" label_%u:\n", linelabels[j]); |
323 | 0 | a("%05d %s", j, lines[j]); |
324 | 0 | MVM_free(lines[j]); |
325 | 0 | if (jumps[j]) { |
326 | 0 | /* horribly inefficient for large frames. again, should use a hash */ |
327 | 0 | line_number = 0; |
328 | 0 | while (linelocs[line_number] != jumps[j]) line_number++; |
329 | 0 | a("label_%u(%05u)", linelabels[line_number], line_number); |
330 | 0 | } |
331 | 0 | a("\n"); |
332 | 0 | } |
333 | 0 | MVM_free(lines); |
334 | 0 | MVM_free(jumps); |
335 | 0 | MVM_free(linelocs); |
336 | 0 | MVM_free(linelabels); |
337 | 0 | MVM_free(labels); |
338 | 0 | MVM_free(annotations); |
339 | 0 | } |
340 | 0 |
|
341 | 0 | *oo = o; |
342 | 0 | *os = s; |
343 | 0 | *ol = l; |
344 | 0 | } |
345 | | |
346 | | |
347 | 0 | char * MVM_bytecode_dump(MVMThreadContext *tc, MVMCompUnit *cu) { |
348 | 0 | MVMuint32 s = 1024; |
349 | 0 | MVMuint32 l = 0; |
350 | 0 | MVMuint32 i, j, k; |
351 | 0 | char *o = MVM_calloc(s, sizeof(char)); |
352 | 0 | char ***frame_lexicals = MVM_malloc(sizeof(char **) * cu->body.num_frames); |
353 | 0 | MVMString *name = MVM_string_utf8_decode(tc, tc->instance->VMString, "", 0); |
354 | 0 |
|
355 | 0 | a("\nMoarVM dump of binary compilation unit:\n\n"); |
356 | 0 |
|
357 | 0 | for (k = 0; k < cu->body.num_scs; k++) { |
358 | 0 | char *tmpstr = MVM_string_utf8_encode_C_string( |
359 | 0 | tc, MVM_cu_string(tc, cu, cu->body.sc_handle_idxs[k])); |
360 | 0 | a(" SC_%u : %s\n", k, tmpstr); |
361 | 0 | MVM_free(tmpstr); |
362 | 0 | } |
363 | 0 |
|
364 | 0 | for (k = 0; k < cu->body.num_callsites; k++) { |
365 | 0 | MVMCallsite *callsite = cu->body.callsites[k]; |
366 | 0 | MVMuint16 arg_count = callsite->arg_count; |
367 | 0 | MVMuint16 nameds_count = 0; |
368 | 0 |
|
369 | 0 | a(" Callsite_%u :\n", k); |
370 | 0 | a(" num_pos: %d\n", callsite->num_pos); |
371 | 0 | a(" arg_count: %u\n", arg_count); |
372 | 0 | for (j = 0, i = 0; j < arg_count; j++) { |
373 | 0 | MVMCallsiteEntry csitee = callsite->arg_flags[i++]; |
374 | 0 | a(" Arg %u :", i); |
375 | 0 | if (csitee & MVM_CALLSITE_ARG_NAMED) { |
376 | 0 | if (callsite->arg_names) { |
377 | 0 | char *arg_name = MVM_string_utf8_encode_C_string(tc, |
378 | 0 | callsite->arg_names[nameds_count++]); |
379 | 0 | a(" named(%s)", arg_name); |
380 | 0 | MVM_free(arg_name); |
381 | 0 | } |
382 | 0 | else { |
383 | 0 | a(" named"); |
384 | 0 | } |
385 | 0 | j++; |
386 | 0 | } |
387 | 0 | else if (csitee & MVM_CALLSITE_ARG_FLAT_NAMED) { |
388 | 0 | a(" flatnamed"); |
389 | 0 | } |
390 | 0 | else if (csitee & MVM_CALLSITE_ARG_FLAT) { |
391 | 0 | a(" flat"); |
392 | 0 | } |
393 | 0 | else a(" positional"); |
394 | 0 | if (csitee & MVM_CALLSITE_ARG_OBJ) a(" obj"); |
395 | 0 | else if (csitee & MVM_CALLSITE_ARG_INT) a(" int"); |
396 | 0 | else if (csitee & MVM_CALLSITE_ARG_NUM) a(" num"); |
397 | 0 | else if (csitee & MVM_CALLSITE_ARG_STR) a(" str"); |
398 | 0 | if (csitee & MVM_CALLSITE_ARG_FLAT) a(" flat"); |
399 | 0 | a("\n"); |
400 | 0 | } |
401 | 0 | } |
402 | 0 | for (k = 0; k < cu->body.num_frames; k++) |
403 | 0 | MVM_bytecode_finish_frame(tc, cu, get_frame(tc, cu, k), 1); |
404 | 0 |
|
405 | 0 | for (k = 0; k < cu->body.num_frames; k++) { |
406 | 0 | MVMStaticFrame *frame = get_frame(tc, cu, k); |
407 | 0 | MVMLexicalRegistry *current, *tmp; |
408 | 0 | unsigned bucket_tmp; |
409 | 0 | char **lexicals; |
410 | 0 |
|
411 | 0 | if (!frame->body.fully_deserialized) { |
412 | 0 | MVM_bytecode_finish_frame(tc, cu, frame, 1); |
413 | 0 | } |
414 | 0 |
|
415 | 0 | lexicals = (char **)MVM_malloc(sizeof(char *) * frame->body.num_lexicals); |
416 | 0 | frame_lexicals[k] = lexicals; |
417 | 0 |
|
418 | 0 | HASH_ITER(hash_handle, frame->body.lexical_names, current, tmp, bucket_tmp) { |
419 | 0 | name->body.storage.blob_32 = (MVMint32 *)current->hash_handle.key; |
420 | 0 | name->body.num_graphs = (MVMuint32)current->hash_handle.keylen / sizeof(MVMGrapheme32); |
421 | 0 | lexicals[current->value] = MVM_string_utf8_encode_C_string(tc, name); |
422 | 0 | } |
423 | 0 | } |
424 | 0 | for (k = 0; k < cu->body.num_frames; k++) { |
425 | 0 | MVMStaticFrame *frame = get_frame(tc, cu, k); |
426 | 0 | char *cuuid; |
427 | 0 | char *fname; |
428 | 0 | cuuid = MVM_string_utf8_encode_C_string(tc, frame->body.cuuid); |
429 | 0 | fname = MVM_string_utf8_encode_C_string(tc, frame->body.name); |
430 | 0 | a(" Frame_%u :\n", k); |
431 | 0 | a(" cuuid : %s\n", cuuid); |
432 | 0 | MVM_free(cuuid); |
433 | 0 | a(" name : %s\n", fname); |
434 | 0 | MVM_free(fname); |
435 | 0 | for (j = 0; j < cu->body.num_frames; j++) { |
436 | 0 | if (get_frame(tc, cu, j) == frame->body.outer) |
437 | 0 | a(" outer : Frame_%u\n", j); |
438 | 0 | } |
439 | 0 |
|
440 | 0 | for (j = 0; j < frame->body.num_locals; j++) { |
441 | 0 | if (!j) |
442 | 0 | a(" Locals :\n"); |
443 | 0 | a(" %6u: loc_%u_%s\n", j, j, get_typename(frame->body.local_types[j])); |
444 | 0 | } |
445 | 0 |
|
446 | 0 | for (j = 0; j < frame->body.num_lexicals; j++) { |
447 | 0 | if (!j) |
448 | 0 | a(" Lexicals :\n"); |
449 | 0 | a(" %6u: lex_Frame_%u_%s_%s\n", j, k, frame_lexicals[k][j], get_typename(frame->body.lexical_types[j])); |
450 | 0 | } |
451 | 0 | a(" Instructions :\n"); |
452 | 0 | { |
453 | 0 | bytecode_dump_frame_internal(tc, frame, NULL, NULL, frame_lexicals, &o, &s, &l); |
454 | 0 | } |
455 | 0 | } |
456 | 0 |
|
457 | 0 | o[l] = '\0'; |
458 | 0 |
|
459 | 0 | for (k = 0; k < cu->body.num_frames; k++) { |
460 | 0 | for (j = 0; j < get_frame(tc, cu, k)->body.num_lexicals; j++) { |
461 | 0 | MVM_free(frame_lexicals[k][j]); |
462 | 0 | } |
463 | 0 | MVM_free(frame_lexicals[k]); |
464 | 0 | } |
465 | 0 | MVM_free(frame_lexicals); |
466 | 0 | return o; |
467 | 0 | } |
468 | | |
469 | | #ifdef DEBUG_HELPERS |
470 | 0 | void MVM_dump_bytecode_of(MVMThreadContext *tc, MVMFrame *frame, MVMSpeshCandidate *maybe_candidate) { |
471 | 0 | MVMuint32 s = 1024; |
472 | 0 | MVMuint32 l = 0; |
473 | 0 | char *o = MVM_calloc(s, sizeof(char)); |
474 | 0 | MVMuint8 *addr; |
475 | 0 |
|
476 | 0 | if (!frame) { |
477 | 0 | frame = tc->cur_frame; |
478 | 0 | addr = *tc->interp_cur_op; |
479 | 0 | } else { |
480 | 0 | addr = frame->return_address; |
481 | 0 | if (!addr) { |
482 | 0 | addr = *tc->interp_cur_op; |
483 | 0 | } |
484 | 0 | } |
485 | 0 |
|
486 | 0 | bytecode_dump_frame_internal(tc, frame->static_info, maybe_candidate, addr, NULL, &o, &s, &l); |
487 | 0 |
|
488 | 0 | o[l] = 0; |
489 | 0 |
|
490 | 0 | fprintf(stderr, "%s", o); |
491 | 0 | } |
492 | | |
493 | 0 | void MVM_dump_bytecode_staticframe(MVMThreadContext *tc, MVMStaticFrame *frame) { |
494 | 0 | MVMuint32 s = 1024; |
495 | 0 | MVMuint32 l = 0; |
496 | 0 | char *o = MVM_calloc(s, sizeof(char)); |
497 | 0 |
|
498 | 0 | bytecode_dump_frame_internal(tc, frame, NULL, NULL, NULL, &o, &s, &l); |
499 | 0 |
|
500 | 0 | o[l] = 0; |
501 | 0 |
|
502 | 0 | fprintf(stderr, "%s", o); |
503 | 0 | } |
504 | | |
505 | 0 | void MVM_dump_bytecode(MVMThreadContext *tc) { |
506 | 0 | MVMStaticFrame *sf = tc->cur_frame->static_info; |
507 | 0 | MVMuint8 *effective_bytecode = MVM_frame_effective_bytecode(tc->cur_frame); |
508 | 0 | if (effective_bytecode == sf->body.bytecode) { |
509 | 0 | MVM_dump_bytecode_of(tc, tc->cur_frame, NULL); |
510 | 0 | } else { |
511 | 0 | MVM_dump_bytecode_of(tc, tc->cur_frame, tc->cur_frame->spesh_cand); |
512 | 0 | /*MVMint32 spesh_cand_idx;*/ |
513 | 0 | /*MVMuint8 found = 0;*/ |
514 | 0 | /*for (spesh_cand_idx = 0; spesh_cand_idx < sf->body.num_spesh_candidates; spesh_cand_idx++) {*/ |
515 | 0 | /*MVMSpeshCandidate *cand = sf->body.spesh_candidates[spesh_cand_idx];*/ |
516 | 0 | /*if (cand->bytecode == effective_bytecode) {*/ |
517 | 0 | /*MVM_dump_bytecode_of(tc, tc->cur_frame, cand);*/ |
518 | 0 | /*found = 1;*/ |
519 | 0 | /*}*/ |
520 | 0 | /*}*/ |
521 | 0 | /*if (!found) {*/ |
522 | 0 | /* It's likely the MAGIC_BYTECODE from the jit? |
523 | 0 | * in that case we just grab tc->cur_frame->spesh_cand apparently */ |
524 | 0 | /*}*/ |
525 | 0 | } |
526 | 0 | } |
527 | | |
528 | 0 | void MVM_dump_bytecode_stackframe(MVMThreadContext *tc, MVMint32 depth) { |
529 | 0 | MVMStaticFrame *sf; |
530 | 0 | MVMuint8 *effective_bytecode; |
531 | 0 | MVMFrame *frame = tc->cur_frame; |
532 | 0 | for (;depth > 0; depth--) { |
533 | 0 | frame = frame->caller; |
534 | 0 | } |
535 | 0 | sf = frame->static_info; |
536 | 0 | effective_bytecode = MVM_frame_effective_bytecode(frame); |
537 | 0 | if (effective_bytecode == sf->body.bytecode) { |
538 | 0 | MVM_dump_bytecode_of(tc, frame, NULL); |
539 | 0 | } else { |
540 | 0 | MVMint32 spesh_cand_idx; |
541 | 0 | MVMStaticFrameSpesh *spesh = sf->body.spesh; |
542 | 0 | for (spesh_cand_idx = 0; spesh_cand_idx < spesh->body.num_spesh_candidates; spesh_cand_idx++) { |
543 | 0 | MVMSpeshCandidate *cand = spesh->body.spesh_candidates[spesh_cand_idx]; |
544 | 0 | if (cand->bytecode == effective_bytecode) { |
545 | 0 | MVM_dump_bytecode_of(tc, frame, cand); |
546 | 0 | } |
547 | 0 | } |
548 | 0 | } |
549 | 0 | } |
550 | | #endif |