1 | /* |
2 | * This file is part of the MicroPython project, http://micropython.org/ |
3 | * |
4 | * The MIT License (MIT) |
5 | * |
6 | * Copyright (c) SatoshiLabs |
7 | * |
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
9 | * of this software and associated documentation files (the "Software"), to deal |
10 | * in the Software without restriction, including without limitation the rights |
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
12 | * copies of the Software, and to permit persons to whom the Software is |
13 | * furnished to do so, subject to the following conditions: |
14 | * |
15 | * The above copyright notice and this permission notice shall be included in |
16 | * all copies or substantial portions of the Software. |
17 | * |
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
24 | * THE SOFTWARE. |
25 | */ |
26 | |
27 | #include "py/profile.h" |
28 | #include "py/bc0.h" |
29 | #include "py/gc.h" |
30 | |
31 | #if MICROPY_PY_SYS_SETTRACE |
32 | |
33 | #define prof_trace_cb MP_STATE_THREAD(prof_trace_callback) |
34 | |
35 | STATIC uint mp_prof_bytecode_lineno(const mp_raw_code_t *rc, size_t bc) { |
36 | const mp_bytecode_prelude_t *prelude = &rc->prelude; |
37 | return mp_bytecode_get_source_line(prelude->line_info, bc); |
38 | } |
39 | |
40 | void mp_prof_extract_prelude(const byte *bytecode, mp_bytecode_prelude_t *prelude) { |
41 | const byte *ip = bytecode; |
42 | |
43 | MP_BC_PRELUDE_SIG_DECODE(ip); |
44 | prelude->n_state = n_state; |
45 | prelude->n_exc_stack = n_exc_stack; |
46 | prelude->scope_flags = scope_flags; |
47 | prelude->n_pos_args = n_pos_args; |
48 | prelude->n_kwonly_args = n_kwonly_args; |
49 | prelude->n_def_pos_args = n_def_pos_args; |
50 | |
51 | MP_BC_PRELUDE_SIZE_DECODE(ip); |
52 | |
53 | prelude->line_info = ip + 4; |
54 | prelude->opcodes = ip + n_info + n_cell; |
55 | |
56 | qstr block_name = ip[0] | (ip[1] << 8); |
57 | qstr source_file = ip[2] | (ip[3] << 8); |
58 | prelude->qstr_block_name = block_name; |
59 | prelude->qstr_source_file = source_file; |
60 | } |
61 | |
62 | /******************************************************************************/ |
63 | // code object |
64 | |
65 | STATIC void code_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { |
66 | (void)kind; |
67 | mp_obj_code_t *o = MP_OBJ_TO_PTR(o_in); |
68 | const mp_raw_code_t *rc = o->rc; |
69 | const mp_bytecode_prelude_t *prelude = &rc->prelude; |
70 | mp_printf(print, |
71 | "<code object %q at 0x%p, file \"%q\", line %d>" , |
72 | prelude->qstr_block_name, |
73 | o, |
74 | prelude->qstr_source_file, |
75 | rc->line_of_definition |
76 | ); |
77 | } |
78 | |
79 | STATIC mp_obj_tuple_t *code_consts(const mp_raw_code_t *rc) { |
80 | const mp_bytecode_prelude_t *prelude = &rc->prelude; |
81 | int start = prelude->n_pos_args + prelude->n_kwonly_args + rc->n_obj; |
82 | int stop = prelude->n_pos_args + prelude->n_kwonly_args + rc->n_obj + rc->n_raw_code; |
83 | mp_obj_tuple_t *consts = MP_OBJ_TO_PTR(mp_obj_new_tuple(stop - start + 1, NULL)); |
84 | |
85 | size_t const_no = 0; |
86 | for (int i = start; i < stop; ++i) { |
87 | mp_obj_t code = mp_obj_new_code((const mp_raw_code_t *)MP_OBJ_TO_PTR(rc->const_table[i])); |
88 | if (code == MP_OBJ_NULL) { |
89 | m_malloc_fail(sizeof(mp_obj_code_t)); |
90 | } |
91 | consts->items[const_no++] = code; |
92 | } |
93 | consts->items[const_no++] = mp_const_none; |
94 | |
95 | return consts; |
96 | } |
97 | |
98 | STATIC mp_obj_t raw_code_lnotab(const mp_raw_code_t *rc) { |
99 | // const mp_bytecode_prelude_t *prelude = &rc->prelude; |
100 | uint start = 0; |
101 | uint stop = rc->fun_data_len - start; |
102 | |
103 | uint last_lineno = mp_prof_bytecode_lineno(rc, start); |
104 | uint lasti = 0; |
105 | |
106 | const uint buffer_chunk_size = (stop - start) >> 2; // heuristic magic |
107 | uint buffer_size = buffer_chunk_size; |
108 | byte *buffer = m_new(byte, buffer_size); |
109 | uint buffer_index = 0; |
110 | |
111 | for (uint i = start; i < stop; ++i) { |
112 | uint lineno = mp_prof_bytecode_lineno(rc, i); |
113 | size_t line_diff = lineno - last_lineno; |
114 | if (line_diff > 0) { |
115 | uint instr_diff = (i - start) - lasti; |
116 | |
117 | assert(instr_diff < 256); |
118 | assert(line_diff < 256); |
119 | |
120 | if (buffer_index + 2 > buffer_size) { |
121 | buffer = m_renew(byte, buffer, buffer_size, buffer_size + buffer_chunk_size); |
122 | buffer_size = buffer_size + buffer_chunk_size; |
123 | } |
124 | last_lineno = lineno; |
125 | lasti = i - start; |
126 | buffer[buffer_index++] = instr_diff; |
127 | buffer[buffer_index++] = line_diff; |
128 | } |
129 | } |
130 | |
131 | mp_obj_t o = mp_obj_new_bytes(buffer, buffer_index); |
132 | m_del(byte, buffer, buffer_size); |
133 | return o; |
134 | } |
135 | |
136 | STATIC void code_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { |
137 | if (dest[0] != MP_OBJ_NULL) { |
138 | // not load attribute |
139 | return; |
140 | } |
141 | mp_obj_code_t *o = MP_OBJ_TO_PTR(self_in); |
142 | const mp_raw_code_t *rc = o->rc; |
143 | const mp_bytecode_prelude_t *prelude = &rc->prelude; |
144 | switch (attr) { |
145 | case MP_QSTR_co_code: |
146 | dest[0] = mp_obj_new_bytes( |
147 | (void *)prelude->opcodes, |
148 | rc->fun_data_len - (prelude->opcodes - (const byte *)rc->fun_data) |
149 | ); |
150 | break; |
151 | case MP_QSTR_co_consts: |
152 | dest[0] = MP_OBJ_FROM_PTR(code_consts(rc)); |
153 | break; |
154 | case MP_QSTR_co_filename: |
155 | dest[0] = MP_OBJ_NEW_QSTR(prelude->qstr_source_file); |
156 | break; |
157 | case MP_QSTR_co_firstlineno: |
158 | dest[0] = MP_OBJ_NEW_SMALL_INT(mp_prof_bytecode_lineno(rc, 0)); |
159 | break; |
160 | case MP_QSTR_co_name: |
161 | dest[0] = MP_OBJ_NEW_QSTR(prelude->qstr_block_name); |
162 | break; |
163 | case MP_QSTR_co_names: |
164 | dest[0] = MP_OBJ_FROM_PTR(o->dict_locals); |
165 | break; |
166 | case MP_QSTR_co_lnotab: |
167 | if (!o->lnotab) { |
168 | o->lnotab = raw_code_lnotab(rc); |
169 | } |
170 | dest[0] = o->lnotab; |
171 | break; |
172 | } |
173 | } |
174 | |
175 | const mp_obj_type_t mp_type_settrace_codeobj = { |
176 | { &mp_type_type }, |
177 | .name = MP_QSTR_code, |
178 | .print = code_print, |
179 | .unary_op = mp_generic_unary_op, |
180 | .attr = code_attr, |
181 | }; |
182 | |
183 | mp_obj_t mp_obj_new_code(const mp_raw_code_t *rc) { |
184 | mp_obj_code_t *o = m_new_obj_maybe(mp_obj_code_t); |
185 | if (o == NULL) { |
186 | return MP_OBJ_NULL; |
187 | } |
188 | o->base.type = &mp_type_settrace_codeobj; |
189 | o->rc = rc; |
190 | o->dict_locals = mp_locals_get(); // this is a wrong! how to do this properly? |
191 | o->lnotab = MP_OBJ_NULL; |
192 | return MP_OBJ_FROM_PTR(o); |
193 | } |
194 | |
195 | /******************************************************************************/ |
196 | // frame object |
197 | |
198 | STATIC void frame_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { |
199 | (void)kind; |
200 | mp_obj_frame_t *frame = MP_OBJ_TO_PTR(o_in); |
201 | mp_obj_code_t *code = frame->code; |
202 | const mp_raw_code_t *rc = code->rc; |
203 | const mp_bytecode_prelude_t *prelude = &rc->prelude; |
204 | mp_printf(print, |
205 | "<frame at 0x%p, file '%q', line %d, code %q>" , |
206 | frame, |
207 | prelude->qstr_source_file, |
208 | frame->lineno, |
209 | prelude->qstr_block_name |
210 | ); |
211 | } |
212 | |
213 | STATIC void frame_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { |
214 | if (dest[0] != MP_OBJ_NULL) { |
215 | // not load attribute |
216 | return; |
217 | } |
218 | |
219 | mp_obj_frame_t *o = MP_OBJ_TO_PTR(self_in); |
220 | |
221 | switch (attr) { |
222 | case MP_QSTR_f_back: |
223 | dest[0] = mp_const_none; |
224 | if (o->code_state->prev_state) { |
225 | dest[0] = MP_OBJ_FROM_PTR(o->code_state->prev_state->frame); |
226 | } |
227 | break; |
228 | case MP_QSTR_f_code: |
229 | dest[0] = MP_OBJ_FROM_PTR(o->code); |
230 | break; |
231 | case MP_QSTR_f_globals: |
232 | dest[0] = MP_OBJ_FROM_PTR(o->code_state->fun_bc->globals); |
233 | break; |
234 | case MP_QSTR_f_lasti: |
235 | dest[0] = MP_OBJ_NEW_SMALL_INT(o->lasti); |
236 | break; |
237 | case MP_QSTR_f_lineno: |
238 | dest[0] = MP_OBJ_NEW_SMALL_INT(o->lineno); |
239 | break; |
240 | } |
241 | } |
242 | |
243 | const mp_obj_type_t mp_type_frame = { |
244 | { &mp_type_type }, |
245 | .name = MP_QSTR_frame, |
246 | .print = frame_print, |
247 | .unary_op = mp_generic_unary_op, |
248 | .attr = frame_attr, |
249 | }; |
250 | |
251 | mp_obj_t mp_obj_new_frame(const mp_code_state_t *code_state) { |
252 | if (gc_is_locked()) { |
253 | return MP_OBJ_NULL; |
254 | } |
255 | |
256 | mp_obj_frame_t *o = m_new_obj_maybe(mp_obj_frame_t); |
257 | if (o == NULL) { |
258 | return MP_OBJ_NULL; |
259 | } |
260 | |
261 | mp_obj_code_t *code = o->code = MP_OBJ_TO_PTR(mp_obj_new_code(code_state->fun_bc->rc)); |
262 | if (code == NULL) { |
263 | return MP_OBJ_NULL; |
264 | } |
265 | |
266 | const mp_raw_code_t *rc = code->rc; |
267 | const mp_bytecode_prelude_t *prelude = &rc->prelude; |
268 | o->code_state = code_state; |
269 | o->base.type = &mp_type_frame; |
270 | o->back = NULL; |
271 | o->code = code; |
272 | o->lasti = code_state->ip - prelude->opcodes; |
273 | o->lineno = mp_prof_bytecode_lineno(rc, o->lasti); |
274 | o->trace_opcodes = false; |
275 | o->callback = MP_OBJ_NULL; |
276 | |
277 | return MP_OBJ_FROM_PTR(o); |
278 | } |
279 | |
280 | |
281 | /******************************************************************************/ |
282 | // Trace logic |
283 | |
284 | typedef struct { |
285 | struct _mp_obj_frame_t *frame; |
286 | mp_obj_t event; |
287 | mp_obj_t arg; |
288 | } prof_callback_args_t; |
289 | |
290 | STATIC mp_obj_t mp_prof_callback_invoke(mp_obj_t callback, prof_callback_args_t *args) { |
291 | assert(mp_obj_is_callable(callback)); |
292 | |
293 | mp_prof_is_executing = true; |
294 | |
295 | mp_obj_t a[3] = {MP_OBJ_FROM_PTR(args->frame), args->event, args->arg}; |
296 | mp_obj_t top = mp_call_function_n_kw(callback, 3, 0, a); |
297 | |
298 | mp_prof_is_executing = false; |
299 | |
300 | if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) { |
301 | mp_obj_t obj = MP_STATE_VM(mp_pending_exception); |
302 | MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; |
303 | nlr_raise(obj); |
304 | } |
305 | return top; |
306 | } |
307 | |
308 | mp_obj_t mp_prof_settrace(mp_obj_t callback) { |
309 | if (mp_obj_is_callable(callback)) { |
310 | prof_trace_cb = callback; |
311 | } else { |
312 | prof_trace_cb = MP_OBJ_NULL; |
313 | } |
314 | return mp_const_none; |
315 | } |
316 | |
317 | mp_obj_t mp_prof_frame_enter(mp_code_state_t *code_state) { |
318 | assert(!mp_prof_is_executing); |
319 | |
320 | mp_obj_frame_t *frame = MP_OBJ_TO_PTR(mp_obj_new_frame(code_state)); |
321 | if (frame == NULL) { |
322 | // Couldn't allocate a frame object |
323 | return MP_OBJ_NULL; |
324 | } |
325 | |
326 | if (code_state->prev_state && code_state->frame == NULL) { |
327 | // We are entering not-yet-traced frame |
328 | // which means it's a CALL event (not a GENERATOR) |
329 | // so set the function definition line. |
330 | const mp_raw_code_t *rc = code_state->fun_bc->rc; |
331 | frame->lineno = rc->line_of_definition; |
332 | if (!rc->line_of_definition) { |
333 | frame->lineno = mp_prof_bytecode_lineno(rc, 0); |
334 | } |
335 | } |
336 | code_state->frame = frame; |
337 | |
338 | if (!prof_trace_cb) { |
339 | return MP_OBJ_NULL; |
340 | } |
341 | |
342 | mp_obj_t top; |
343 | prof_callback_args_t _args, *args = &_args; |
344 | args->frame = code_state->frame; |
345 | |
346 | // SETTRACE event CALL |
347 | args->event = MP_OBJ_NEW_QSTR(MP_QSTR_call); |
348 | args->arg = mp_const_none; |
349 | top = mp_prof_callback_invoke(prof_trace_cb, args); |
350 | |
351 | code_state->frame->callback = mp_obj_is_callable(top) ? top : MP_OBJ_NULL; |
352 | |
353 | // Invalidate the last executed line number so the LINE trace can trigger after this CALL. |
354 | frame->lineno = 0; |
355 | |
356 | return top; |
357 | } |
358 | |
359 | mp_obj_t mp_prof_frame_update(const mp_code_state_t *code_state) { |
360 | mp_obj_frame_t *frame = code_state->frame; |
361 | if (frame == NULL) { |
362 | // Frame was not allocated (eg because there was no memory available) |
363 | return MP_OBJ_NULL; |
364 | } |
365 | |
366 | mp_obj_frame_t *o = frame; |
367 | mp_obj_code_t *code = o->code; |
368 | const mp_raw_code_t *rc = code->rc; |
369 | const mp_bytecode_prelude_t *prelude = &rc->prelude; |
370 | |
371 | assert(o->code_state == code_state); |
372 | |
373 | o->lasti = code_state->ip - prelude->opcodes; |
374 | o->lineno = mp_prof_bytecode_lineno(rc, o->lasti); |
375 | |
376 | return MP_OBJ_FROM_PTR(o); |
377 | } |
378 | |
379 | mp_obj_t mp_prof_instr_tick(mp_code_state_t *code_state, bool is_exception) { |
380 | // Detect execution recursion |
381 | assert(!mp_prof_is_executing); |
382 | assert(code_state->frame); |
383 | assert(mp_obj_get_type(code_state->frame) == &mp_type_frame); |
384 | |
385 | // Detect data recursion |
386 | assert(code_state != code_state->prev_state); |
387 | |
388 | mp_obj_t top = mp_const_none; |
389 | mp_obj_t callback = code_state->frame->callback; |
390 | |
391 | prof_callback_args_t _args, *args = &_args; |
392 | args->frame = code_state->frame; |
393 | args->event = mp_const_none; |
394 | args->arg = mp_const_none; |
395 | |
396 | // Call event's are handled inside mp_prof_frame_enter |
397 | |
398 | // SETTRACE event EXCEPTION |
399 | if (is_exception) { |
400 | args->event = MP_OBJ_NEW_QSTR(MP_QSTR_exception); |
401 | top = mp_prof_callback_invoke(callback, args); |
402 | return top; |
403 | } |
404 | |
405 | // SETTRACE event LINE |
406 | const mp_raw_code_t *rc = code_state->fun_bc->rc; |
407 | const mp_bytecode_prelude_t *prelude = &rc->prelude; |
408 | size_t prev_line_no = args->frame->lineno; |
409 | size_t current_line_no = mp_prof_bytecode_lineno(rc, code_state->ip - prelude->opcodes); |
410 | if (prev_line_no != current_line_no) { |
411 | args->frame->lineno = current_line_no; |
412 | args->event = MP_OBJ_NEW_QSTR(MP_QSTR_line); |
413 | top = mp_prof_callback_invoke(callback, args); |
414 | } |
415 | |
416 | // SETTRACE event RETURN |
417 | const byte *ip = code_state->ip; |
418 | if (*ip == MP_BC_RETURN_VALUE || *ip == MP_BC_YIELD_VALUE) { |
419 | args->event = MP_OBJ_NEW_QSTR(MP_QSTR_return); |
420 | top = mp_prof_callback_invoke(callback, args); |
421 | if (code_state->prev_state && *ip == MP_BC_RETURN_VALUE) { |
422 | code_state->frame->callback = MP_OBJ_NULL; |
423 | } |
424 | } |
425 | |
426 | // SETTRACE event OPCODE |
427 | // TODO: frame.f_trace_opcodes=True |
428 | if (false) { |
429 | args->event = MP_OBJ_NEW_QSTR(MP_QSTR_opcode); |
430 | } |
431 | |
432 | return top; |
433 | } |
434 | |
435 | /******************************************************************************/ |
436 | // DEBUG |
437 | |
438 | // This section is for debugging the settrace feature itself, and is not intended |
439 | // to be included in production/release builds. The code structure for this block |
440 | // was taken from py/showbc.c and should not be used as a reference. To enable |
441 | // this debug feature enable MICROPY_PROF_INSTR_DEBUG_PRINT_ENABLE in py/profile.h. |
442 | #if MICROPY_PROF_INSTR_DEBUG_PRINT_ENABLE |
443 | |
444 | #include "runtime0.h" |
445 | |
446 | #define DECODE_UINT { \ |
447 | unum = 0; \ |
448 | do { \ |
449 | unum = (unum << 7) + (*ip & 0x7f); \ |
450 | } while ((*ip++ & 0x80) != 0); \ |
451 | } |
452 | #define DECODE_ULABEL do { unum = (ip[0] | (ip[1] << 8)); ip += 2; } while (0) |
453 | #define DECODE_SLABEL do { unum = (ip[0] | (ip[1] << 8)) - 0x8000; ip += 2; } while (0) |
454 | |
455 | #define DECODE_QSTR \ |
456 | qst = ip[0] | ip[1] << 8; \ |
457 | ip += 2; |
458 | #define DECODE_PTR \ |
459 | DECODE_UINT; \ |
460 | ptr = (const byte *)const_table[unum] |
461 | #define DECODE_OBJ \ |
462 | DECODE_UINT; \ |
463 | obj = (mp_obj_t)const_table[unum] |
464 | |
465 | typedef struct _mp_dis_instruction_t { |
466 | mp_uint_t qstr_opname; |
467 | mp_uint_t arg; |
468 | mp_obj_t argobj; |
469 | mp_obj_t argobjex_cache; |
470 | } mp_dis_instruction_t; |
471 | |
472 | STATIC const byte *mp_prof_opcode_decode(const byte *ip, const mp_uint_t *const_table, mp_dis_instruction_t *instruction) { |
473 | mp_uint_t unum; |
474 | const byte *ptr; |
475 | mp_obj_t obj; |
476 | qstr qst; |
477 | |
478 | instruction->qstr_opname = MP_QSTR_; |
479 | instruction->arg = 0; |
480 | instruction->argobj = mp_const_none; |
481 | instruction->argobjex_cache = mp_const_none; |
482 | |
483 | switch (*ip++) { |
484 | case MP_BC_LOAD_CONST_FALSE: |
485 | instruction->qstr_opname = MP_QSTR_LOAD_CONST_FALSE; |
486 | break; |
487 | |
488 | case MP_BC_LOAD_CONST_NONE: |
489 | instruction->qstr_opname = MP_QSTR_LOAD_CONST_NONE; |
490 | break; |
491 | |
492 | case MP_BC_LOAD_CONST_TRUE: |
493 | instruction->qstr_opname = MP_QSTR_LOAD_CONST_TRUE; |
494 | break; |
495 | |
496 | case MP_BC_LOAD_CONST_SMALL_INT: { |
497 | mp_int_t num = 0; |
498 | if ((ip[0] & 0x40) != 0) { |
499 | // Number is negative |
500 | num--; |
501 | } |
502 | do { |
503 | num = (num << 7) | (*ip & 0x7f); |
504 | } while ((*ip++ & 0x80) != 0); |
505 | instruction->qstr_opname = MP_QSTR_LOAD_CONST_SMALL_INT; |
506 | instruction->arg = num; |
507 | break; |
508 | } |
509 | |
510 | case MP_BC_LOAD_CONST_STRING: |
511 | DECODE_QSTR; |
512 | instruction->qstr_opname = MP_QSTR_LOAD_CONST_STRING; |
513 | instruction->arg = qst; |
514 | instruction->argobj = MP_OBJ_NEW_QSTR(qst); |
515 | break; |
516 | |
517 | case MP_BC_LOAD_CONST_OBJ: |
518 | DECODE_OBJ; |
519 | instruction->qstr_opname = MP_QSTR_LOAD_CONST_OBJ; |
520 | instruction->arg = unum; |
521 | instruction->argobj = obj; |
522 | break; |
523 | |
524 | case MP_BC_LOAD_NULL: |
525 | instruction->qstr_opname = MP_QSTR_LOAD_NULL; |
526 | break; |
527 | |
528 | case MP_BC_LOAD_FAST_N: |
529 | DECODE_UINT; |
530 | instruction->qstr_opname = MP_QSTR_LOAD_FAST_N; |
531 | instruction->arg = unum; |
532 | break; |
533 | |
534 | case MP_BC_LOAD_DEREF: |
535 | DECODE_UINT; |
536 | instruction->qstr_opname = MP_QSTR_LOAD_DEREF; |
537 | instruction->arg = unum; |
538 | break; |
539 | |
540 | case MP_BC_LOAD_NAME: |
541 | DECODE_QSTR; |
542 | instruction->qstr_opname = MP_QSTR_LOAD_NAME; |
543 | instruction->arg = qst; |
544 | instruction->argobj = MP_OBJ_NEW_QSTR(qst); |
545 | if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) { |
546 | instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT(*ip++); |
547 | } |
548 | break; |
549 | |
550 | case MP_BC_LOAD_GLOBAL: |
551 | DECODE_QSTR; |
552 | instruction->qstr_opname = MP_QSTR_LOAD_GLOBAL; |
553 | instruction->arg = qst; |
554 | instruction->argobj = MP_OBJ_NEW_QSTR(qst); |
555 | if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) { |
556 | instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT(*ip++); |
557 | } |
558 | break; |
559 | |
560 | case MP_BC_LOAD_ATTR: |
561 | DECODE_QSTR; |
562 | instruction->qstr_opname = MP_QSTR_LOAD_ATTR; |
563 | instruction->arg = qst; |
564 | instruction->argobj = MP_OBJ_NEW_QSTR(qst); |
565 | if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) { |
566 | instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT(*ip++); |
567 | } |
568 | break; |
569 | |
570 | case MP_BC_LOAD_METHOD: |
571 | DECODE_QSTR; |
572 | instruction->qstr_opname = MP_QSTR_LOAD_METHOD; |
573 | instruction->arg = qst; |
574 | instruction->argobj = MP_OBJ_NEW_QSTR(qst); |
575 | break; |
576 | |
577 | case MP_BC_LOAD_SUPER_METHOD: |
578 | DECODE_QSTR; |
579 | instruction->qstr_opname = MP_QSTR_LOAD_SUPER_METHOD; |
580 | instruction->arg = qst; |
581 | instruction->argobj = MP_OBJ_NEW_QSTR(qst); |
582 | break; |
583 | |
584 | case MP_BC_LOAD_BUILD_CLASS: |
585 | instruction->qstr_opname = MP_QSTR_LOAD_BUILD_CLASS; |
586 | break; |
587 | |
588 | case MP_BC_LOAD_SUBSCR: |
589 | instruction->qstr_opname = MP_QSTR_LOAD_SUBSCR; |
590 | break; |
591 | |
592 | case MP_BC_STORE_FAST_N: |
593 | DECODE_UINT; |
594 | instruction->qstr_opname = MP_QSTR_STORE_FAST_N; |
595 | instruction->arg = unum; |
596 | break; |
597 | |
598 | case MP_BC_STORE_DEREF: |
599 | DECODE_UINT; |
600 | instruction->qstr_opname = MP_QSTR_STORE_DEREF; |
601 | instruction->arg = unum; |
602 | break; |
603 | |
604 | case MP_BC_STORE_NAME: |
605 | DECODE_QSTR; |
606 | instruction->qstr_opname = MP_QSTR_STORE_NAME; |
607 | instruction->arg = qst; |
608 | instruction->argobj = MP_OBJ_NEW_QSTR(qst); |
609 | break; |
610 | |
611 | case MP_BC_STORE_GLOBAL: |
612 | DECODE_QSTR; |
613 | instruction->qstr_opname = MP_QSTR_STORE_GLOBAL; |
614 | instruction->arg = qst; |
615 | instruction->argobj = MP_OBJ_NEW_QSTR(qst); |
616 | break; |
617 | |
618 | case MP_BC_STORE_ATTR: |
619 | DECODE_QSTR; |
620 | instruction->qstr_opname = MP_QSTR_STORE_ATTR; |
621 | instruction->arg = qst; |
622 | instruction->argobj = MP_OBJ_NEW_QSTR(qst); |
623 | if (MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE) { |
624 | instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT(*ip++); |
625 | } |
626 | break; |
627 | |
628 | case MP_BC_STORE_SUBSCR: |
629 | instruction->qstr_opname = MP_QSTR_STORE_SUBSCR; |
630 | break; |
631 | |
632 | case MP_BC_DELETE_FAST: |
633 | DECODE_UINT; |
634 | instruction->qstr_opname = MP_QSTR_DELETE_FAST; |
635 | instruction->arg = unum; |
636 | break; |
637 | |
638 | case MP_BC_DELETE_DEREF: |
639 | DECODE_UINT; |
640 | instruction->qstr_opname = MP_QSTR_DELETE_DEREF; |
641 | instruction->arg = unum; |
642 | break; |
643 | |
644 | case MP_BC_DELETE_NAME: |
645 | DECODE_QSTR; |
646 | instruction->qstr_opname = MP_QSTR_DELETE_NAME; |
647 | instruction->arg = qst; |
648 | instruction->argobj = MP_OBJ_NEW_QSTR(qst); |
649 | break; |
650 | |
651 | case MP_BC_DELETE_GLOBAL: |
652 | DECODE_QSTR; |
653 | instruction->qstr_opname = MP_QSTR_DELETE_GLOBAL; |
654 | instruction->arg = qst; |
655 | instruction->argobj = MP_OBJ_NEW_QSTR(qst); |
656 | break; |
657 | |
658 | case MP_BC_DUP_TOP: |
659 | instruction->qstr_opname = MP_QSTR_DUP_TOP; |
660 | break; |
661 | |
662 | case MP_BC_DUP_TOP_TWO: |
663 | instruction->qstr_opname = MP_QSTR_DUP_TOP_TWO; |
664 | break; |
665 | |
666 | case MP_BC_POP_TOP: |
667 | instruction->qstr_opname = MP_QSTR_POP_TOP; |
668 | break; |
669 | |
670 | case MP_BC_ROT_TWO: |
671 | instruction->qstr_opname = MP_QSTR_ROT_TWO; |
672 | break; |
673 | |
674 | case MP_BC_ROT_THREE: |
675 | instruction->qstr_opname = MP_QSTR_ROT_THREE; |
676 | break; |
677 | |
678 | case MP_BC_JUMP: |
679 | DECODE_SLABEL; |
680 | instruction->qstr_opname = MP_QSTR_JUMP; |
681 | instruction->arg = unum; |
682 | break; |
683 | |
684 | case MP_BC_POP_JUMP_IF_TRUE: |
685 | DECODE_SLABEL; |
686 | instruction->qstr_opname = MP_QSTR_POP_JUMP_IF_TRUE; |
687 | instruction->arg = unum; |
688 | break; |
689 | |
690 | case MP_BC_POP_JUMP_IF_FALSE: |
691 | DECODE_SLABEL; |
692 | instruction->qstr_opname = MP_QSTR_POP_JUMP_IF_FALSE; |
693 | instruction->arg = unum; |
694 | break; |
695 | |
696 | case MP_BC_JUMP_IF_TRUE_OR_POP: |
697 | DECODE_SLABEL; |
698 | instruction->qstr_opname = MP_QSTR_JUMP_IF_TRUE_OR_POP; |
699 | instruction->arg = unum; |
700 | break; |
701 | |
702 | case MP_BC_JUMP_IF_FALSE_OR_POP: |
703 | DECODE_SLABEL; |
704 | instruction->qstr_opname = MP_QSTR_JUMP_IF_FALSE_OR_POP; |
705 | instruction->arg = unum; |
706 | break; |
707 | |
708 | case MP_BC_SETUP_WITH: |
709 | DECODE_ULABEL; // loop-like labels are always forward |
710 | instruction->qstr_opname = MP_QSTR_SETUP_WITH; |
711 | instruction->arg = unum; |
712 | break; |
713 | |
714 | case MP_BC_WITH_CLEANUP: |
715 | instruction->qstr_opname = MP_QSTR_WITH_CLEANUP; |
716 | break; |
717 | |
718 | case MP_BC_UNWIND_JUMP: |
719 | DECODE_SLABEL; |
720 | instruction->qstr_opname = MP_QSTR_UNWIND_JUMP; |
721 | instruction->arg = unum; |
722 | break; |
723 | |
724 | case MP_BC_SETUP_EXCEPT: |
725 | DECODE_ULABEL; // except labels are always forward |
726 | instruction->qstr_opname = MP_QSTR_SETUP_EXCEPT; |
727 | instruction->arg = unum; |
728 | break; |
729 | |
730 | case MP_BC_SETUP_FINALLY: |
731 | DECODE_ULABEL; // except labels are always forward |
732 | instruction->qstr_opname = MP_QSTR_SETUP_FINALLY; |
733 | instruction->arg = unum; |
734 | break; |
735 | |
736 | case MP_BC_END_FINALLY: |
737 | // if TOS is an exception, reraises the exception (3 values on TOS) |
738 | // if TOS is an integer, does something else |
739 | // if TOS is None, just pops it and continues |
740 | // else error |
741 | instruction->qstr_opname = MP_QSTR_END_FINALLY; |
742 | break; |
743 | |
744 | case MP_BC_GET_ITER: |
745 | instruction->qstr_opname = MP_QSTR_GET_ITER; |
746 | break; |
747 | |
748 | case MP_BC_GET_ITER_STACK: |
749 | instruction->qstr_opname = MP_QSTR_GET_ITER_STACK; |
750 | break; |
751 | |
752 | case MP_BC_FOR_ITER: |
753 | DECODE_ULABEL; // the jump offset if iteration finishes; for labels are always forward |
754 | instruction->qstr_opname = MP_QSTR_FOR_ITER; |
755 | instruction->arg = unum; |
756 | break; |
757 | |
758 | case MP_BC_BUILD_TUPLE: |
759 | DECODE_UINT; |
760 | instruction->qstr_opname = MP_QSTR_BUILD_TUPLE; |
761 | instruction->arg = unum; |
762 | break; |
763 | |
764 | case MP_BC_BUILD_LIST: |
765 | DECODE_UINT; |
766 | instruction->qstr_opname = MP_QSTR_BUILD_LIST; |
767 | instruction->arg = unum; |
768 | break; |
769 | |
770 | case MP_BC_BUILD_MAP: |
771 | DECODE_UINT; |
772 | instruction->qstr_opname = MP_QSTR_BUILD_MAP; |
773 | instruction->arg = unum; |
774 | break; |
775 | |
776 | case MP_BC_STORE_MAP: |
777 | instruction->qstr_opname = MP_QSTR_STORE_MAP; |
778 | break; |
779 | |
780 | case MP_BC_BUILD_SET: |
781 | DECODE_UINT; |
782 | instruction->qstr_opname = MP_QSTR_BUILD_SET; |
783 | instruction->arg = unum; |
784 | break; |
785 | |
786 | #if MICROPY_PY_BUILTINS_SLICE |
787 | case MP_BC_BUILD_SLICE: |
788 | DECODE_UINT; |
789 | instruction->qstr_opname = MP_QSTR_BUILD_SLICE; |
790 | instruction->arg = unum; |
791 | break; |
792 | #endif |
793 | |
794 | case MP_BC_STORE_COMP: |
795 | DECODE_UINT; |
796 | instruction->qstr_opname = MP_QSTR_STORE_COMP; |
797 | instruction->arg = unum; |
798 | break; |
799 | |
800 | case MP_BC_UNPACK_SEQUENCE: |
801 | DECODE_UINT; |
802 | instruction->qstr_opname = MP_QSTR_UNPACK_SEQUENCE; |
803 | instruction->arg = unum; |
804 | break; |
805 | |
806 | case MP_BC_UNPACK_EX: |
807 | DECODE_UINT; |
808 | instruction->qstr_opname = MP_QSTR_UNPACK_EX; |
809 | instruction->arg = unum; |
810 | break; |
811 | |
812 | case MP_BC_MAKE_FUNCTION: |
813 | DECODE_PTR; |
814 | instruction->qstr_opname = MP_QSTR_MAKE_FUNCTION; |
815 | instruction->arg = unum; |
816 | instruction->argobj = mp_obj_new_int_from_ull((uint64_t)ptr); |
817 | break; |
818 | |
819 | case MP_BC_MAKE_FUNCTION_DEFARGS: |
820 | DECODE_PTR; |
821 | instruction->qstr_opname = MP_QSTR_MAKE_FUNCTION_DEFARGS; |
822 | instruction->arg = unum; |
823 | instruction->argobj = mp_obj_new_int_from_ull((uint64_t)ptr); |
824 | break; |
825 | |
826 | case MP_BC_MAKE_CLOSURE: { |
827 | DECODE_PTR; |
828 | mp_uint_t n_closed_over = *ip++; |
829 | instruction->qstr_opname = MP_QSTR_MAKE_CLOSURE; |
830 | instruction->arg = unum; |
831 | instruction->argobj = mp_obj_new_int_from_ull((uint64_t)ptr); |
832 | instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT(n_closed_over); |
833 | break; |
834 | } |
835 | |
836 | case MP_BC_MAKE_CLOSURE_DEFARGS: { |
837 | DECODE_PTR; |
838 | mp_uint_t n_closed_over = *ip++; |
839 | instruction->qstr_opname = MP_QSTR_MAKE_CLOSURE_DEFARGS; |
840 | instruction->arg = unum; |
841 | instruction->argobj = mp_obj_new_int_from_ull((uint64_t)ptr); |
842 | instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT(n_closed_over); |
843 | break; |
844 | } |
845 | |
846 | case MP_BC_CALL_FUNCTION: |
847 | DECODE_UINT; |
848 | instruction->qstr_opname = MP_QSTR_CALL_FUNCTION; |
849 | instruction->arg = unum & 0xff; |
850 | instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT((unum >> 8) & 0xff); |
851 | break; |
852 | |
853 | case MP_BC_CALL_FUNCTION_VAR_KW: |
854 | DECODE_UINT; |
855 | instruction->qstr_opname = MP_QSTR_CALL_FUNCTION_VAR_KW; |
856 | instruction->arg = unum & 0xff; |
857 | instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT((unum >> 8) & 0xff); |
858 | break; |
859 | |
860 | case MP_BC_CALL_METHOD: |
861 | DECODE_UINT; |
862 | instruction->qstr_opname = MP_QSTR_CALL_METHOD; |
863 | instruction->arg = unum & 0xff; |
864 | instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT((unum >> 8) & 0xff); |
865 | break; |
866 | |
867 | case MP_BC_CALL_METHOD_VAR_KW: |
868 | DECODE_UINT; |
869 | instruction->qstr_opname = MP_QSTR_CALL_METHOD_VAR_KW; |
870 | instruction->arg = unum & 0xff; |
871 | instruction->argobjex_cache = MP_OBJ_NEW_SMALL_INT((unum >> 8) & 0xff); |
872 | break; |
873 | |
874 | case MP_BC_RETURN_VALUE: |
875 | instruction->qstr_opname = MP_QSTR_RETURN_VALUE; |
876 | break; |
877 | |
878 | case MP_BC_RAISE_LAST: |
879 | instruction->qstr_opname = MP_QSTR_RAISE_LAST; |
880 | break; |
881 | |
882 | case MP_BC_RAISE_OBJ: |
883 | instruction->qstr_opname = MP_QSTR_RAISE_OBJ; |
884 | break; |
885 | |
886 | case MP_BC_RAISE_FROM: |
887 | instruction->qstr_opname = MP_QSTR_RAISE_FROM; |
888 | break; |
889 | |
890 | case MP_BC_YIELD_VALUE: |
891 | instruction->qstr_opname = MP_QSTR_YIELD_VALUE; |
892 | break; |
893 | |
894 | case MP_BC_YIELD_FROM: |
895 | instruction->qstr_opname = MP_QSTR_YIELD_FROM; |
896 | break; |
897 | |
898 | case MP_BC_IMPORT_NAME: |
899 | DECODE_QSTR; |
900 | instruction->qstr_opname = MP_QSTR_IMPORT_NAME; |
901 | instruction->arg = qst; |
902 | instruction->argobj = MP_OBJ_NEW_QSTR(qst); |
903 | break; |
904 | |
905 | case MP_BC_IMPORT_FROM: |
906 | DECODE_QSTR; |
907 | instruction->qstr_opname = MP_QSTR_IMPORT_FROM; |
908 | instruction->arg = qst; |
909 | instruction->argobj = MP_OBJ_NEW_QSTR(qst); |
910 | break; |
911 | |
912 | case MP_BC_IMPORT_STAR: |
913 | instruction->qstr_opname = MP_QSTR_IMPORT_STAR; |
914 | break; |
915 | |
916 | default: |
917 | if (ip[-1] < MP_BC_LOAD_CONST_SMALL_INT_MULTI + 64) { |
918 | instruction->qstr_opname = MP_QSTR_LOAD_CONST_SMALL_INT; |
919 | instruction->arg = (mp_int_t)ip[-1] - MP_BC_LOAD_CONST_SMALL_INT_MULTI - 16; |
920 | } else if (ip[-1] < MP_BC_LOAD_FAST_MULTI + 16) { |
921 | instruction->qstr_opname = MP_QSTR_LOAD_FAST; |
922 | instruction->arg = (mp_uint_t)ip[-1] - MP_BC_LOAD_FAST_MULTI; |
923 | } else if (ip[-1] < MP_BC_STORE_FAST_MULTI + 16) { |
924 | instruction->qstr_opname = MP_QSTR_STORE_FAST; |
925 | instruction->arg = (mp_uint_t)ip[-1] - MP_BC_STORE_FAST_MULTI; |
926 | } else if (ip[-1] < MP_BC_UNARY_OP_MULTI + MP_UNARY_OP_NUM_BYTECODE) { |
927 | instruction->qstr_opname = MP_QSTR_UNARY_OP; |
928 | instruction->arg = (mp_uint_t)ip[-1] - MP_BC_UNARY_OP_MULTI; |
929 | } else if (ip[-1] < MP_BC_BINARY_OP_MULTI + MP_BINARY_OP_NUM_BYTECODE) { |
930 | mp_uint_t op = ip[-1] - MP_BC_BINARY_OP_MULTI; |
931 | instruction->qstr_opname = MP_QSTR_BINARY_OP; |
932 | instruction->arg = op; |
933 | } else { |
934 | mp_printf(&mp_plat_print, "code %p, opcode 0x%02x not implemented\n" , ip - 1, ip[-1]); |
935 | assert(0); |
936 | return ip; |
937 | } |
938 | break; |
939 | } |
940 | |
941 | return ip; |
942 | } |
943 | |
944 | void mp_prof_print_instr(const byte *ip, mp_code_state_t *code_state) { |
945 | mp_dis_instruction_t _instruction, *instruction = &_instruction; |
946 | mp_prof_opcode_decode(ip, code_state->fun_bc->rc->const_table, instruction); |
947 | const mp_raw_code_t *rc = code_state->fun_bc->rc; |
948 | const mp_bytecode_prelude_t *prelude = &rc->prelude; |
949 | |
950 | mp_uint_t offset = ip - prelude->opcodes; |
951 | mp_printf(&mp_plat_print, "instr" ); |
952 | |
953 | /* long path */ if (1) { |
954 | mp_printf(&mp_plat_print, |
955 | "@0x%p:%q:%q+0x%04x:%d" , |
956 | ip, |
957 | prelude->qstr_source_file, |
958 | prelude->qstr_block_name, |
959 | offset, |
960 | mp_prof_bytecode_lineno(rc, offset) |
961 | ); |
962 | } |
963 | |
964 | /* bytecode */ if (0) { |
965 | mp_printf(&mp_plat_print, " %02x %02x %02x %02x" , ip[0], ip[1], ip[2], ip[3]); |
966 | } |
967 | |
968 | mp_printf(&mp_plat_print, " 0x%02x %q [%d]" , *ip, instruction->qstr_opname, instruction->arg); |
969 | |
970 | if (instruction->argobj != mp_const_none) { |
971 | mp_printf(&mp_plat_print, " $" ); |
972 | mp_obj_print_helper(&mp_plat_print, instruction->argobj, PRINT_REPR); |
973 | } |
974 | if (instruction->argobjex_cache != mp_const_none) { |
975 | mp_printf(&mp_plat_print, " #" ); |
976 | mp_obj_print_helper(&mp_plat_print, instruction->argobjex_cache, PRINT_REPR); |
977 | } |
978 | |
979 | mp_printf(&mp_plat_print, "\n" ); |
980 | } |
981 | |
982 | #endif // MICROPY_PROF_INSTR_DEBUG_PRINT_ENABLE |
983 | |
984 | #endif // MICROPY_PY_SYS_SETTRACE |
985 | |