Drive one segment of execution; on `Pending*` re-stash the VM into the recycled `PausedRun` box. */
(mut vm: VM<'static>, src: &str, prev_paused: Option<Box<PausedRun>>)
| 113 | |
| 114 | /* Drive one segment of execution; on `Pending*` re-stash the VM into the recycled `PausedRun` box. */ |
| 115 | fn step_vm(mut vm: VM<'static>, src: &str, prev_paused: Option<Box<PausedRun>>) -> u32 { |
| 116 | let result = { |
| 117 | let _guard = VmGuard::new(&mut vm); |
| 118 | vm.run() |
| 119 | }; |
| 120 | match result { |
| 121 | Ok(_) => { |
| 122 | drop(vm); |
| 123 | drop(prev_paused); |
| 124 | STATUS_DONE |
| 125 | } |
| 126 | Err(VmErr::HostYield(status)) => { |
| 127 | let (kind, deadline) = match status { |
| 128 | SchedulerStatus::PendingTimer(d) => (STATUS_PENDING_TIMER, d), |
| 129 | SchedulerStatus::PendingFrame => (STATUS_PENDING_FRAME, 0), |
| 130 | SchedulerStatus::PendingEvent => (STATUS_PENDING_EVENT, 0), |
| 131 | SchedulerStatus::PendingHostCall => (STATUS_PENDING_HOST_CALL, 0), |
| 132 | SchedulerStatus::Done => (STATUS_DONE, 0), |
| 133 | }; |
| 134 | let mut paused = match prev_paused { |
| 135 | Some(mut b) => { |
| 136 | b.vm = Some(vm); |
| 137 | b.last_yield_deadline_ns = deadline; |
| 138 | b |
| 139 | } |
| 140 | None => Box::new(PausedRun { |
| 141 | vm: Some(vm), |
| 142 | last_yield_deadline_ns: deadline, |
| 143 | }), |
| 144 | }; |
| 145 | // Re-publish `current_vm` to the boxed VM so embedder calls like `host_edge_encode` (run between this yield and the next `run_resume`) can still allocate into the heap. The Box's address is stable across the move into rt. |
| 146 | let vm_ptr = paused.vm.as_mut().map(|v| NonNull::from(v).cast::<VM<'static>>()); |
| 147 | with_runtime(|rt| { |
| 148 | rt.paused_run = Some(paused); |
| 149 | rt.current_vm = vm_ptr; |
| 150 | }); |
| 151 | kind |
| 152 | } |
| 153 | Err(e) => { |
| 154 | // An uncaught `SystemExit` with an integer code is clean termination, not a crash. |
| 155 | if let Some(code) = vm.system_exit_code() { |
| 156 | drop(vm); |
| 157 | drop(prev_paused); |
| 158 | return STATUS_EXIT | ((code as u32) & 0xFF); |
| 159 | } |
| 160 | let traceback = e.render_traceback( |
| 161 | src, vm.error_pos(), None, |
| 162 | vm.call_stack_frames(), vm.function_names_ref(), |
| 163 | ); |
| 164 | drop(vm); |
| 165 | drop(prev_paused); |
| 166 | let n = unsafe { write_out(&traceback) }; |
| 167 | STATUS_ERROR | ((n as u32) & STATUS_PAYLOAD_MASK) |
| 168 | } |
| 169 | } |
| 170 | } |
| 171 | |
| 172 | #[unsafe(no_mangle)] |
no test coverage detected