(&mut self, vm: &VirtualMachine, reason: UnwindReason)
| 6321 | /// Optionally returns an exception. |
| 6322 | #[cfg_attr(feature = "flame-it", flame("Frame"))] |
| 6323 | fn unwind_blocks(&mut self, vm: &VirtualMachine, reason: UnwindReason) -> FrameResult { |
| 6324 | // use exception table for exception handling |
| 6325 | match reason { |
| 6326 | UnwindReason::Raising { exception } => { |
| 6327 | // Look up handler in exception table |
| 6328 | // lasti points to NEXT instruction (already incremented in run loop) |
| 6329 | // The exception occurred at the previous instruction |
| 6330 | // Python uses signed int where INSTR_OFFSET() - 1 = -1 before first instruction. |
| 6331 | // We use u32, so check for 0 explicitly. |
| 6332 | if self.lasti() == 0 { |
| 6333 | // No instruction executed yet, no handler can match |
| 6334 | return Err(exception); |
| 6335 | } |
| 6336 | let offset = self.lasti() - 1; |
| 6337 | if let Some(entry) = |
| 6338 | bytecode::find_exception_handler(&self.code.exceptiontable, offset) |
| 6339 | { |
| 6340 | // Fire EXCEPTION_HANDLED before setting up handler. |
| 6341 | // If the callback raises, the handler is NOT set up and the |
| 6342 | // new exception propagates instead. |
| 6343 | if vm.state.monitoring_events.load() & monitoring::EVENT_EXCEPTION_HANDLED != 0 |
| 6344 | { |
| 6345 | let byte_offset = offset * 2; |
| 6346 | let exc_obj: PyObjectRef = exception.clone().into(); |
| 6347 | monitoring::fire_exception_handled(vm, self.code, byte_offset, &exc_obj)?; |
| 6348 | } |
| 6349 | |
| 6350 | // 1. Pop stack to entry.depth |
| 6351 | while self.localsplus.stack_len() > entry.depth as usize { |
| 6352 | let _ = self.localsplus.stack_pop(); |
| 6353 | } |
| 6354 | |
| 6355 | // 2. If push_lasti=true (SETUP_CLEANUP), push lasti before exception |
| 6356 | // pushes lasti as PyLong |
| 6357 | if entry.push_lasti { |
| 6358 | self.push_value(vm.ctx.new_int(offset as i32).into()); |
| 6359 | } |
| 6360 | |
| 6361 | // 3. Push exception onto stack |
| 6362 | // always push exception, PUSH_EXC_INFO transforms [exc] -> [prev_exc, exc] |
| 6363 | // Do NOT call vm.set_exception here! PUSH_EXC_INFO will do it. |
| 6364 | // PUSH_EXC_INFO needs to get prev_exc from vm.current_exception() BEFORE setting the new one. |
| 6365 | self.push_value(exception.into()); |
| 6366 | |
| 6367 | // 4. Jump to handler |
| 6368 | self.jump(bytecode::Label::from_u32(entry.target)); |
| 6369 | |
| 6370 | Ok(None) |
| 6371 | } else { |
| 6372 | // No handler found, propagate exception |
| 6373 | Err(exception) |
| 6374 | } |
| 6375 | } |
| 6376 | UnwindReason::Returning { value } => Ok(Some(ExecutionResult::Return(value))), |
| 6377 | } |
| 6378 | } |
| 6379 | |
| 6380 | fn execute_store_subscript(&mut self, vm: &VirtualMachine) -> FrameResult { |
no test coverage detected