You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
py: Tidy up variables in VM, probably fixes subtle bugs.
Things get tricky when using the nlr code to catch exceptions. Need to
ensure that the variables (stack layout) in the exception handler are
the same as in the bit protected by the exception handler.
Prior to this patch there were a few bugs. 1) The constant
mp_const_MemoryError_obj was being preloaded to a specific location on
the stack at the start of the function. But this location on the stack
was being overwritten in the opcode loop (since it didn't think that
variable would ever be referenced again), and so when an exception
occurred, the variable holding the address of MemoryError was corrupt.
2) The FOR_ITER opcode detection in the exception handler used sp, which
may or may not contain the right value coming out of the main opcode
loop.
With this patch there is a clear separation of variables used in the
opcode loop and in the exception handler (should fix issue (2) above).
Furthermore, nlr_raise is no longer used in the opcode loop. Instead,
it jumps directly into the exception handler. This tells the C compiler
more about the possible code flow, and means that it should have the
same stack layout for the exception handler. This should fix issue (1)
above. Indeed, the generated (ARM) assembler has been checked explicitly,
and with 'goto exception_handler', the problem with &MemoryError is
fixed.
This may now fix problems with rge-sm, and probably many other subtle
bugs yet to show themselves. Incidentally, rge-sm now passes on
pyboard (with a reduced range of integration)!
Main lesson: nlr is tricky. Don't use nlr_push unless you know what you
are doing! Luckily, it's not used in many places. Using nlr_raise/jump
is fine.
// variables that are visible to the exception handler (declared volatile)
193
190
volatileboolcurrently_in_except_block=MP_TAGPTR_TAG(*exc_sp_in_out); // 0 or 1, to detect nested exceptions
194
191
mp_exc_stack_t*volatileexc_sp=MP_TAGPTR_PTR(*exc_sp_in_out); // stack grows up, exc_sp points to top of stack
195
-
constbyte*volatilesave_ip=ip; // this is so we can access ip in the exception handler without making ip volatile (which means the compiler can't keep it in a register in the main loop)
192
+
constbyte*volatilesave_ip=*ip_in_out; // this is so we can access ip in the exception handler without making ip volatile (which means the compiler can't keep it in a register in the main loop)
193
+
mp_obj_t*volatilesave_sp=*sp_in_out; // this is so we can access sp in the exception handler when needed
196
194
197
195
// outer exception handling loop
198
196
for (;;) {
197
+
nlr_buf_tnlr;
199
198
outer_dispatch_loop:
200
199
if (nlr_push(&nlr) ==0) {
200
+
// local variables that are not visible to the exception handler
201
+
byteop=0;
202
+
constbyte*ip=*ip_in_out;
203
+
mp_obj_t*sp=*sp_in_out;
204
+
machine_uint_tunum;
205
+
qstrqst;
206
+
mp_obj_tobj1, obj2;
207
+
201
208
// If we have exception to inject, now that we finish setting up
202
209
// execution context, raise it. This works as if RAISE_VARARGS
203
210
// bytecode was executed.
204
211
// Injecting exc into yield from generator is a special case,
205
212
// handled by MP_BC_YIELD_FROM itself
206
213
if (inject_exc!=MP_OBJ_NULL&&*ip!=MP_BC_YIELD_FROM) {
0 commit comments